difftreelog
merge develop into test/playground-migration
in: master
79 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -113,6 +113,20 @@
checksum = "508b352bb5c066aac251f6daf6b36eccd03e8a88e8081cd44959ea277a3af9a8"
[[package]]
+name = "app-promotion-rpc"
+version = "0.1.0"
+dependencies = [
+ "pallet-common",
+ "pallet-evm",
+ "parity-scale-codec 3.1.5",
+ "sp-api",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+ "up-data-structs",
+]
+
+[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5127,6 +5141,7 @@
name = "opal-runtime"
version = "0.9.27"
dependencies = [
+ "app-promotion-rpc",
"cumulus-pallet-aura-ext",
"cumulus-pallet-dmp-queue",
"cumulus-pallet-parachain-system",
@@ -5150,6 +5165,7 @@
"hex-literal",
"log",
"orml-vesting",
+ "pallet-app-promotion",
"pallet-aura",
"pallet-balances",
"pallet-base-fee",
@@ -5296,6 +5312,31 @@
]
[[package]]
+name = "pallet-app-promotion"
+version = "0.1.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-evm",
+ "pallet-evm-contract-helpers",
+ "pallet-evm-migration",
+ "pallet-randomness-collective-flip",
+ "pallet-timestamp",
+ "pallet-unique",
+ "parity-scale-codec 3.1.5",
+ "scale-info",
+ "serde",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+ "up-data-structs",
+]
+
+[[package]]
name = "pallet-aura"
version = "4.0.0-dev"
source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.27#8eff668a42325aeb4433eace1604f4d286a6ec05"
@@ -5694,6 +5735,7 @@
name = "pallet-evm-contract-helpers"
version = "0.2.0"
dependencies = [
+ "ethereum",
"evm-coder",
"fp-evm-mapping",
"frame-support",
@@ -6432,7 +6474,7 @@
[[package]]
name = "pallet-unique"
-version = "0.1.3"
+version = "0.1.4"
dependencies = [
"ethereum",
"evm-coder",
@@ -8332,6 +8374,7 @@
name = "quartz-runtime"
version = "0.9.27"
dependencies = [
+ "app-promotion-rpc",
"cumulus-pallet-aura-ext",
"cumulus-pallet-dmp-queue",
"cumulus-pallet-parachain-system",
@@ -8355,6 +8398,7 @@
"hex-literal",
"log",
"orml-vesting",
+ "pallet-app-promotion",
"pallet-aura",
"pallet-balances",
"pallet-base-fee",
@@ -12103,9 +12147,10 @@
[[package]]
name = "uc-rpc"
-version = "0.1.3"
+version = "0.1.4"
dependencies = [
"anyhow",
+ "app-promotion-rpc",
"jsonrpsee",
"pallet-common",
"pallet-evm",
@@ -12184,6 +12229,7 @@
name = "unique-node"
version = "0.9.27"
dependencies = [
+ "app-promotion-rpc",
"clap",
"cumulus-client-cli",
"cumulus-client-collator",
@@ -12272,6 +12318,7 @@
name = "unique-rpc"
version = "0.1.1"
dependencies = [
+ "app-promotion-rpc",
"fc-db",
"fc-mapping-sync",
"fc-rpc",
@@ -12321,6 +12368,7 @@
name = "unique-runtime"
version = "0.9.27"
dependencies = [
+ "app-promotion-rpc",
"cumulus-pallet-aura-ext",
"cumulus-pallet-dmp-queue",
"cumulus-pallet-parachain-system",
@@ -12344,6 +12392,7 @@
"hex-literal",
"log",
"orml-vesting",
+ "pallet-app-promotion",
"pallet-aura",
"pallet-balances",
"pallet-base-fee",
Makefilediffbeforeafterboth--- a/Makefile
+++ b/Makefile
@@ -128,5 +128,9 @@
bench-rmrk-equip:
make _bench PALLET=proxy-rmrk-equip
+.PHONY: bench-app-promotion
+bench-app-promotion:
+ make _bench PALLET=app-promotion PALLET_DIR=app-promotion
+
.PHONY: bench
bench: bench-evm-migration bench-unique bench-structure bench-fungible bench-refungible bench-nonfungible bench-scheduler bench-rmrk-core bench-rmrk-equip
client/rpc/CHANGELOG.mddiffbeforeafterboth--- a/client/rpc/CHANGELOG.md
+++ b/client/rpc/CHANGELOG.md
@@ -3,15 +3,21 @@
All notable changes to this project will be documented in this file.
<!-- bureaucrate goes here -->
+
+## [v0.1.4] 2022-09-08
+
+### Added
+- Support RPC for `AppPromotion` pallet.
+
## [v0.1.3] 2022-08-16
### Other changes
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
+- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
+- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
+- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
## [0.1.2] - 2022-08-12
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.3"
+version = "0.1.4"
license = "GPLv3"
edition = "2021"
@@ -8,6 +8,7 @@
pallet-common = { default-features = false, path = '../../pallets/common' }
up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
up-rpc = { path = "../../primitives/rpc" }
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc"}
rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
codec = { package = "parity-scale-codec", version = "3.1.2" }
jsonrpsee = { version = "0.14.0", features = ["server", "macros"] }
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -23,6 +23,7 @@
proc_macros::rpc,
};
use anyhow::anyhow;
+use sp_runtime::traits::{AtLeast32BitUnsigned, Member};
use up_data_structs::{
RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,
PropertyKeyPermission, TokenData, TokenChild,
@@ -30,6 +31,7 @@
use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};
use sp_blockchain::HeaderBackend;
use up_rpc::UniqueApi as UniqueRuntimeApi;
+use app_promotion_rpc::AppPromotionApi as AppPromotionRuntimeApi;
// RMRK
use rmrk_rpc::RmrkApi as RmrkRuntimeApi;
@@ -37,6 +39,7 @@
RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId,
};
+pub use app_promotion_unique_rpc::AppPromotionApiServer;
pub use rmrk_unique_rpc::RmrkApiServer;
#[rpc(server)]
@@ -245,6 +248,46 @@
) -> Result<Option<String>>;
}
+mod app_promotion_unique_rpc {
+ use super::*;
+
+ #[rpc(server)]
+ #[async_trait]
+ pub trait AppPromotionApi<BlockHash, BlockNumber, CrossAccountId, AccountId> {
+ /// Returns the total amount of staked tokens.
+ #[method(name = "appPromotion_totalStaked")]
+ fn total_staked(
+ &self,
+ staker: Option<CrossAccountId>,
+ at: Option<BlockHash>,
+ ) -> Result<String>;
+
+ ///Returns the total amount of staked tokens per block when staked.
+ #[method(name = "appPromotion_totalStakedPerBlock")]
+ fn total_staked_per_block(
+ &self,
+ staker: CrossAccountId,
+ at: Option<BlockHash>,
+ ) -> Result<Vec<(BlockNumber, String)>>;
+
+ /// Returns the total amount of tokens pending withdrawal from staking.
+ #[method(name = "appPromotion_pendingUnstake")]
+ fn pending_unstake(
+ &self,
+ staker: Option<CrossAccountId>,
+ at: Option<BlockHash>,
+ ) -> Result<String>;
+
+ /// Returns the total amount of tokens pending withdrawal from staking per block.
+ #[method(name = "appPromotion_pendingUnstakePerBlock")]
+ fn pending_unstake_per_block(
+ &self,
+ staker: CrossAccountId,
+ at: Option<BlockHash>,
+ ) -> Result<Vec<(BlockNumber, String)>>;
+ }
+}
+
mod rmrk_unique_rpc {
use super::*;
@@ -367,34 +410,28 @@
}
}
-pub struct Unique<C, P> {
- client: Arc<C>,
- _marker: std::marker::PhantomData<P>,
-}
+macro_rules! define_struct_for_server_api {
+ ($name:ident) => {
+ pub struct $name<C, P> {
+ client: Arc<C>,
+ _marker: std::marker::PhantomData<P>,
+ }
-impl<C, P> Unique<C, P> {
- pub fn new(client: Arc<C>) -> Self {
- Self {
- client,
- _marker: Default::default(),
+ impl<C, P> $name<C, P> {
+ pub fn new(client: Arc<C>) -> Self {
+ Self {
+ client,
+ _marker: Default::default(),
+ }
+ }
}
- }
+ };
}
-pub struct Rmrk<C, P> {
- client: Arc<C>,
- _marker: std::marker::PhantomData<P>,
-}
+define_struct_for_server_api!(Unique);
+define_struct_for_server_api!(AppPromotion);
+define_struct_for_server_api!(Rmrk);
-impl<C, P> Rmrk<C, P> {
- pub fn new(client: Arc<C>) -> Self {
- Self {
- client,
- _marker: Default::default(),
- }
- }
-}
-
macro_rules! pass_method {
(
$method_name:ident(
@@ -440,6 +477,12 @@
};
}
+macro_rules! app_promotion_api {
+ () => {
+ dyn AppPromotionRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>
+ };
+}
+
macro_rules! rmrk_api {
() => {
dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>
@@ -522,6 +565,35 @@
pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);
}
+impl<C, Block, BlockNumber, CrossAccountId, AccountId>
+ app_promotion_unique_rpc::AppPromotionApiServer<
+ <Block as BlockT>::Hash,
+ BlockNumber,
+ CrossAccountId,
+ AccountId,
+ > for AppPromotion<C, Block>
+where
+ Block: BlockT,
+ BlockNumber: Decode + Member + AtLeast32BitUnsigned,
+ AccountId: Decode,
+ C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
+ C::Api: AppPromotionRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>,
+ CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,
+{
+ pass_method!(total_staked(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), app_promotion_api);
+ pass_method!(total_staked_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, String)> =>
+ |v| v
+ .into_iter()
+ .map(|(b, a)| (b, a.to_string()))
+ .collect::<Vec<_>>(), app_promotion_api);
+ pass_method!(pending_unstake(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), app_promotion_api);
+ pass_method!(pending_unstake_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, String)> =>
+ |v| v
+ .into_iter()
+ .map(|(b, a)| (b, a.to_string()))
+ .collect::<Vec<_>>(), app_promotion_api);
+}
+
#[allow(deprecated)]
impl<
C,
doc/separate_rpc.mddiffbeforeafterboth--- /dev/null
+++ b/doc/separate_rpc.md
@@ -0,0 +1,123 @@
+1. Create, in the `primitives` folder, a crate with a trait for RPC generation.
+ ```rust
+ sp_api::decl_runtime_apis! {
+ #[api_version(2)]
+ pub trait ModuleNameApi<CrossAccountId>
+ where
+ CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,
+ {
+ fn method_name(user: Option<CrossAccountId>) -> Result<u128, DispatchError>;
+ }
+ }
+ ```
+
+2. client/rpc/src/lib.rs
+ * Add a trait with the required methods. Mark it with `#[rpc(server)]` and `#[async_trait]` directives.
+ ```rust
+ #[rpc(server)]
+ #[async_trait]
+ pub trait ModuleNameApi<BlockHash, CrossAccountId> {
+ #[method(name = "moduleName_methodName")]
+ fn method_name(&self, user: Option<CrossAccountId>, at: Option<BlockHash>)
+ -> Result<String>;
+ }
+ ```
+ * Don't forget to write the correct method identifier in the form `moduleName_methodName`.
+ * Add a structure for which the server API interface will be implemented.
+ ```rust
+ define_struct_for_server_api!(ModuleName);
+ ```
+ * Define a macro to be used in the implementation of the server API interface.
+ ```rust
+ macro_rules! module_api {
+ () => {
+ dyn ModuleNameRuntimeApi<BlockHash, CrossAccountId>
+ };
+ }
+ ```
+ * Implement a server API interface.
+ ```rust
+ impl<C, Block, CrossAccountId>
+ ModuleNameApiServer<<Block as BlockT>::Hash, CrossAccountId> for ModuleName<C, Block>
+ where
+ Block: BlockT,
+ C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
+ C::Api: AppPromotionRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>,
+ CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,
+ {
+ pass_method!(method_name(user: Option<CrossAccountId>) -> String => |v| v.to_string(), app_promotion_api);
+ }
+ ```
+
+3. runtime/common/runtime_apis.rs
+ * Implement the `ModuleNameApi` interface for `Runtime`. Optionally, you can mark a feature flag to disable the functionality.
+ ```rust
+ impl MethodApi<Block, BlockNumber, CrossAccountId, AccountId> for Runtime {
+ fn method_name(user: Option<CrossAccountId>) -> Result<u128, DispatchError> {
+ #[cfg(not(feature = "module"))]
+ return unsupported!();
+
+ #[cfg(feature = "module")]
+ return Ok(0);
+ }
+ }
+ ```
+
+4. node/cli/src/service.rs
+ * Set the `MethodApi<Block, Runtime::CrossAccountId>` bound in the `start_node_impl`, `start_node`, `start_dev_node` methods.
+
+5. node/rpc/src/lib.rs
+ * Add `MethodApi<Block, Runtime::CrossAccountId>` bound to `create_full` method.
+ * Enable RPC in the `create_full` method by adding `io.merge(ModuleName::new(client.clone()).into_rpc())?;`
+
+6. Add a new crate (see point 1) into dependencies.
+ * client/rpc/Cargo.toml
+ * node/rpc/Cargo.toml
+ * runtime/opal/Cargo.toml
+ * runtime/quartz/Cargo.toml
+ * runtime/unique/Cargo.toml
+
+7. Create tests/src/interfaces/ModuleName/definitions.ts and describe the necessary methods in it.
+ ```ts
+ type RpcParam = {
+ name: string;
+ type: string;
+ isOptional?: true;
+ };
+
+ const CROSS_ACCOUNT_ID_TYPE = 'PalletEvmAccountBasicCrossAccountIdRepr';
+
+ const fun = (description: string, params: RpcParam[], type: string) => ({
+ description,
+ params: [...params, atParam],
+ type,
+ });
+
+ export default {
+ types: {},
+ rpc: {
+ methodName: fun(
+ 'Documentation for method',
+ [{name: 'user', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
+ 'u128',
+ ),
+ },
+ };
+ ```
+
+8. Describe definitions from paragraph 7 in tests/src/interfaces/definitions.ts.
+ ```ts
+ export {default as ModuleName} from './module/definitions';
+ ```
+
+9. tests/src/substrate/substrate-api.ts
+ * Set the RPC interface in the `defaultApiOptions` function, add an entry in the `rpc` parameter
+ ```ts
+ module: defs.module.rpc,
+ ```
+
+10. tests/src/util/playgrounds/unique.dev.ts
+ * Specify RPC interface in `connect` function, add entry in `rpc` parameter
+ ```ts
+ module: defs.module.rpc,
+ ```
\ No newline at end of file
node/cli/Cargo.tomldiffbeforeafterboth--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -318,6 +318,7 @@
pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" }
unique-rpc = { default-features = false, path = "../rpc" }
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false}
rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
[features]
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -63,7 +63,9 @@
use fc_rpc_core::types::FilterPool;
use fc_mapping_sync::{MappingSyncWorker, SyncStrategy};
-use up_common::types::opaque::{AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block};
+use up_common::types::opaque::{
+ AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block, BlockNumber,
+};
// RMRK
use up_data_structs::{
@@ -362,6 +364,7 @@
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
+ + app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>
+ rmrk_rpc::RmrkApi<
Block,
AccountId,
@@ -663,6 +666,7 @@
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
+ + app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>
+ rmrk_rpc::RmrkApi<
Block,
AccountId,
@@ -807,6 +811,7 @@
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
+ + app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>
+ rmrk_rpc::RmrkApi<
Block,
AccountId,
node/rpc/Cargo.tomldiffbeforeafterboth--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -53,6 +53,7 @@
pallet-unique = { path = "../../pallets/unique" }
uc-rpc = { path = "../../client/rpc" }
up-rpc = { path = "../../primitives/rpc" }
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc"}
rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
up-data-structs = { default-features = false, path = "../../primitives/data-structs" }
node/rpc/src/lib.rsdiffbeforeafterboth--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -145,6 +145,12 @@
C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
C::Api: fp_rpc::ConvertTransactionRuntimeApi<Block>,
C::Api: up_rpc::UniqueApi<Block, <R as RuntimeInstance>::CrossAccountId, AccountId>,
+ C::Api: app_promotion_rpc::AppPromotionApi<
+ Block,
+ BlockNumber,
+ <R as RuntimeInstance>::CrossAccountId,
+ AccountId,
+ >,
C::Api: rmrk_rpc::RmrkApi<
Block,
AccountId,
@@ -169,6 +175,7 @@
EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer,
};
use uc_rpc::{UniqueApiServer, Unique};
+ use uc_rpc::{AppPromotionApiServer, AppPromotion};
#[cfg(not(feature = "unique-runtime"))]
use uc_rpc::{RmrkApiServer, Rmrk};
@@ -227,6 +234,9 @@
io.merge(Unique::new(client.clone()).into_rpc())?;
+ #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]
+ io.merge(AppPromotion::new(client.clone()).into_rpc())?;
+
#[cfg(not(feature = "unique-runtime"))]
io.merge(Rmrk::new(client.clone()).into_rpc())?;
pallets/app-promotion/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/pallets/app-promotion/Cargo.toml
@@ -0,0 +1,73 @@
+################################################################################
+# Package
+
+[package]
+authors = ['Unique Network <support@uniquenetwork.io>']
+description = 'Unique App Promotion Pallet'
+edition = '2021'
+homepage = 'https://unique.network'
+license = 'GPLv3'
+name = 'pallet-app-promotion'
+repository = 'https://github.com/UniqueNetwork/unique-chain'
+version = '0.1.0'
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
+
+[features]
+default = ['std']
+runtime-benchmarks = [
+ 'frame-benchmarking',
+ 'frame-support/runtime-benchmarks',
+ 'frame-system/runtime-benchmarks',
+ # 'pallet-unique/runtime-benchmarks',
+]
+std = [
+ 'codec/std',
+ 'frame-benchmarking/std',
+ 'frame-support/std',
+ 'frame-system/std',
+ 'pallet-balances/std',
+ 'pallet-timestamp/std',
+ 'pallet-randomness-collective-flip/std',
+ 'pallet-evm/std',
+ 'sp-io/std',
+ 'sp-std/std',
+ 'sp-runtime/std',
+ 'sp-core/std',
+ 'serde/std',
+
+]
+[dependencies]
+scale-info = { version = "2.0.1", default-features = false, features = [
+ "derive",
+] }
+################################################################################
+# Substrate Dependencies
+
+codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '3.1.2' }
+frame-benchmarking = {default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+frame-system ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-balances ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-timestamp ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-randomness-collective-flip ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-evm ={ default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" }
+sp-std ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-io ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+serde = { default-features = false, features = ['derive'], version = '1.0.130' }
+
+################################################################################
+# local dependencies
+
+up-data-structs ={ default-features = false, path = "../../primitives/data-structs" }
+pallet-common ={ default-features = false, path = "../common" }
+pallet-unique ={ default-features = false, path = "../unique" }
+pallet-evm-contract-helpers ={ default-features = false, path = "../evm-contract-helpers" }
+
+[dev-dependencies]
+pallet-evm-migration ={ default-features = false, path = "../evm-migration" }
+
+################################################################################
pallets/app-promotion/src/benchmarking.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/app-promotion/src/benchmarking.rs
@@ -0,0 +1,162 @@
+// 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/>.
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use super::*;
+use crate::Pallet as PromototionPallet;
+
+use sp_runtime::traits::Bounded;
+use sp_std::vec;
+
+use frame_benchmarking::{benchmarks, account};
+use frame_support::traits::OnInitialize;
+use frame_system::{Origin, RawOrigin};
+use pallet_unique::benchmarking::create_nft_collection;
+use pallet_evm_migration::Pallet as EvmMigrationPallet;
+
+const SEED: u32 = 0;
+
+fn set_admin<T>() -> Result<T::AccountId, sp_runtime::DispatchError>
+where
+ T: Config + pallet_unique::Config + pallet_evm_migration::Config,
+ T::BlockNumber: From<u32> + Into<u32>,
+ <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum + From<u128>,
+{
+ let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
+
+ <T as Config>::Currency::make_free_balance_be(
+ &pallet_admin,
+ Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value(),
+ );
+
+ PromototionPallet::<T>::set_admin_address(
+ RawOrigin::Root.into(),
+ T::CrossAccountId::from_sub(pallet_admin.clone()),
+ )?;
+
+ Ok(pallet_admin)
+}
+
+benchmarks! {
+ where_clause{
+ where T: Config + pallet_unique::Config + pallet_evm_migration::Config ,
+ T::BlockNumber: From<u32> + Into<u32>,
+ <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum + From<u128>
+ }
+
+ on_initialize {
+ let b in 0..PENDING_LIMIT_PER_BLOCK;
+ set_admin::<T>()?;
+
+ (0..b).try_for_each(|index| {
+ let staker = account::<T::AccountId>("staker", index, SEED);
+ <T as Config>::Currency::make_free_balance_be(&staker, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ PromototionPallet::<T>::stake(RawOrigin::Signed(staker.clone()).into(), Into::<BalanceOf<T>>::into(100u128) * T::Nominal::get())?;
+ PromototionPallet::<T>::unstake(RawOrigin::Signed(staker.clone()).into()).map_err(|e| e.error)?;
+ Result::<(), sp_runtime::DispatchError>::Ok(())
+ })?;
+ let block_number = <frame_system::Pallet<T>>::current_block_number() + T::PendingInterval::get();
+ }: {PromototionPallet::<T>::on_initialize(block_number)}
+
+ set_admin_address {
+ let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
+ let _ = <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ } : _(RawOrigin::Root, T::CrossAccountId::from_sub(pallet_admin))
+
+ payout_stakers{
+ let b in 1..101;
+
+ let pallet_admin = account::<T::AccountId>("admin", 1, SEED);
+ let share = Perbill::from_rational(1u32, 20);
+ PromototionPallet::<T>::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?;
+ <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+
+ let staker: T::AccountId = account("caller", 0, SEED);
+ <T as Config>::Currency::make_free_balance_be(&staker, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let stakers: Vec<T::AccountId> = (0..b).map(|index| account("staker", index, SEED)).collect();
+ stakers.iter().for_each(|staker| {
+ <T as Config>::Currency::make_free_balance_be(&staker, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ });
+ (0..10).try_for_each(|_| {
+ stakers.iter()
+ .map(|staker| {
+ PromototionPallet::<T>::stake(RawOrigin::Signed(staker.clone()).into(), Into::<BalanceOf<T>>::into(100u128) * T::Nominal::get())
+ }).collect::<Result<Vec<_>, _>>()?;
+ <frame_system::Pallet<T>>::finalize();
+ Result::<(), sp_runtime::DispatchError>::Ok(())
+ })?;
+ } : _(RawOrigin::Signed(pallet_admin.clone()), Some(b as u8))
+
+ stake {
+ let caller = account::<T::AccountId>("caller", 0, SEED);
+ let share = Perbill::from_rational(1u32, 10);
+ let _ = <T as Config>::Currency::make_free_balance_be(&caller, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ } : _(RawOrigin::Signed(caller.clone()), share * <T as Config>::Currency::total_balance(&caller))
+
+ unstake {
+ let caller = account::<T::AccountId>("caller", 0, SEED);
+ let share = Perbill::from_rational(1u32, 20);
+ let _ = <T as Config>::Currency::make_free_balance_be(&caller, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ (0..10).map(|_| {
+ <frame_system::Pallet<T>>::finalize();
+ PromototionPallet::<T>::stake(RawOrigin::Signed(caller.clone()).into(), share * <T as Config>::Currency::total_balance(&caller))
+ }).collect::<Result<Vec<_>, _>>()?;
+
+ } : _(RawOrigin::Signed(caller.clone()))
+
+ sponsor_collection {
+ let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
+ PromototionPallet::<T>::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?;
+ let _ = <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let caller: T::AccountId = account("caller", 0, SEED);
+ let _ = <T as Config>::Currency::make_free_balance_be(&caller, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let collection = create_nft_collection::<T>(caller.clone())?;
+ } : _(RawOrigin::Signed(pallet_admin.clone()), collection)
+
+ stop_sponsoring_collection {
+ let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
+ PromototionPallet::<T>::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?;
+ let _ = <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let caller: T::AccountId = account("caller", 0, SEED);
+ let _ = <T as Config>::Currency::make_free_balance_be(&caller, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let collection = create_nft_collection::<T>(caller.clone())?;
+ PromototionPallet::<T>::sponsor_collection(RawOrigin::Signed(pallet_admin.clone()).into(), collection)?;
+ } : _(RawOrigin::Signed(pallet_admin.clone()), collection)
+
+ sponsor_contract {
+ let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
+ PromototionPallet::<T>::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?;
+
+ let _ = <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let address = H160::from_low_u64_be(SEED as u64);
+ let data: Vec<u8> = (0..20 as u8).collect();
+ <EvmMigrationPallet<T>>::begin(RawOrigin::Root.into(), address)?;
+ <EvmMigrationPallet<T>>::finish(RawOrigin::Root.into(), address, data)?;
+ } : _(RawOrigin::Signed(pallet_admin.clone()), address)
+
+ stop_sponsoring_contract {
+ let pallet_admin = account::<T::AccountId>("admin", 0, SEED);
+ PromototionPallet::<T>::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?;
+
+ let _ = <T as Config>::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::<T>::max_value());
+ let address = H160::from_low_u64_be(SEED as u64);
+ let data: Vec<u8> = (0..20 as u8).collect();
+ <EvmMigrationPallet<T>>::begin(RawOrigin::Root.into(), address)?;
+ <EvmMigrationPallet<T>>::finish(RawOrigin::Root.into(), address, data)?;
+ PromototionPallet::<T>::sponsor_contract(RawOrigin::Signed(pallet_admin.clone()).into(), address)?;
+ } : _(RawOrigin::Signed(pallet_admin.clone()), address)
+}
pallets/app-promotion/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/app-promotion/src/lib.rs
@@ -0,0 +1,758 @@
+// 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/>.
+
+//! # App promotion
+//!
+//! The app promotion pallet is designed to ... .
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Functions
+//!
+
+// #![recursion_limit = "1024"]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;
+
+pub mod types;
+pub mod weights;
+
+use sp_std::{
+ vec::{Vec},
+ vec,
+ iter::Sum,
+ borrow::ToOwned,
+ cell::RefCell,
+};
+use sp_core::H160;
+use codec::EncodeLike;
+use pallet_balances::BalanceLock;
+pub use types::*;
+
+use up_data_structs::CollectionId;
+
+use frame_support::{
+ dispatch::{DispatchResult},
+ traits::{
+ Currency, Get, LockableCurrency, WithdrawReasons, tokens::Balance, ExistenceRequirement,
+ },
+ ensure,
+};
+
+use weights::WeightInfo;
+
+pub use pallet::*;
+use pallet_evm::account::CrossAccountId;
+use sp_runtime::{
+ Perbill,
+ traits::{BlockNumberProvider, CheckedAdd, CheckedSub, AccountIdConversion, Zero},
+ ArithmeticError,
+};
+
+pub const LOCK_IDENTIFIER: [u8; 8] = *b"appstake";
+
+const PENDING_LIMIT_PER_BLOCK: u32 = 3;
+
+type BalanceOf<T> =
+ <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
+
+#[frame_support::pallet]
+pub mod pallet {
+ use super::*;
+ use frame_support::{
+ Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, PalletId,
+ traits::ReservableCurrency,
+ };
+ use frame_system::pallet_prelude::*;
+
+ #[pallet::config]
+ pub trait Config: frame_system::Config + pallet_evm::account::Config {
+ /// Type to interact with the native token
+ type Currency: ExtendedLockableCurrency<Self::AccountId>
+ + ReservableCurrency<Self::AccountId>;
+
+ /// Type for interacting with collections
+ type CollectionHandler: CollectionHandler<
+ AccountId = Self::AccountId,
+ CollectionId = CollectionId,
+ >;
+
+ /// Type for interacting with conrtacts
+ type ContractHandler: ContractHandler<AccountId = Self::CrossAccountId, ContractId = H160>;
+
+ /// ID for treasury
+ type TreasuryAccountId: Get<Self::AccountId>;
+
+ /// The app's pallet id, used for deriving its sovereign account ID.
+ #[pallet::constant]
+ type PalletId: Get<PalletId>;
+
+ /// In relay blocks.
+ #[pallet::constant]
+ type RecalculationInterval: Get<Self::BlockNumber>;
+
+ /// In parachain blocks.
+ #[pallet::constant]
+ type PendingInterval: Get<Self::BlockNumber>;
+
+ /// Rate of return for interval in blocks defined in `RecalculationInterval`.
+ #[pallet::constant]
+ type IntervalIncome: Get<Perbill>;
+
+ /// Decimals for the `Currency`.
+ #[pallet::constant]
+ type Nominal: Get<BalanceOf<Self>>;
+
+ /// Weight information for extrinsics in this pallet.
+ type WeightInfo: WeightInfo;
+
+ // The relay block number provider
+ type RelayBlockNumberProvider: BlockNumberProvider<BlockNumber = Self::BlockNumber>;
+
+ /// Events compatible with [`frame_system::Config::Event`].
+ type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
+ }
+
+ #[pallet::pallet]
+ #[pallet::generate_store(pub(super) trait Store)]
+ pub struct Pallet<T>(_);
+
+ #[pallet::event]
+ #[pallet::generate_deposit(fn deposit_event)]
+ pub enum Event<T: Config> {
+ /// Staking recalculation was performed
+ ///
+ /// # Arguments
+ /// * AccountId: ID of the staker.
+ /// * Balance : recalculation base
+ /// * Balance : total income
+ StakingRecalculation(
+ /// An recalculated staker
+ T::AccountId,
+ /// Base on which interest is calculated
+ BalanceOf<T>,
+ /// Amount of accrued interest
+ BalanceOf<T>,
+ ),
+
+ /// Staking was performed
+ ///
+ /// # Arguments
+ /// * AccountId: ID of the staker
+ /// * Balance : staking amount
+ Stake(T::AccountId, BalanceOf<T>),
+
+ /// Unstaking was performed
+ ///
+ /// # Arguments
+ /// * AccountId: ID of the staker
+ /// * Balance : unstaking amount
+ Unstake(T::AccountId, BalanceOf<T>),
+
+ /// The admin was set
+ ///
+ /// # Arguments
+ /// * AccountId: ID of the admin
+ SetAdmin(T::AccountId),
+ }
+
+ #[pallet::error]
+ pub enum Error<T> {
+ /// Error due to action requiring admin to be set.
+ AdminNotSet,
+ /// No permission to perform an action.
+ NoPermission,
+ /// Insufficient funds to perform an action.
+ NotSufficientFunds,
+ /// Occurs when a pending unstake cannot be added in this block. PENDING_LIMIT_PER_BLOCK` limits exceeded.
+ PendingForBlockOverflow,
+ /// The error is due to the fact that the collection/contract must already be sponsored in order to perform the action.
+ SponsorNotSet,
+ /// Errors caused by incorrect actions with a locked balance.
+ IncorrectLockedBalanceOperation,
+ }
+
+ #[pallet::storage]
+ pub type TotalStaked<T: Config> = StorageValue<Value = BalanceOf<T>, QueryKind = ValueQuery>;
+
+ #[pallet::storage]
+ pub type Admin<T: Config> = StorageValue<Value = T::AccountId, QueryKind = OptionQuery>;
+
+ /// Amount of tokens staked by account in the blocknumber.
+ #[pallet::storage]
+ pub type Staked<T: Config> = StorageNMap<
+ Key = (
+ Key<Blake2_128Concat, T::AccountId>,
+ Key<Twox64Concat, T::BlockNumber>,
+ ),
+ Value = (BalanceOf<T>, T::BlockNumber),
+ QueryKind = ValueQuery,
+ >;
+ /// Amount of stakes for an Account
+ #[pallet::storage]
+ pub type StakesPerAccount<T: Config> =
+ StorageMap<_, Blake2_128Concat, T::AccountId, u8, ValueQuery>;
+
+ #[pallet::storage]
+ pub type PendingUnstake<T: Config> = StorageMap<
+ _,
+ Twox64Concat,
+ T::BlockNumber,
+ BoundedVec<(T::AccountId, BalanceOf<T>), ConstU32<PENDING_LIMIT_PER_BLOCK>>,
+ ValueQuery,
+ >;
+
+ /// Stores a key for record for which the next revenue recalculation would be performed.
+ /// If `None`, then recalculation has not yet been performed or calculations have been completed for all stakers.
+ #[pallet::storage]
+ #[pallet::getter(fn get_next_calculated_record)]
+ pub type NextCalculatedRecord<T: Config> =
+ StorageValue<Value = (T::AccountId, T::BlockNumber), QueryKind = OptionQuery>;
+
+ #[pallet::hooks]
+ impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+ /// Block overflow is impossible due to the fact that the unstake algorithm in on_initialize
+ /// implies the execution of a strictly limited number of relatively lightweight operations.
+ /// A separate benchmark has been implemented to scale the weight depending on the number of pendings.
+ fn on_initialize(current_block_number: T::BlockNumber) -> Weight
+ where
+ <T as frame_system::Config>::BlockNumber: From<u32>,
+ {
+ let block_pending = PendingUnstake::<T>::take(current_block_number);
+ let counter = block_pending.len() as u32;
+
+ if !block_pending.is_empty() {
+ block_pending.into_iter().for_each(|(staker, amount)| {
+ <T::Currency as ReservableCurrency<T::AccountId>>::unreserve(&staker, amount);
+ });
+ }
+
+ T::WeightInfo::on_initialize(counter)
+ }
+ }
+
+ #[pallet::call]
+ impl<T: Config> Pallet<T>
+ where
+ T::BlockNumber: From<u32> + Into<u32>,
+ <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum + From<u128>,
+ {
+ #[pallet::weight(T::WeightInfo::set_admin_address())]
+ pub fn set_admin_address(origin: OriginFor<T>, admin: T::CrossAccountId) -> DispatchResult {
+ ensure_root(origin)?;
+
+ <Admin<T>>::set(Some(admin.as_sub().to_owned()));
+
+ Self::deposit_event(Event::SetAdmin(admin.as_sub().to_owned()));
+
+ Ok(())
+ }
+
+ #[pallet::weight(T::WeightInfo::stake())]
+ pub fn stake(staker: OriginFor<T>, amount: BalanceOf<T>) -> DispatchResult {
+ let staker_id = ensure_signed(staker)?;
+
+ ensure!(
+ StakesPerAccount::<T>::get(&staker_id) < 10,
+ Error::<T>::NoPermission
+ );
+
+ ensure!(
+ amount >= <BalanceOf<T>>::from(100u128) * T::Nominal::get(),
+ ArithmeticError::Underflow
+ );
+
+ let balance =
+ <<T as Config>::Currency as Currency<T::AccountId>>::free_balance(&staker_id);
+
+ <<T as Config>::Currency as Currency<T::AccountId>>::ensure_can_withdraw(
+ &staker_id,
+ amount,
+ WithdrawReasons::all(),
+ balance
+ .checked_sub(&amount)
+ .ok_or(ArithmeticError::Underflow)?,
+ )?;
+
+ Self::add_lock_balance(&staker_id, amount)?;
+
+ let block_number = T::RelayBlockNumberProvider::current_block_number();
+
+ let recalculate_after_interval: T::BlockNumber =
+ if block_number % T::RecalculationInterval::get() == 0u32.into() {
+ 1u32.into()
+ } else {
+ 2u32.into()
+ };
+
+ let recalc_block = (block_number / T::RecalculationInterval::get()
+ + recalculate_after_interval)
+ * T::RecalculationInterval::get();
+
+ <Staked<T>>::insert((&staker_id, block_number), {
+ let mut balance_and_recalc_block = <Staked<T>>::get((&staker_id, block_number));
+ balance_and_recalc_block.0 = balance_and_recalc_block
+ .0
+ .checked_add(&amount)
+ .ok_or(ArithmeticError::Overflow)?;
+ balance_and_recalc_block.1 = recalc_block;
+ balance_and_recalc_block
+ });
+
+ <TotalStaked<T>>::set(
+ <TotalStaked<T>>::get()
+ .checked_add(&amount)
+ .ok_or(ArithmeticError::Overflow)?,
+ );
+
+ StakesPerAccount::<T>::mutate(&staker_id, |stakes| *stakes += 1);
+
+ Self::deposit_event(Event::Stake(staker_id, amount));
+
+ Ok(())
+ }
+
+ #[pallet::weight(T::WeightInfo::unstake())]
+ pub fn unstake(staker: OriginFor<T>) -> DispatchResultWithPostInfo {
+ let staker_id = ensure_signed(staker)?;
+ let block = <frame_system::Pallet<T>>::block_number() + T::PendingInterval::get();
+ let mut pendings = <PendingUnstake<T>>::get(block);
+
+ ensure!(!pendings.is_full(), Error::<T>::PendingForBlockOverflow);
+
+ let mut total_stakes = 0u64;
+
+ let total_staked: BalanceOf<T> = Staked::<T>::drain_prefix((&staker_id,))
+ .map(|(_, (amount, _))| {
+ total_stakes += 1;
+ amount
+ })
+ .sum();
+
+ if total_staked.is_zero() {
+ return Ok(None.into()); // TO-DO
+ }
+
+ pendings
+ .try_push((staker_id.clone(), total_staked))
+ .map_err(|_| Error::<T>::PendingForBlockOverflow)?;
+
+ <PendingUnstake<T>>::insert(block, pendings);
+
+ Self::unlock_balance(&staker_id, total_staked)?;
+
+ <T::Currency as ReservableCurrency<T::AccountId>>::reserve(&staker_id, total_staked)?;
+
+ TotalStaked::<T>::set(
+ TotalStaked::<T>::get()
+ .checked_sub(&total_staked)
+ .ok_or(ArithmeticError::Underflow)?,
+ );
+
+ StakesPerAccount::<T>::remove(&staker_id);
+
+ Self::deposit_event(Event::Unstake(staker_id, total_staked));
+
+ Ok(None.into())
+ }
+
+ #[pallet::weight(T::WeightInfo::sponsor_collection())]
+ pub fn sponsor_collection(
+ admin: OriginFor<T>,
+ collection_id: CollectionId,
+ ) -> DispatchResult {
+ let admin_id = ensure_signed(admin)?;
+ ensure!(
+ admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,
+ Error::<T>::NoPermission
+ );
+
+ T::CollectionHandler::set_sponsor(Self::account_id(), collection_id)
+ }
+ #[pallet::weight(T::WeightInfo::stop_sponsoring_collection())]
+ pub fn stop_sponsoring_collection(
+ admin: OriginFor<T>,
+ collection_id: CollectionId,
+ ) -> DispatchResult {
+ let admin_id = ensure_signed(admin)?;
+
+ ensure!(
+ admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,
+ Error::<T>::NoPermission
+ );
+
+ ensure!(
+ T::CollectionHandler::sponsor(collection_id)?.ok_or(<Error<T>>::SponsorNotSet)?
+ == Self::account_id(),
+ <Error<T>>::NoPermission
+ );
+ T::CollectionHandler::remove_collection_sponsor(collection_id)
+ }
+
+ #[pallet::weight(T::WeightInfo::sponsor_contract())]
+ pub fn sponsor_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {
+ let admin_id = ensure_signed(admin)?;
+
+ ensure!(
+ admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,
+ Error::<T>::NoPermission
+ );
+
+ T::ContractHandler::set_sponsor(
+ T::CrossAccountId::from_sub(Self::account_id()),
+ contract_id,
+ )
+ }
+
+ #[pallet::weight(T::WeightInfo::stop_sponsoring_contract())]
+ pub fn stop_sponsoring_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {
+ let admin_id = ensure_signed(admin)?;
+
+ ensure!(
+ admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,
+ Error::<T>::NoPermission
+ );
+
+ ensure!(
+ T::ContractHandler::sponsor(contract_id)?
+ .ok_or(<Error<T>>::SponsorNotSet)?
+ .as_sub() == &Self::account_id(),
+ <Error<T>>::NoPermission
+ );
+ T::ContractHandler::remove_contract_sponsor(contract_id)
+ }
+
+ #[pallet::weight(T::WeightInfo::payout_stakers(stakers_number.unwrap_or(20) as u32))]
+ pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {
+ let admin_id = ensure_signed(admin)?;
+
+ ensure!(
+ admin_id == Admin::<T>::get().ok_or(Error::<T>::AdminNotSet)?,
+ Error::<T>::NoPermission
+ );
+
+ let current_recalc_block =
+ Self::get_current_recalc_block(T::RelayBlockNumberProvider::current_block_number());
+ let next_recalc_block = current_recalc_block + T::RecalculationInterval::get();
+
+ let mut storage_iterator = Self::get_next_calculated_key()
+ .map_or(Staked::<T>::iter(), |key| Staked::<T>::iter_from(key));
+
+ NextCalculatedRecord::<T>::set(None);
+
+ // {
+ // let mut stakers_number = stakers_number.unwrap_or(20);
+ // let mut last_id = admin_id;
+ // let mut income_acc = BalanceOf::<T>::default();
+ // let mut amount_acc = BalanceOf::<T>::default();
+
+ // while let Some((
+ // (current_id, staked_block),
+ // (amount, next_recalc_block_for_stake),
+ // )) = storage_iterator.next()
+ // {
+ // if last_id != current_id {
+ // if income_acc != BalanceOf::<T>::default() {
+ // <T::Currency as Currency<T::AccountId>>::transfer(
+ // &T::TreasuryAccountId::get(),
+ // &last_id,
+ // income_acc,
+ // ExistenceRequirement::KeepAlive,
+ // )
+ // .and_then(|_| Self::add_lock_balance(&last_id, income_acc))?;
+
+ // Self::deposit_event(Event::StakingRecalculation(
+ // last_id, amount, income_acc,
+ // ));
+ // }
+
+ // if stakers_number == 0 {
+ // NextCalculatedRecord::<T>::set(Some((current_id, staked_block)));
+ // break;
+ // }
+ // stakers_number -= 1;
+ // income_acc = BalanceOf::<T>::default();
+ // last_id = current_id;
+ // };
+ // if current_recalc_block >= next_recalc_block_for_stake {
+ // Self::recalculate_and_insert_stake(
+ // &last_id,
+ // staked_block,
+ // next_recalc_block,
+ // amount,
+ // ((current_recalc_block - next_recalc_block_for_stake)
+ // / T::RecalculationInterval::get())
+ // .into() + 1,
+ // &mut income_acc,
+ // );
+ // }
+ // }
+ // }
+
+ {
+ let mut stakers_number = stakers_number.unwrap_or(20);
+ let last_id = RefCell::new(None);
+ let income_acc = RefCell::new(BalanceOf::<T>::default());
+ let amount_acc = RefCell::new(BalanceOf::<T>::default());
+
+ let flush_stake = || -> DispatchResult {
+ if let Some(last_id) = &*last_id.borrow() {
+ if !income_acc.borrow().is_zero() {
+ <T::Currency as Currency<T::AccountId>>::transfer(
+ &T::TreasuryAccountId::get(),
+ last_id,
+ *income_acc.borrow(),
+ ExistenceRequirement::KeepAlive,
+ )
+ .and_then(|_| {
+ Self::add_lock_balance(last_id, *income_acc.borrow())?;
+ <TotalStaked<T>>::try_mutate(|staked| {
+ staked
+ .checked_add(&*income_acc.borrow())
+ .ok_or(ArithmeticError::Overflow.into())
+ })
+ })?;
+
+ Self::deposit_event(Event::StakingRecalculation(
+ last_id.clone(),
+ *amount_acc.borrow(),
+ *income_acc.borrow(),
+ ));
+ }
+
+ *income_acc.borrow_mut() = BalanceOf::<T>::default();
+ *amount_acc.borrow_mut() = BalanceOf::<T>::default();
+ }
+ Ok(())
+ };
+
+ while let Some((
+ (current_id, staked_block),
+ (amount, next_recalc_block_for_stake),
+ )) = storage_iterator.next()
+ {
+ if stakers_number == 0 {
+ NextCalculatedRecord::<T>::set(Some((current_id, staked_block)));
+ break;
+ }
+ if last_id.borrow().as_ref() != Some(¤t_id) {
+ flush_stake()?;
+ *last_id.borrow_mut() = Some(current_id.clone());
+ stakers_number -= 1;
+ };
+ if current_recalc_block >= next_recalc_block_for_stake {
+ *amount_acc.borrow_mut() += amount;
+ Self::recalculate_and_insert_stake(
+ ¤t_id,
+ staked_block,
+ next_recalc_block,
+ amount,
+ ((current_recalc_block - next_recalc_block_for_stake)
+ / T::RecalculationInterval::get())
+ .into() + 1,
+ &mut *income_acc.borrow_mut(),
+ );
+ }
+ }
+ flush_stake()?;
+ }
+
+ Ok(())
+ }
+ }
+}
+
+impl<T: Config> Pallet<T> {
+ pub fn account_id() -> T::AccountId {
+ T::PalletId::get().into_account_truncating()
+ }
+
+ fn unlock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+ let locked_balance = Self::get_locked_balance(staker)
+ .map(|l| l.amount)
+ .ok_or(<Error<T>>::IncorrectLockedBalanceOperation)?;
+
+ // It is understood that we cannot unlock more funds than were locked by staking.
+ // Therefore, if implemented correctly, this error should not occur.
+ Self::set_lock_unchecked(
+ staker,
+ locked_balance
+ .checked_sub(&amount)
+ .ok_or(ArithmeticError::Underflow)?,
+ );
+ Ok(())
+ }
+
+ fn add_lock_balance(staker: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
+ Self::get_locked_balance(staker)
+ .map_or(<BalanceOf<T>>::default(), |l| l.amount)
+ .checked_add(&amount)
+ .map(|new_lock| Self::set_lock_unchecked(staker, new_lock))
+ .ok_or(ArithmeticError::Overflow.into())
+ }
+
+ fn set_lock_unchecked(staker: &T::AccountId, amount: BalanceOf<T>) {
+ if amount.is_zero() {
+ <T::Currency as LockableCurrency<T::AccountId>>::remove_lock(LOCK_IDENTIFIER, &staker);
+ } else {
+ <T::Currency as LockableCurrency<T::AccountId>>::set_lock(
+ LOCK_IDENTIFIER,
+ staker,
+ amount,
+ WithdrawReasons::all(),
+ )
+ }
+ }
+
+ pub fn get_locked_balance(
+ staker: impl EncodeLike<T::AccountId>,
+ ) -> Option<BalanceLock<BalanceOf<T>>> {
+ <T::Currency as ExtendedLockableCurrency<T::AccountId>>::locks(staker)
+ .into_iter()
+ .find(|l| l.id == LOCK_IDENTIFIER)
+ }
+
+ pub fn total_staked_by_id(staker: impl EncodeLike<T::AccountId>) -> Option<BalanceOf<T>> {
+ let staked = Staked::<T>::iter_prefix((staker,))
+ .into_iter()
+ .fold(<BalanceOf<T>>::default(), |acc, (_, (amount, _))| {
+ acc + amount
+ });
+ if staked != <BalanceOf<T>>::default() {
+ Some(staked)
+ } else {
+ None
+ }
+ }
+
+ pub fn total_staked_by_id_per_block(
+ staker: impl EncodeLike<T::AccountId>,
+ ) -> Option<Vec<(T::BlockNumber, BalanceOf<T>)>> {
+ let mut staked = Staked::<T>::iter_prefix((staker,))
+ .into_iter()
+ .map(|(block, (amount, _))| (block, amount))
+ .collect::<Vec<_>>();
+ staked.sort_by_key(|(block, _)| *block);
+ if !staked.is_empty() {
+ Some(staked)
+ } else {
+ None
+ }
+ }
+
+ pub fn cross_id_total_staked(staker: Option<T::CrossAccountId>) -> Option<BalanceOf<T>> {
+ staker.map_or(Some(<TotalStaked<T>>::get()), |s| {
+ Self::total_staked_by_id(s.as_sub())
+ })
+ }
+
+ // pub fn cross_id_locked_balance(staker: T::CrossAccountId) -> BalanceOf<T> {
+ // Self::get_locked_balance(staker.as_sub())
+ // .map(|l| l.amount)
+ // .unwrap_or_default()
+ // }
+
+ pub fn cross_id_total_staked_per_block(
+ staker: T::CrossAccountId,
+ ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {
+ Self::total_staked_by_id_per_block(staker.as_sub()).unwrap_or_default()
+ }
+
+ fn recalculate_and_insert_stake(
+ staker: &T::AccountId,
+ staked_block: T::BlockNumber,
+ next_recalc_block: T::BlockNumber,
+ base: BalanceOf<T>,
+ iters: u32,
+ income_acc: &mut BalanceOf<T>,
+ ) {
+ let income = Self::calculate_income(base, iters);
+
+ base.checked_add(&income).map(|res| {
+ <Staked<T>>::insert((staker, staked_block), (res, next_recalc_block));
+ *income_acc += income;
+ });
+ }
+
+ fn calculate_income<I>(base: I, iters: u32) -> I
+ where
+ I: EncodeLike<BalanceOf<T>> + Balance,
+ {
+ let mut income = base;
+
+ (0..iters).for_each(|_| income += T::IntervalIncome::get() * income);
+
+ income - base
+ }
+
+ fn get_current_recalc_block(current_relay_block: T::BlockNumber) -> T::BlockNumber {
+ (current_relay_block / T::RecalculationInterval::get()) * T::RecalculationInterval::get()
+ }
+
+ // fn get_next_recalc_block(current_relay_block: T::BlockNumber) -> T::BlockNumber {
+ // Self::get_current_recalc_block(current_relay_block) + T::RecalculationInterval::get()
+ // }
+
+ fn get_next_calculated_key() -> Option<Vec<u8>> {
+ Self::get_next_calculated_record().map(|key| Staked::<T>::hashed_key_for(key))
+ }
+}
+
+impl<T: Config> Pallet<T>
+where
+ <<T as Config>::Currency as Currency<T::AccountId>>::Balance: Sum,
+{
+ /// Since user funds are not transferred anywhere by staking, overflow protection is provided
+ /// at the level of the associated type `Balance` of `Currency` trait. In order to overflow,
+ /// the staker must have more funds on his account than the maximum set for `Balance` type.
+ pub fn cross_id_pending_unstake(staker: Option<T::CrossAccountId>) -> BalanceOf<T> {
+ staker.map_or(
+ PendingUnstake::<T>::iter_values()
+ .flat_map(|pendings| pendings.into_iter().map(|(_, amount)| amount))
+ .sum(),
+ |s| {
+ PendingUnstake::<T>::iter_values()
+ .flatten()
+ .filter_map(|(id, amount)| {
+ if id == *s.as_sub() {
+ Some(amount)
+ } else {
+ None
+ }
+ })
+ .sum()
+ },
+ )
+ }
+
+ pub fn cross_id_pending_unstake_per_block(
+ staker: T::CrossAccountId,
+ ) -> Vec<(T::BlockNumber, BalanceOf<T>)> {
+ let mut unsorted_res = vec![];
+ PendingUnstake::<T>::iter().for_each(|(block, pendings)| {
+ pendings.into_iter().for_each(|(id, amount)| {
+ if id == *staker.as_sub() {
+ unsorted_res.push((block, amount));
+ };
+ })
+ });
+
+ unsorted_res.sort_by_key(|(block, _)| *block);
+ unsorted_res
+ }
+}
pallets/app-promotion/src/types.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/app-promotion/src/types.rs
@@ -0,0 +1,107 @@
+use codec::EncodeLike;
+use frame_support::{traits::LockableCurrency, WeakBoundedVec, Parameter, dispatch::DispatchResult};
+
+use pallet_balances::{BalanceLock, Config as BalancesConfig, Pallet as PalletBalances};
+use pallet_common::CollectionHandle;
+
+use sp_runtime::DispatchError;
+use up_data_structs::{CollectionId};
+use sp_std::borrow::ToOwned;
+use pallet_evm_contract_helpers::{Pallet as EvmHelpersPallet, Config as EvmHelpersConfig};
+
+pub trait ExtendedLockableCurrency<AccountId: Parameter>: LockableCurrency<AccountId> {
+ fn locks<KArg>(who: KArg) -> WeakBoundedVec<BalanceLock<Self::Balance>, Self::MaxLocks>
+ where
+ KArg: EncodeLike<AccountId>;
+}
+
+impl<T: BalancesConfig<I>, I: 'static> ExtendedLockableCurrency<T::AccountId>
+ for PalletBalances<T, I>
+{
+ fn locks<KArg>(who: KArg) -> WeakBoundedVec<BalanceLock<Self::Balance>, Self::MaxLocks>
+ where
+ KArg: EncodeLike<T::AccountId>,
+ {
+ Self::locks(who)
+ }
+}
+
+pub trait CollectionHandler {
+ type CollectionId;
+ type AccountId;
+
+ fn set_sponsor(
+ sponsor_id: Self::AccountId,
+ collection_id: Self::CollectionId,
+ ) -> DispatchResult;
+
+ fn remove_collection_sponsor(collection_id: Self::CollectionId) -> DispatchResult;
+
+ fn sponsor(collection_id: Self::CollectionId)
+ -> Result<Option<Self::AccountId>, DispatchError>;
+}
+
+impl<T: pallet_unique::Config> CollectionHandler for pallet_unique::Pallet<T> {
+ type CollectionId = CollectionId;
+
+ type AccountId = T::AccountId;
+
+ fn set_sponsor(
+ sponsor_id: Self::AccountId,
+ collection_id: Self::CollectionId,
+ ) -> DispatchResult {
+ Self::force_set_sponsor(sponsor_id, collection_id)
+ }
+
+ fn remove_collection_sponsor(collection_id: Self::CollectionId) -> DispatchResult {
+ Self::force_remove_collection_sponsor(collection_id)
+ }
+
+ fn sponsor(
+ collection_id: Self::CollectionId,
+ ) -> Result<Option<Self::AccountId>, DispatchError> {
+ Ok(<CollectionHandle<T>>::try_get(collection_id)?
+ .sponsorship
+ .sponsor()
+ .map(|acc| acc.to_owned()))
+ }
+}
+
+pub trait ContractHandler {
+ type ContractId;
+ type AccountId;
+
+ fn set_sponsor(
+ sponsor_id: Self::AccountId,
+ contract_address: Self::ContractId,
+ ) -> DispatchResult;
+
+ fn remove_contract_sponsor(contract_address: Self::ContractId) -> DispatchResult;
+
+ fn sponsor(
+ contract_address: Self::ContractId,
+ ) -> Result<Option<Self::AccountId>, DispatchError>;
+}
+
+impl<T: EvmHelpersConfig> ContractHandler for EvmHelpersPallet<T> {
+ type ContractId = sp_core::H160;
+
+ type AccountId = T::CrossAccountId;
+
+ fn set_sponsor(
+ sponsor_id: Self::AccountId,
+ contract_address: Self::ContractId,
+ ) -> DispatchResult {
+ Self::force_set_sponsor(contract_address, &sponsor_id)
+ }
+
+ fn remove_contract_sponsor(contract_address: Self::ContractId) -> DispatchResult {
+ Self::force_remove_sponsor(contract_address)
+ }
+
+ fn sponsor(
+ contract_address: Self::ContractId,
+ ) -> Result<Option<Self::AccountId>, DispatchError> {
+ Ok(Self::get_sponsor(contract_address))
+ }
+}
pallets/app-promotion/src/weights.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/app-promotion/src/weights.rs
@@ -0,0 +1,209 @@
+// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs
+
+//! Autogenerated weights for pallet_app_promotion
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2022-09-07, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
+
+// Executed Command:
+// target/release/unique-collator
+// benchmark
+// pallet
+// --pallet
+// pallet-app-promotion
+// --wasm-execution
+// compiled
+// --extrinsic
+// *
+// --template
+// .maintain/frame-weight-template.hbs
+// --steps=50
+// --repeat=80
+// --heap-pages=4096
+// --output=./pallets/app-promotion/src/weights.rs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(missing_docs)]
+#![allow(clippy::unnecessary_cast)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use sp_std::marker::PhantomData;
+
+/// Weight functions needed for pallet_app_promotion.
+pub trait WeightInfo {
+ fn on_initialize(b: u32, ) -> Weight;
+ fn set_admin_address() -> Weight;
+ fn payout_stakers(b: u32, ) -> Weight;
+ fn stake() -> Weight;
+ fn unstake() -> Weight;
+ fn sponsor_collection() -> Weight;
+ fn stop_sponsoring_collection() -> Weight;
+ fn sponsor_contract() -> Weight;
+ fn stop_sponsoring_contract() -> Weight;
+}
+
+/// Weights for pallet_app_promotion using the Substrate node and recommended hardware.
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+ // Storage: AppPromotion PendingUnstake (r:1 w:0)
+ // Storage: System Account (r:1 w:1)
+ fn on_initialize(b: u32, ) -> Weight {
+ (2_651_000 as Weight)
+ // Standard Error: 103_000
+ .saturating_add((6_024_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(1 as Weight))
+ .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
+ .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(b as Weight)))
+ }
+ // Storage: AppPromotion Admin (r:0 w:1)
+ fn set_admin_address() -> Weight {
+ (7_117_000 as Weight)
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: ParachainSystem ValidationData (r:1 w:0)
+ // Storage: AppPromotion NextCalculatedRecord (r:1 w:1)
+ // Storage: AppPromotion Staked (r:2 w:0)
+ fn payout_stakers(b: u32, ) -> Weight {
+ (9_958_000 as Weight)
+ // Standard Error: 8_000
+ .saturating_add((4_406_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(4 as Weight))
+ .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion StakesPerAccount (r:1 w:1)
+ // Storage: System Account (r:1 w:1)
+ // Storage: Balances Locks (r:1 w:1)
+ // Storage: ParachainSystem ValidationData (r:1 w:0)
+ // Storage: AppPromotion Staked (r:1 w:1)
+ // Storage: AppPromotion TotalStaked (r:1 w:1)
+ fn stake() -> Weight {
+ (20_574_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(6 as Weight))
+ .saturating_add(T::DbWeight::get().writes(5 as Weight))
+ }
+ // Storage: AppPromotion PendingUnstake (r:1 w:1)
+ // Storage: AppPromotion Staked (r:2 w:1)
+ // Storage: Balances Locks (r:1 w:1)
+ // Storage: System Account (r:1 w:1)
+ // Storage: AppPromotion TotalStaked (r:1 w:1)
+ // Storage: AppPromotion StakesPerAccount (r:0 w:1)
+ fn unstake() -> Weight {
+ (31_703_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(6 as Weight))
+ .saturating_add(T::DbWeight::get().writes(6 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: Common CollectionById (r:1 w:1)
+ fn sponsor_collection() -> Weight {
+ (12_932_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(2 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: Common CollectionById (r:1 w:1)
+ fn stop_sponsoring_collection() -> Weight {
+ (12_453_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(2 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: EvmContractHelpers Sponsoring (r:0 w:1)
+ fn sponsor_contract() -> Weight {
+ (11_952_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(1 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: EvmContractHelpers Sponsoring (r:1 w:1)
+ fn stop_sponsoring_contract() -> Weight {
+ (12_538_000 as Weight)
+ .saturating_add(T::DbWeight::get().reads(2 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+}
+
+// For backwards compatibility and tests
+impl WeightInfo for () {
+ // Storage: AppPromotion PendingUnstake (r:1 w:0)
+ // Storage: System Account (r:1 w:1)
+ fn on_initialize(b: u32, ) -> Weight {
+ (2_651_000 as Weight)
+ // Standard Error: 103_000
+ .saturating_add((6_024_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(1 as Weight))
+ .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
+ .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(b as Weight)))
+ }
+ // Storage: AppPromotion Admin (r:0 w:1)
+ fn set_admin_address() -> Weight {
+ (7_117_000 as Weight)
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: ParachainSystem ValidationData (r:1 w:0)
+ // Storage: AppPromotion NextCalculatedRecord (r:1 w:1)
+ // Storage: AppPromotion Staked (r:2 w:0)
+ fn payout_stakers(b: u32, ) -> Weight {
+ (9_958_000 as Weight)
+ // Standard Error: 8_000
+ .saturating_add((4_406_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(4 as Weight))
+ .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion StakesPerAccount (r:1 w:1)
+ // Storage: System Account (r:1 w:1)
+ // Storage: Balances Locks (r:1 w:1)
+ // Storage: ParachainSystem ValidationData (r:1 w:0)
+ // Storage: AppPromotion Staked (r:1 w:1)
+ // Storage: AppPromotion TotalStaked (r:1 w:1)
+ fn stake() -> Weight {
+ (20_574_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(6 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(5 as Weight))
+ }
+ // Storage: AppPromotion PendingUnstake (r:1 w:1)
+ // Storage: AppPromotion Staked (r:2 w:1)
+ // Storage: Balances Locks (r:1 w:1)
+ // Storage: System Account (r:1 w:1)
+ // Storage: AppPromotion TotalStaked (r:1 w:1)
+ // Storage: AppPromotion StakesPerAccount (r:0 w:1)
+ fn unstake() -> Weight {
+ (31_703_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(6 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(6 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: Common CollectionById (r:1 w:1)
+ fn sponsor_collection() -> Weight {
+ (12_932_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(2 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: Common CollectionById (r:1 w:1)
+ fn stop_sponsoring_collection() -> Weight {
+ (12_453_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(2 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: EvmContractHelpers Sponsoring (r:0 w:1)
+ fn sponsor_contract() -> Weight {
+ (11_952_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(1 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: AppPromotion Admin (r:1 w:0)
+ // Storage: EvmContractHelpers Sponsoring (r:1 w:1)
+ fn stop_sponsoring_contract() -> Weight {
+ (12_538_000 as Weight)
+ .saturating_add(RocksDbWeight::get().reads(2 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+}
pallets/common/Cargo.tomldiffbeforeafterboth--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -40,4 +40,7 @@
"up-data-structs/std",
"pallet-evm/std",
]
-runtime-benchmarks = ["frame-benchmarking"]
+runtime-benchmarks = [
+ "frame-benchmarking/runtime-benchmarks",
+ "up-data-structs/runtime-benchmarks",
+]
pallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -9,6 +9,7 @@
"derive",
] }
log = { default-features = false, version = "0.4.14" }
+ethereum = { version = "0.12.0", default-features = false }
# Substrate
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -17,7 +17,9 @@
//! Implementation of magic contract
use core::marker::PhantomData;
-use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
+use evm_coder::{
+ abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
+};
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};
use pallet_evm::{
ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,
@@ -33,6 +35,35 @@
use up_sponsorship::SponsorshipHandler;
use sp_std::vec::Vec;
+/// Pallet events.
+#[derive(ToLog)]
+pub enum ContractHelpersEvents {
+ /// Contract sponsor was set.
+ ContractSponsorSet {
+ /// Contract address of the affected collection.
+ #[indexed]
+ contract_address: address,
+ /// New sponsor address.
+ sponsor: address,
+ },
+
+ /// New sponsor was confirm.
+ ContractSponsorshipConfirmed {
+ /// Contract address of the affected collection.
+ #[indexed]
+ contract_address: address,
+ /// New sponsor address.
+ sponsor: address,
+ },
+
+ /// Collection sponsor was removed.
+ ContractSponsorRemoved {
+ /// Contract address of the affected collection.
+ #[indexed]
+ contract_address: address,
+ },
+}
+
/// See [`ContractHelpersCall`]
pub struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
@@ -46,7 +77,7 @@
}
/// @title Magic contract, which allows users to reconfigure other contracts
-#[solidity_interface(name = ContractHelpers)]
+#[solidity_interface(name = ContractHelpers, events(ContractHelpersEvents))]
impl<T: Config> ContractHelpers<T>
where
T::AccountId: AsRef<[u8; 32]>,
@@ -91,9 +122,17 @@
self.recorder().consume_sload()?;
self.recorder().consume_sstore()?;
- Pallet::<T>::self_sponsored_enable(&T::CrossAccountId::from_eth(caller), contract_address)
+ let caller = T::CrossAccountId::from_eth(caller);
+
+ Pallet::<T>::ensure_owner(contract_address, *caller.as_eth())
.map_err(dispatch_to_evm::<T>)?;
+ Pallet::<T>::force_set_sponsor(
+ contract_address,
+ &T::CrossAccountId::from_eth(contract_address),
+ )
+ .map_err(dispatch_to_evm::<T>)?;
+
Ok(())
}
pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -16,7 +16,7 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
-#![deny(missing_docs)]
+#![warn(missing_docs)]
use codec::{Decode, Encode, MaxEncodedLen};
pub use pallet::*;
@@ -27,18 +27,24 @@
#[frame_support::pallet]
pub mod pallet {
pub use super::*;
+ use crate::eth::ContractHelpersEvents;
use frame_support::pallet_prelude::*;
use pallet_evm_coder_substrate::DispatchResult;
use sp_core::H160;
- use pallet_evm::account::CrossAccountId;
+ use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
use up_data_structs::SponsorshipState;
+ use evm_coder::ToLog;
#[pallet::config]
pub trait Config:
frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config
{
+ /// Overarching event type.
+ type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
+
/// Address, under which magic contract will be available
type ContractAddress: Get<H160>;
+
/// In case of enabled sponsoring, but no sponsoring rate limit set,
/// this value will be used implicitly
type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;
@@ -150,6 +156,32 @@
QueryKind = ValueQuery,
>;
+ #[pallet::event]
+ #[pallet::generate_deposit(pub fn deposit_event)]
+ pub enum Event<T: Config> {
+ /// Contract sponsor was set.
+ ContractSponsorSet(
+ /// Contract address of the affected collection.
+ H160,
+ /// New sponsor address.
+ T::AccountId,
+ ),
+
+ /// New sponsor was confirm.
+ ContractSponsorshipConfirmed(
+ /// Contract address of the affected collection.
+ H160,
+ /// New sponsor address.
+ T::AccountId,
+ ),
+
+ /// Collection sponsor was removed.
+ ContractSponsorRemoved(
+ /// Contract address of the affected collection.
+ H160,
+ ),
+ }
+
impl<T: Config> Pallet<T> {
/// Get contract owner.
pub fn contract_owner(contract: H160) -> H160 {
@@ -169,43 +201,118 @@
contract,
SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),
);
+
+ <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(
+ contract,
+ sponsor.as_sub().clone(),
+ ));
+ <PalletEvm<T>>::deposit_log(
+ ContractHelpersEvents::ContractSponsorSet {
+ contract_address: contract,
+ sponsor: *sponsor.as_eth(),
+ }
+ .to_log(contract),
+ );
Ok(())
}
- /// Set `contract` as self sponsored.
+ /// TO-DO
///
- /// `sender` must be owner of contract.
- pub fn self_sponsored_enable(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {
- Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;
+ ///
+ pub fn force_set_sponsor(
+ contract_address: H160,
+ sponsor: &T::CrossAccountId,
+ ) -> DispatchResult {
Sponsoring::<T>::insert(
- contract,
- SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(
- contract,
- )),
+ contract_address,
+ SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),
);
+
+ let eth_sponsor = *sponsor.as_eth();
+ let sub_sponsor = sponsor.as_sub().clone();
+
+ <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(
+ contract_address,
+ sub_sponsor.clone(),
+ ));
+ <PalletEvm<T>>::deposit_log(
+ ContractHelpersEvents::ContractSponsorSet {
+ contract_address,
+ sponsor: eth_sponsor,
+ }
+ .to_log(contract_address),
+ );
+
+ <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(
+ contract_address,
+ sub_sponsor,
+ ));
+ <PalletEvm<T>>::deposit_log(
+ ContractHelpersEvents::ContractSponsorshipConfirmed {
+ contract_address,
+ sponsor: eth_sponsor,
+ }
+ .to_log(contract_address),
+ );
+
Ok(())
}
/// Remove sponsor for `contract`.
///
/// `sender` must be owner of contract.
- pub fn remove_sponsor(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {
- Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;
- Sponsoring::<T>::remove(contract);
+ pub fn remove_sponsor(
+ sender: &T::CrossAccountId,
+ contract_address: H160,
+ ) -> DispatchResult {
+ Self::ensure_owner(contract_address, *sender.as_eth())?;
+ Self::force_remove_sponsor(contract_address)
+ }
+
+ /// TO-DO
+ ///
+ ///
+ pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {
+ Sponsoring::<T>::remove(contract_address);
+
+ Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));
+ <PalletEvm<T>>::deposit_log(
+ ContractHelpersEvents::ContractSponsorRemoved { contract_address }
+ .to_log(contract_address),
+ );
+
Ok(())
}
/// Confirm sponsorship.
///
/// `sender` must be same that set via [`set_sponsor`].
- pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {
- match Sponsoring::<T>::get(contract) {
+ pub fn confirm_sponsorship(
+ sender: &T::CrossAccountId,
+ contract_address: H160,
+ ) -> DispatchResult {
+ match Sponsoring::<T>::get(contract_address) {
SponsorshipState::Unconfirmed(sponsor) => {
ensure!(sponsor == *sender, Error::<T>::NoPermission);
+ let eth_sponsor = *sponsor.as_eth();
+ let sub_sponsor = sponsor.as_sub().clone();
Sponsoring::<T>::insert(
- contract,
+ contract_address,
SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),
);
+
+ <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(
+ contract_address,
+ sub_sponsor,
+ ));
+ <PalletEvm<T>>::deposit_log(
+ ContractHelpersEvents::ContractSponsorshipConfirmed {
+ contract_address,
+ sponsor: eth_sponsor,
+ }
+ .to_log(contract_address),
+ );
+
Ok(())
}
SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {
pallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -21,9 +21,19 @@
}
}
+/// @dev inlined interface
+contract ContractHelpersEvents {
+ event ContractSponsorSet(address indexed contractAddress, address sponsor);
+ event ContractSponsorshipConfirmed(
+ address indexed contractAddress,
+ address sponsor
+ );
+ event ContractSponsorRemoved(address indexed contractAddress);
+}
+
/// @title Magic contract, which allows users to reconfigure other contracts
/// @dev the ERC-165 identifier for this interface is 0xd77fab70
-contract ContractHelpers is Dummy, ERC165 {
+contract ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
/// Get user, which deployed specified contract
/// @dev May return zero address in case if contract is deployed
/// using uniquenetwork evm-migration pallet, or using other terms not
pallets/unique/CHANGELOG.mddiffbeforeafterboth--- a/pallets/unique/CHANGELOG.md
+++ b/pallets/unique/CHANGELOG.md
@@ -3,22 +3,29 @@
All notable changes to this project will be documented in this file.
<!-- bureaucrate goes here -->
+
+## [v0.1.4] 2022-09-5
+
+### Added
+
+- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic.
+
## [v0.1.3] 2022-08-16
### Other changes
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
+- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
+- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31
+- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31
Every extrinsic now runs in transaction implicitly, and
`#[transactional]` on pallet dispatchable is now meaningless
Upstream-Change: https://github.com/paritytech/substrate/issues/10806
-- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975
+- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975
New methods allows to call `remove_prefix` with limit multiple times
in the same block
@@ -27,10 +34,12 @@
Upstream-Change: https://github.com/paritytech/substrate/pull/11490
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
+- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
## [v0.1.1] - 2022-07-25
+
### Added
-- Method for creating `ERC721Metadata` compatible NFT collection.
-- Method for creating `ERC721Metadata` compatible ReFungible collection.
-- Method for creating ReFungible collection.
+
+- Method for creating `ERC721Metadata` compatible NFT collection.
+- Method for creating `ERC721Metadata` compatible ReFungible collection.
+- Method for creating ReFungible collection.
pallets/unique/Cargo.tomldiffbeforeafterboth--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -9,7 +9,7 @@
license = 'GPLv3'
name = 'pallet-unique'
repository = 'https://github.com/UniqueNetwork/unique-chain'
-version = "0.1.3"
+version = "0.1.4"
[package.metadata.docs.rs]
targets = ['x86_64-unknown-linux-gnu']
pallets/unique/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/unique/src/benchmarking.rs
+++ b/pallets/unique/src/benchmarking.rs
@@ -46,7 +46,9 @@
)?;
Ok(<pallet_common::CreatedCollectionCount<T>>::get())
}
-fn create_nft_collection<T: Config>(owner: T::AccountId) -> Result<CollectionId, DispatchError> {
+pub fn create_nft_collection<T: Config>(
+ owner: T::AccountId,
+) -> Result<CollectionId, DispatchError> {
create_collection_helper::<T>(owner, CollectionMode::NFT)
}
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -98,7 +98,7 @@
pub mod eth;
#[cfg(feature = "runtime-benchmarks")]
-mod benchmarking;
+pub mod benchmarking;
pub mod weights;
use weights::WeightInfo;
@@ -277,7 +277,7 @@
{
type Error = Error<T>;
- fn deposit_event() = default;
+ pub fn deposit_event() = default;
fn on_initialize(_now: T::BlockNumber) -> Weight {
0
@@ -1103,3 +1103,35 @@
}
}
}
+
+impl<T: Config> Pallet<T> {
+ pub fn force_set_sponsor(sponsor: T::AccountId, collection_id: CollectionId) -> DispatchResult {
+ let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
+ target_collection.check_is_internal()?;
+ target_collection.set_sponsor(sponsor.clone())?;
+
+ Self::deposit_event(Event::<T>::CollectionSponsorSet(
+ collection_id,
+ sponsor.clone(),
+ ));
+
+ ensure!(
+ target_collection.confirm_sponsorship(&sponsor)?,
+ Error::<T>::ConfirmUnsetSponsorFail
+ );
+
+ Self::deposit_event(Event::<T>::SponsorshipConfirmed(collection_id, sponsor));
+
+ target_collection.save()
+ }
+
+ pub fn force_remove_collection_sponsor(collection_id: CollectionId) -> DispatchResult {
+ let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
+ target_collection.check_is_internal()?;
+ target_collection.sponsorship = SponsorshipState::Disabled;
+
+ Self::deposit_event(Event::<T>::CollectionSponsorRemoved(collection_id));
+
+ target_collection.save()
+ }
+}
primitives/app_promotion_rpc/CHANGELOG.mddiffbeforeafterboth--- /dev/null
+++ b/primitives/app_promotion_rpc/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+<!-- bureaucrate goes here -->
primitives/app_promotion_rpc/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/primitives/app_promotion_rpc/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "app-promotion-rpc"
+version = "0.1.0"
+license = "GPLv3"
+edition = "2021"
+
+[dependencies]
+pallet-common = { default-features = false, path = '../../pallets/common' }
+up-data-structs = { default-features = false, path = '../data-structs' }
+codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = [
+ "derive",
+] }
+sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" }
+
+[features]
+default = ["std"]
+std = [
+ "codec/std",
+ "sp-core/std",
+ "sp-std/std",
+ "sp-api/std",
+ "sp-runtime/std",
+ "pallet-common/std",
+ "up-data-structs/std",
+]
primitives/app_promotion_rpc/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/primitives/app_promotion_rpc/src/lib.rs
@@ -0,0 +1,41 @@
+// 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/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use sp_std::vec::Vec;
+use codec::Decode;
+use sp_runtime::{
+ DispatchError,
+ traits::{AtLeast32BitUnsigned, Member},
+};
+
+type Result<T> = core::result::Result<T, DispatchError>;
+
+sp_api::decl_runtime_apis! {
+ #[api_version(2)]
+ /// Trait for generate rpc.
+ pub trait AppPromotionApi<BlockNumber ,CrossAccountId, AccountId> where
+ BlockNumber: Decode + Member + AtLeast32BitUnsigned,
+ AccountId: Decode,
+ CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,
+ {
+ fn total_staked(staker: Option<CrossAccountId>) -> Result<u128>;
+ fn total_staked_per_block(staker: CrossAccountId) -> Result<Vec<(BlockNumber, u128)>>;
+ fn pending_unstake(staker: Option<CrossAccountId>) -> Result<u128>;
+ fn pending_unstake_per_block(staker: CrossAccountId) -> Result<Vec<(BlockNumber, u128)>>;
+ }
+}
primitives/common/src/constants.rsdiffbeforeafterboth--- a/primitives/common/src/constants.rs
+++ b/primitives/common/src/constants.rs
@@ -22,6 +22,7 @@
use crate::types::{BlockNumber, Balance};
pub const MILLISECS_PER_BLOCK: u64 = 12000;
+pub const MILLISECS_PER_RELAY_BLOCK: u64 = 6000;
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
@@ -30,6 +31,11 @@
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
+// These time units are defined in number of relay blocks.
+pub const RELAY_MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_RELAY_BLOCK as BlockNumber);
+pub const RELAY_HOURS: BlockNumber = RELAY_MINUTES * 60;
+pub const RELAY_DAYS: BlockNumber = RELAY_HOURS * 24;
+
pub const MICROUNIQUE: Balance = 1_000_000_000_000;
pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
primitives/rpc/src/lib.rsdiffbeforeafterboth--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -20,9 +20,13 @@
CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property,
PropertyKeyPermission, TokenData, TokenChild,
};
+
use sp_std::vec::Vec;
use codec::Decode;
-use sp_runtime::DispatchError;
+use sp_runtime::{
+ DispatchError,
+ traits::{AtLeast32BitUnsigned, Member},
+};
type Result<T> = core::result::Result<T, DispatchError>;
@@ -120,6 +124,7 @@
/// Get total pieces of token.
fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result<Option<u128>>;
+
fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;
}
}
runtime/common/config/ethereum.rsdiffbeforeafterboth--- a/runtime/common/config/ethereum.rs
+++ b/runtime/common/config/ethereum.rs
@@ -112,6 +112,7 @@
}
impl pallet_evm_contract_helpers::Config for Runtime {
+ type Event = Event;
type ContractAddress = HelpersContractAddress;
type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
}
runtime/common/config/pallets/app_promotion.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/pallets/app_promotion.rs
@@ -0,0 +1,63 @@
+// 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/>.
+
+use crate::{
+ runtime_common::config::pallets::{TreasuryAccountId, RelayChainBlockNumberProvider},
+ Runtime, Balances, BlockNumber, Unique, Event, EvmContractHelpers,
+};
+
+use frame_support::{parameter_types, PalletId};
+use sp_arithmetic::Perbill;
+use up_common::{
+ constants::{UNIQUE, RELAY_DAYS},
+ types::Balance,
+};
+
+#[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))]
+parameter_types! {
+ pub const AppPromotionId: PalletId = PalletId(*b"appstake");
+ pub const RecalculationInterval: BlockNumber = 20;
+ pub const PendingInterval: BlockNumber = 10;
+ pub const Nominal: Balance = UNIQUE;
+ // pub const Day: BlockNumber = DAYS;
+ pub IntervalIncome: Perbill = Perbill::from_rational(RecalculationInterval::get(), RELAY_DAYS) * Perbill::from_rational(5u32, 10_000);
+}
+
+#[cfg(any(feature = "unique-runtime", feature = "quartz-runtime"))]
+parameter_types! {
+ pub const AppPromotionId: PalletId = PalletId(*b"appstake");
+ pub const RecalculationInterval: BlockNumber = RELAY_DAYS;
+ pub const PendingInterval: BlockNumber = 7 * RELAY_DAYS;
+ pub const Nominal: Balance = UNIQUE;
+ // pub const Day: BlockNumber = RELAY_DAYS;
+ pub IntervalIncome: Perbill = Perbill::from_rational(5u32, 10_000);
+}
+
+impl pallet_app_promotion::Config for Runtime {
+ type PalletId = AppPromotionId;
+ type CollectionHandler = Unique;
+ type ContractHandler = EvmContractHelpers;
+ type Currency = Balances;
+ type WeightInfo = pallet_app_promotion::weights::SubstrateWeight<Self>;
+ type TreasuryAccountId = TreasuryAccountId;
+ type RelayBlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
+ type RecalculationInterval = RecalculationInterval;
+ type PendingInterval = PendingInterval;
+ // type Day = Day;
+ type Nominal = Nominal;
+ type IntervalIncome = IntervalIncome;
+ type Event = Event;
+}
runtime/common/config/pallets/mod.rsdiffbeforeafterboth--- a/runtime/common/config/pallets/mod.rs
+++ b/runtime/common/config/pallets/mod.rs
@@ -40,6 +40,9 @@
#[cfg(feature = "scheduler")]
pub mod scheduler;
+#[cfg(feature = "app-promotion")]
+pub mod app_promotion;
+
parameter_types! {
pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
runtime/common/construct_runtime/mod.rsdiffbeforeafterboth--- a/runtime/common/construct_runtime/mod.rs
+++ b/runtime/common/construct_runtime/mod.rs
@@ -77,12 +77,15 @@
#[runtimes(opal)]
RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
+ #[runtimes(opal)]
+ AppPromotion: pallet_app_promotion::{Pallet, Call, Storage, Event<T>} = 73,
+
// Frontier
EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
- EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
+ EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage, Event<T>} = 151,
EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
}
runtime/common/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -189,6 +189,40 @@
}
}
+ impl app_promotion_rpc::AppPromotionApi<Block, BlockNumber, CrossAccountId, AccountId> for Runtime {
+ fn total_staked(staker: Option<CrossAccountId>) -> Result<u128, DispatchError> {
+ #[cfg(not(feature = "app-promotion"))]
+ return unsupported!();
+
+ #[cfg(feature = "app-promotion")]
+ return Ok(<pallet_app_promotion::Pallet<Runtime>>::cross_id_total_staked(staker).unwrap_or_default());
+ }
+
+ fn total_staked_per_block(staker: CrossAccountId) -> Result<Vec<(BlockNumber, u128)>, DispatchError> {
+ #[cfg(not(feature = "app-promotion"))]
+ return unsupported!();
+
+ #[cfg(feature = "app-promotion")]
+ return Ok(<pallet_app_promotion::Pallet<Runtime>>::cross_id_total_staked_per_block(staker));
+ }
+
+ fn pending_unstake(staker: Option<CrossAccountId>) -> Result<u128, DispatchError> {
+ #[cfg(not(feature = "app-promotion"))]
+ return unsupported!();
+
+ #[cfg(feature = "app-promotion")]
+ return Ok(<pallet_app_promotion::Pallet<Runtime>>::cross_id_pending_unstake(staker));
+ }
+
+ fn pending_unstake_per_block(staker: CrossAccountId) -> Result<Vec<(BlockNumber, u128)>, DispatchError> {
+ #[cfg(not(feature = "app-promotion"))]
+ return unsupported!();
+
+ #[cfg(feature = "app-promotion")]
+ return Ok(<pallet_app_promotion::Pallet<Runtime>>::cross_id_pending_unstake_per_block(staker))
+ }
+ }
+
impl rmrk_rpc::RmrkApi<
Block,
AccountId,
@@ -638,6 +672,7 @@
list_benchmark!(list, extra, pallet_unique, Unique);
list_benchmark!(list, extra, pallet_structure, Structure);
list_benchmark!(list, extra, pallet_inflation, Inflation);
+ list_benchmark!(list, extra, pallet_app_promotion, AppPromotion);
list_benchmark!(list, extra, pallet_fungible, Fungible);
list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);
@@ -693,6 +728,7 @@
add_benchmark!(params, batches, pallet_unique, Unique);
add_benchmark!(params, batches, pallet_structure, Structure);
add_benchmark!(params, batches, pallet_inflation, Inflation);
+ add_benchmark!(params, batches, pallet_app_promotion, AppPromotion);
add_benchmark!(params, batches, pallet_fungible, Fungible);
add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);
runtime/opal/Cargo.tomldiffbeforeafterboth--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -37,6 +37,7 @@
'pallet-proxy-rmrk-equip/runtime-benchmarks',
'pallet-unique/runtime-benchmarks',
'pallet-inflation/runtime-benchmarks',
+ 'pallet-app-promotion/runtime-benchmarks',
'pallet-unique-scheduler/runtime-benchmarks',
'pallet-xcm/runtime-benchmarks',
'sp-runtime/runtime-benchmarks',
@@ -82,12 +83,14 @@
'pallet-base-fee/std',
'fp-rpc/std',
'up-rpc/std',
+ 'app-promotion-rpc/std',
'fp-evm-mapping/std',
'fp-self-contained/std',
'parachain-info/std',
'serde',
'pallet-inflation/std',
'pallet-configuration/std',
+ 'pallet-app-promotion/std',
'pallet-common/std',
'pallet-structure/std',
'pallet-fungible/std',
@@ -122,11 +125,12 @@
"orml-vesting/std",
]
limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
-opal-runtime = ['refungible', 'scheduler', 'rmrk']
+opal-runtime = ['refungible', 'scheduler', 'rmrk', 'app-promotion']
refungible = []
scheduler = []
rmrk = []
+app-promotion = []
################################################################################
# Substrate Dependencies
@@ -411,9 +415,11 @@
derivative = "2.2.0"
pallet-unique = { path = '../../pallets/unique', default-features = false }
up-rpc = { path = "../../primitives/rpc", default-features = false }
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false}
rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false }
fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" }
pallet-inflation = { path = '../../pallets/inflation', default-features = false }
+pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
up-data-structs = { path = '../../primitives/data-structs', default-features = false }
pallet-configuration = { default-features = false, path = "../../pallets/configuration" }
pallet-common = { default-features = false, path = "../../pallets/common" }
runtime/quartz/Cargo.tomldiffbeforeafterboth--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -82,6 +82,7 @@
'pallet-base-fee/std',
'fp-rpc/std',
'up-rpc/std',
+ 'app-promotion-rpc/std',
'fp-evm-mapping/std',
'fp-self-contained/std',
'parachain-info/std',
@@ -416,8 +417,10 @@
derivative = "2.2.0"
pallet-unique = { path = '../../pallets/unique', default-features = false }
up-rpc = { path = "../../primitives/rpc", default-features = false }
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false}
fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" }
pallet-inflation = { path = '../../pallets/inflation', default-features = false }
+pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
up-data-structs = { path = '../../primitives/data-structs', default-features = false }
pallet-configuration = { default-features = false, path = "../../pallets/configuration" }
pallet-common = { default-features = false, path = "../../pallets/common" }
runtime/unique/Cargo.tomldiffbeforeafterboth--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -83,6 +83,7 @@
'pallet-base-fee/std',
'fp-rpc/std',
'up-rpc/std',
+ 'app-promotion-rpc/std',
'fp-evm-mapping/std',
'fp-self-contained/std',
'parachain-info/std',
@@ -409,8 +410,10 @@
derivative = "2.2.0"
pallet-unique = { path = '../../pallets/unique', default-features = false }
up-rpc = { path = "../../primitives/rpc", default-features = false }
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false}
rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false }
pallet-inflation = { path = '../../pallets/inflation', default-features = false }
+pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
up-data-structs = { path = '../../primitives/data-structs', default-features = false }
pallet-configuration = { default-features = false, path = "../../pallets/configuration" }
pallet-common = { default-features = false, path = "../../pallets/common" }
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -30,6 +30,7 @@
"testEth": "mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.test.ts'",
"testEthMarketplace": "mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.test.ts'",
"testEthNesting": "mocha --timeout 9999999 -r ts-node/register './**/eth/nesting/**/*.test.ts'",
+ "testEthPayable": "mocha --timeout 9999999 -r ts-node/register './**/eth/payable.test.ts'",
"load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",
"loadTransfer": "ts-node src/transfer.nload.ts",
"testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts",
@@ -64,6 +65,7 @@
"testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts",
"testAdminTransferAndBurn": "mocha --timeout 9999999 -r ts-node/register ./**/adminTransferAndBurn.test.ts",
"testSetMintPermission": "mocha --timeout 9999999 -r ts-node/register ./**/setMintPermission.test.ts",
+ "testSetPublicAccessMode": "mocha --timeout 9999999 -r ts-node/register ./**/setPublicAccessMode.test.ts",
"testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.test.ts",
"testContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/contractSponsoring.test.ts",
"testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",
@@ -71,7 +73,6 @@
"testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",
"testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",
"testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
- "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",
"testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
"testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",
"testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",
@@ -80,10 +81,12 @@
"testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
"testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
"testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
- "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",
+ "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts",
+ "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.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",
+ "testPromotion": "mocha --timeout 9999999 -r ts-node/register ./**/app-promotion.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/app-promotion.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/app-promotion.test.ts
@@ -0,0 +1,800 @@
+// 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 {
+ normalizeAccountId,
+ getModuleNames,
+ Pallets,
+} from './util/helpers';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import {usingPlaygrounds} from './util/playgrounds';
+
+import {encodeAddress} from '@polkadot/util-crypto';
+import {stringToU8a} from '@polkadot/util';
+import {SponsoringMode, contractHelpers, createEthAccountWithBalance, deployFlipper, itWeb3, transferBalanceToEth} from './eth/util/helpers';
+import {DevUniqueHelper} from './util/playgrounds/unique.dev';
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+let alice: IKeyringPair;
+let palletAdmin: IKeyringPair;
+let nominal: bigint;
+const palletAddress = calculatePalleteAddress('appstake');
+let accounts: IKeyringPair[] = [];
+const LOCKING_PERIOD = 20n; // 20 blocks of relay
+const UNLOCKING_PERIOD = 10n; // 20 blocks of parachain
+const rewardAvailableInBlock = (stakedInBlock: bigint) => (stakedInBlock - stakedInBlock % LOCKING_PERIOD) + (LOCKING_PERIOD * 2n);
+
+const beforeEach = async (context: Mocha.Context) => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) context.skip();
+ alice = privateKey('//Alice');
+ palletAdmin = privateKey('//Charlie'); // TODO use custom address
+ await helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));
+ nominal = helper.balance.getOneTokenNominal();
+ await helper.balance.transferToSubstrate(alice, palletAdmin.address, 1000n * nominal);
+ await helper.balance.transferToSubstrate(alice, palletAddress, 1000n * nominal);
+ accounts = await helper.arrange.createCrowd(100, 1000n, alice); // create accounts-pool to speed up tests
+ });
+};
+
+describe('app-promotions.stake extrinsic', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ it('should "lock" staking balance, add it to "staked" map, and increase "totalStaked" amount', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [staker, recepient] = [accounts.pop()!, accounts.pop()!];
+ const totalStakedBefore = await helper.staking.getTotalStaked();
+
+ // Minimum stake amount is 100:
+ await expect(helper.staking.stake(staker, 100n * nominal - 1n)).to.be.eventually.rejected;
+ await helper.staking.stake(staker, 100n * nominal);
+
+ // Staker balance is: miscFrozen: 100, feeFrozen: 100, reserved: 0n...
+ // ...so he can not transfer 900
+ expect (await helper.balance.getSubstrateFull(staker.address)).to.contain({miscFrozen: 100n * nominal, feeFrozen: 100n * nominal, reserved: 0n});
+ await expect(helper.balance.transferToSubstrate(staker, recepient.address, 900n * nominal)).to.be.rejected;
+
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+ // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo?
+ expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 100n * nominal); // total tokens amount staked in app-promotion increased
+
+
+ await helper.staking.stake(staker, 200n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal);
+ expect((await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map((x) => x[1])).to.be.deep.equal([100n * nominal, 200n * nominal]);
+ });
+ });
+
+ it('should allow to create maximum 10 stakes for account', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [staker] = await helper.arrange.createAccounts([2000n], alice);
+ for (let i = 0; i < 10; i++) {
+ await helper.staking.stake(staker, 100n * nominal);
+ }
+
+ // can have 10 stakes
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(1000n * nominal);
+ expect(await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).to.have.length(10);
+
+ await expect(helper.staking.stake(staker, 100n * nominal)).to.be.rejected;
+
+ // After unstake can stake again
+ await helper.staking.unstake(staker);
+ await helper.staking.stake(staker, 100n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.equal(100n * nominal);
+ });
+ });
+
+ it('should reject transaction if stake amount is more than total free balance minus frozen', async () => {
+ await usingPlaygrounds(async helper => {
+ const staker = accounts.pop()!;
+
+ // Can't stake full balance because Alice needs to pay some fee
+ await expect(helper.staking.stake(staker, 1000n * nominal)).to.be.eventually.rejected;
+ await helper.staking.stake(staker, 500n * nominal);
+
+ // Can't stake 500 tkn because Alice has Less than 500 transferable;
+ await expect(helper.staking.stake(staker, 500n * nominal)).to.be.eventually.rejected;
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(500n * nominal);
+ });
+ });
+
+ it('for different accounts in one block is possible', async () => {
+ await usingPlaygrounds(async helper => {
+ const crowd = [accounts.pop()!, accounts.pop()!, accounts.pop()!, accounts.pop()!];
+
+ const crowdStartsToStake = crowd.map(user => helper.staking.stake(user, 100n * nominal));
+ await expect(Promise.all(crowdStartsToStake)).to.be.eventually.fulfilled;
+
+ const crowdStakes = await Promise.all(crowd.map(address => helper.staking.getTotalStaked({Substrate: address.address})));
+ expect(crowdStakes).to.deep.equal([100n * nominal, 100n * nominal, 100n * nominal, 100n * nominal]);
+ });
+ });
+});
+
+describe('unstake balance extrinsic', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ it('should change balance state from "frozen" to "reserved", add it to "pendingUnstake" map, and subtract it from totalStaked', async () => {
+ await usingPlaygrounds(async helper => {
+ const [staker, recepient] = [accounts.pop()!, accounts.pop()!];
+ const totalStakedBefore = await helper.staking.getTotalStaked();
+ await helper.staking.stake(staker, 900n * nominal);
+ await helper.staking.unstake(staker);
+
+ // Right after unstake balance is reserved
+ // Staker can not transfer
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 900n * nominal, miscFrozen: 0n, feeFrozen: 0n});
+ await expect(helper.balance.transferToSubstrate(staker, recepient.address, 100n * nominal)).to.be.rejected;
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(900n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
+ expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore);
+ });
+ });
+
+ it('should unlock balance after unlocking period ends and remove it from "pendingUnstake"', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const staker = accounts.pop()!;
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.unstake(staker);
+ const unstakedInBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}))[0][0];
+
+ // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n
+ await helper.wait.forParachainBlockNumber(unstakedInBlock);
+ expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, miscFrozen: 0n, feeFrozen: 0n});
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+
+ // staker can transfer:
+ await helper.balance.transferToSubstrate(staker, alice.address, 998n * nominal);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(1n);
+ });
+ });
+
+ it('should successfully unstake multiple stakes', async () => {
+ await usingPlaygrounds(async helper => {
+ const staker = accounts.pop()!;
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+ await helper.staking.stake(staker, 300n * nominal);
+
+ // staked: [100, 200, 300]; unstaked: 0
+ let pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
+ let unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);
+ let stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);
+ expect(pendingUnstake).to.be.deep.equal(0n);
+ expect(unstakedPerBlock).to.be.deep.equal([]);
+ expect(stakedPerBlock).to.be.deep.equal([100n * nominal, 200n * nominal, 300n * nominal]);
+
+ // Can unstake multiple stakes
+ await helper.staking.unstake(staker);
+ const unstakingBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}))[0][0];
+ pendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address});
+ unstakedPerBlock = (await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address})).map(stake => stake[1]);
+ stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(stake => stake[1]);
+ expect(pendingUnstake).to.be.equal(600n * nominal);
+ expect(stakedPerBlock).to.be.deep.equal([]);
+ expect(unstakedPerBlock).to.be.deep.equal([600n * nominal]);
+
+ expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 600n * nominal, feeFrozen: 0n, miscFrozen: 0n});
+ await helper.wait.forParachainBlockNumber(unstakingBlock);
+ expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, feeFrozen: 0n, miscFrozen: 0n});
+ expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
+ });
+ });
+
+ it('should not have any effects if no active stakes', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const staker = accounts.pop()!;
+
+ // unstake has no effect if no stakes at all
+ await helper.staking.unstake(staker);
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(0n);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); // TODO bigint closeTo helper
+
+ // TODO stake() unstake() waitUnstaked() unstake();
+
+ // can't unstake if there are only pendingUnstakes
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.unstake(staker);
+ await helper.staking.unstake(staker);
+
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
+ });
+ });
+
+ it('should keep different unlocking block for each unlocking stake', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const staker = accounts.pop()!;
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.unstake(staker);
+ await helper.staking.stake(staker, 120n * nominal);
+ await helper.staking.unstake(staker);
+
+ const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
+ expect(unstakingPerBlock).has.length(2);
+ expect(unstakingPerBlock[0][1]).to.equal(100n * nominal);
+ expect(unstakingPerBlock[1][1]).to.equal(120n * nominal);
+ });
+ });
+
+ it('should be possible for different accounts in one block', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const stakers = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
+
+ await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
+ await Promise.all(stakers.map(staker => helper.staking.unstake(staker)));
+
+ await Promise.all(stakers.map(async (staker) => {
+ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
+ }));
+ });
+ });
+});
+
+describe('Admin adress', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ it('can be set by sudo only', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const nonAdmin = accounts.pop()!;
+ // nonAdmin can not set admin not from himself nor as a sudo
+ await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.eventually.rejected;
+ await expect(helper.signTransaction(nonAdmin, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.eventually.rejected;
+
+ // Alice can
+ await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.eventually.fulfilled;
+ });
+ });
+
+ it('can be any valid CrossAccountId', async () => {
+ // We are not going to set an eth address as a sponsor,
+ // but we do want to check, it doesn't break anything;
+ await usingPlaygrounds(async (helper) => {
+ const account = accounts.pop()!;
+ const ethAccount = helper.address.substrateToEth(account.address);
+ // Alice sets Ethereum address as a sudo. Then Substrate address back...
+ await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.eventually.fulfilled;
+ await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.eventually.fulfilled;
+
+ // ...It doesn't break anything;
+ const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ await expect(helper.signTransaction(account, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
+ });
+ });
+
+ it('can be reassigned', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [oldAdmin, newAdmin, collectionOwner] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress(normalizeAccountId(oldAdmin))))).to.be.eventually.fulfilled;
+ await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress(normalizeAccountId(newAdmin))))).to.be.eventually.fulfilled;
+ await expect(helper.signTransaction(oldAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
+
+ await expect(helper.signTransaction(newAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.eventually.fulfilled;
+ });
+ });
+});
+
+describe('App-promotion collection sponsoring', () => {
+ before(async function () {
+ await beforeEach(this);
+ await usingPlaygrounds(async (helper) => {
+ const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address}));
+ await helper.signTransaction(alice, tx);
+ });
+ });
+
+ it('should actually sponsor transactions', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [collectionOwner, tokenSender, receiver] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'Name', description: 'Description', tokenPrefix: 'Prefix', limits: {sponsorTransferTimeout: 0}});
+ const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address});
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId));
+ const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress);
+
+ await token.transfer(tokenSender, {Substrate: receiver.address});
+ expect (await token.getOwner()).to.be.deep.equal({Substrate: receiver.address});
+ const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress);
+
+ // senders balance the same, transaction has sponsored
+ expect (await helper.balance.getSubstrate(tokenSender.address)).to.be.equal(1000n * nominal);
+ expect (palletBalanceBefore > palletBalanceAfter).to.be.true;
+ });
+ });
+
+ it('can not be set by non admin', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];
+
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
+ expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled');
+ });
+ });
+
+ it('should set pallet address as confirmed admin', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [collectionOwner, oldSponsor] = [accounts.pop()!, accounts.pop()!];
+
+ // Can set sponsoring for collection without sponsor
+ const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.eventually.fulfilled;
+ expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+
+ // Can set sponsoring for collection with unconfirmed sponsor
+ const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});
+ expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address});
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.eventually.fulfilled;
+ expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+
+ // Can set sponsoring for collection with confirmed sponsor
+ const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});
+ await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor);
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.eventually.fulfilled;
+ expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+ });
+ });
+
+ it('can be overwritten by collection owner', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [collectionOwner, newSponsor] = [accounts.pop()!, accounts.pop()!];
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ const collectionId = collection.collectionId;
+
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;
+
+ // Collection limits still can be changed by the owner
+ expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true;
+ expect((await collection.getData())?.raw.limits.sponsorTransferTimeout).to.be.equal(0);
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+
+ // Collection sponsor can be changed too
+ expect((await collection.setSponsor(collectionOwner, newSponsor.address))).to.be.true;
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: newSponsor.address});
+ });
+ });
+
+ it('should not overwrite collection limits set by the owner earlier', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};
+ const collectionWithLimits = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
+
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.eventually.fulfilled;
+ expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);
+ });
+ });
+
+ it('should reject transaction if collection doesn\'t exist', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const collectionOwner = accounts.pop()!;
+
+ // collection has never existed
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(999999999))).to.be.eventually.rejected;
+ // collection has been burned
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ await collection.burn(collectionOwner);
+
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
+ });
+ });
+});
+
+describe('app-promotion stopSponsoringCollection', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ it('can not be called by non-admin', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.eventually.fulfilled;
+
+ await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.eventually.rejected;
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
+ });
+ });
+
+ it('should set sponsoring as disabled', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [collectionOwner, recepient] = [accounts.pop()!, accounts.pop()!];
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}});
+ const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address});
+
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.sponsorCollection(collection.collectionId));
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId));
+
+ expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');
+
+ // Transactions are not sponsored anymore:
+ const ownerBalanceBefore = await helper.balance.getSubstrate(collectionOwner.address);
+ await token.transfer(collectionOwner, {Substrate: recepient.address});
+ const ownerBalanceAfter = await helper.balance.getSubstrate(collectionOwner.address);
+ expect(ownerBalanceAfter < ownerBalanceBefore).to.be.equal(true);
+ });
+ });
+
+ it('should not affect collection which is not sponsored by pallete', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const collectionOwner = accounts.pop()!;
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: collectionOwner.address});
+ await collection.confirmSponsorship(collectionOwner);
+
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.eventually.rejected;
+
+ expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address});
+ });
+ });
+
+ it('should reject transaction if collection does not exist', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const collectionOwner = accounts.pop()!;
+ const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+
+ await collection.burn(collectionOwner);
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.eventually.rejected;
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.stopSponsoringCollection(999999999))).to.be.eventually.rejected;
+ });
+ });
+});
+
+describe('app-promotion contract sponsoring', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ itWeb3('should set palletes address as a sponsor', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ const contractMethods = contractHelpers(web3, contractOwner);
+
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address));
+
+ expect(await contractMethods.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ expect((await api.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner);
+ expect((await api.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({
+ confirmed: {
+ substrate: palletAddress,
+ },
+ });
+ });
+ });
+
+ itWeb3('should overwrite sponsoring mode and existed sponsor', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ const contractMethods = contractHelpers(web3, contractOwner);
+
+ await expect(contractMethods.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
+
+ // Contract is self sponsored
+ expect((await api.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.be.deep.equal({
+ confirmed: {
+ ethereum: flipper.options.address.toLowerCase(),
+ },
+ });
+
+ // set promotion sponsoring
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address));
+
+ // new sponsor is pallet address
+ expect(await contractMethods.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ expect((await api.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner);
+ expect((await api.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({
+ confirmed: {
+ substrate: palletAddress,
+ },
+ });
+ });
+ });
+
+ itWeb3('can be overwritten by contract owner', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ const contractMethods = contractHelpers(web3, contractOwner);
+
+ // contract sponsored by pallet
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address));
+
+ // owner sets self sponsoring
+ await expect(contractMethods.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
+
+ expect(await contractMethods.methods.hasSponsor(flipper.options.address).call()).to.be.true;
+ expect((await api.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner);
+ expect((await api.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({
+ confirmed: {
+ ethereum: flipper.options.address.toLowerCase(),
+ },
+ });
+ });
+ });
+
+ itWeb3('can not be set by non admin', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const nonAdmin = accounts.pop()!;
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ const contractMethods = contractHelpers(web3, contractOwner);
+
+ await expect(contractMethods.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
+
+ // nonAdmin calls sponsorContract
+ await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address))).to.be.rejected;
+
+ // contract still self-sponsored
+ expect((await api.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({
+ confirmed: {
+ ethereum: flipper.options.address.toLowerCase(),
+ },
+ });
+ });
+
+ itWeb3('should be rejected for non-contract address', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+
+ });
+ });
+ });
+
+ itWeb3('should actually sponsor transactions', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ const contractHelper = contractHelpers(web3, contractOwner);
+ await contractHelper.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: contractOwner});
+ await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner});
+ await transferBalanceToEth(api, alice, flipper.options.address, 1000n);
+
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address));
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ const callerBalance = await helper.balance.getEthereum(caller);
+ const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address);
+
+ expect(callerBalance).to.be.equal(1000n * nominal);
+ expect(1000n * nominal > contractBalanceAfter).to.be.true;
+ });
+ });
+});
+
+describe('app-promotion stopSponsoringContract', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ itWeb3('should remove pallet address from contract sponsors', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ await transferBalanceToEth(api, alice, flipper.options.address);
+ const contractHelper = contractHelpers(web3, contractOwner);
+ await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner});
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address));
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringContract(flipper.options.address));
+
+ expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false;
+ expect((await api.query.evmContractHelpers.owner(flipper.options.address)).toJSON()).to.be.equal(contractOwner);
+ expect((await api.query.evmContractHelpers.sponsoring(flipper.options.address)).toJSON()).to.deep.equal({
+ disabled: null,
+ });
+
+ await flipper.methods.flip().send({from: caller});
+ expect(await flipper.methods.getValue().call()).to.be.true;
+
+ const callerBalance = await helper.balance.getEthereum(caller);
+ const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address);
+
+ // caller payed for call
+ expect(1000n * nominal > callerBalance).to.be.true;
+ expect(contractBalanceAfter).to.be.equal(1000n * nominal);
+ });
+ });
+
+ itWeb3('can not be called by non-admin', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const nonAdmin = accounts.pop()!;
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+
+ await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorContract(flipper.options.address));
+ await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.stopSponsoringContract(flipper.options.address))).to.be.rejected;
+ });
+ });
+
+ itWeb3('should not affect a contract which is not sponsored by pallete', async ({api, web3, privateKeyWrapper}) => {
+ await usingPlaygrounds(async (helper) => {
+ const nonAdmin = accounts.pop()!;
+ const contractOwner = (await createEthAccountWithBalance(api, web3, privateKeyWrapper)).toLowerCase();
+ const flipper = await deployFlipper(web3, contractOwner);
+ const contractHelper = contractHelpers(web3, contractOwner);
+ await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;
+
+ await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.stopSponsoringContract(flipper.options.address))).to.be.rejected;
+ });
+ });
+});
+
+describe('app-promotion rewards', () => {
+ before(async function () {
+ await beforeEach(this);
+ });
+
+ it('can not be called by non admin', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const nonAdmin = accounts.pop()!;
+ await expect(helper.signTransaction(nonAdmin, helper.api!.tx.appPromotion.payoutStakers(100))).to.be.rejected;
+ });
+ });
+
+ it('should credit 0.05% for staking period', async () => {
+ await usingPlaygrounds(async helper => {
+ const staker = accounts.pop()!;
+
+ await waitPromotionPeriodDoesntEnd(helper);
+
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+
+ // wait rewards are available:
+ const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[1][0];
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock));
+
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
+
+ const totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
+ expect(totalStakedPerBlock).to.be.deep.equal([calculateIncome(100n * nominal, 10n), calculateIncome(200n * nominal, 10n)]);
+ });
+ });
+
+ it('shoud be paid for more than one period if payments was missed', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const staker = accounts.pop()!;
+
+ await helper.staking.stake(staker, 100n * nominal);
+ // wait for two rewards are available:
+ const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock) + LOCKING_PERIOD);
+
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
+ const stakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ const frozenBalanceShouldBe = calculateIncome(100n * nominal, 10n, 2);
+ expect(stakedPerBlock[0][1]).to.be.equal(frozenBalanceShouldBe);
+
+ const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);
+
+ expect(stakerFullBalance).to.contain({reserved: 0n, feeFrozen: frozenBalanceShouldBe, miscFrozen: frozenBalanceShouldBe});
+ });
+ });
+
+ it('should not be credited for unstaked (reserved) balance', async () => {
+ await usingPlaygrounds(async helper => {
+ // staker unstakes before rewards has been payed
+ const staker = accounts.pop()!;
+ await helper.staking.stake(staker, 100n * nominal);
+ const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock) + LOCKING_PERIOD);
+ await helper.staking.unstake(staker);
+
+ // so he did not receive any rewards
+ const totalBalanceBefore = await helper.balance.getSubstrate(staker.address);
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
+ const totalBalanceAfter = await helper.balance.getSubstrate(staker.address);
+
+ expect(totalBalanceBefore).to.be.equal(totalBalanceAfter);
+ });
+ });
+
+ it('should bring compound interest', async () => {
+ await usingPlaygrounds(async helper => {
+ const staker = accounts.pop()!;
+
+ await helper.staking.stake(staker, 100n * nominal);
+
+ const stakedInBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}))[0][0];
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock));
+
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
+ let totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
+ expect(totalStakedPerBlock).to.deep.equal([calculateIncome(100n * nominal, 10n)]);
+
+ await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock) + LOCKING_PERIOD);
+ await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
+ totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
+ expect(totalStakedPerBlock).to.deep.equal([calculateIncome(100n * nominal, 10n, 2)]);
+ });
+ });
+
+ it.skip('can be paid 1000 rewards in a time', async () => {
+ // all other stakes should be unstaked
+ await usingPlaygrounds(async (helper) => {
+ const oneHundredStakers = await helper.arrange.createCrowd(100, 1050n, alice);
+
+ // stakers stakes 10 times each
+ for (let i = 0; i < 10; i++) {
+ await Promise.all(oneHundredStakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
+ }
+ await helper.wait.newBlocks(40);
+ const result = await helper.signTransaction(palletAdmin, helper.api!.tx.appPromotion.payoutStakers(100));
+ });
+ });
+
+ it.skip('can handle 40.000 rewards', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [donor] = await helper.arrange.createAccounts([7_000_000n], alice);
+ const crowdStakes = async () => {
+ // each account in the crowd stakes 2 times
+ const crowd = await helper.arrange.createCrowd(500, 300n, donor);
+ await Promise.all(crowd.map(account => helper.staking.stake(account, 100n * nominal)));
+ await Promise.all(crowd.map(account => helper.staking.stake(account, 100n * nominal)));
+ //
+ };
+
+ for (let i = 0; i < 40; i++) {
+ await crowdStakes();
+ }
+
+ // TODO pay rewards for some period
+ });
+ });
+});
+
+function calculatePalleteAddress(palletId: any) {
+ const address = stringToU8a(('modl' + palletId).padEnd(32, '\0'));
+ return encodeAddress(address);
+}
+
+function calculateIncome(base: bigint, calcPeriod: bigint, iter = 0): bigint {
+ const DAY = 7200n;
+ const ACCURACY = 1_000_000_000n;
+ const income = base + base * (ACCURACY * (calcPeriod * 5n) / (10_000n * DAY)) / ACCURACY ;
+
+ if (iter > 1) {
+ return calculateIncome(income, calcPeriod, iter - 1);
+ } else return income;
+}
+
+// Wait while promotion period less than specified block, to avoid boundary cases
+// 0 if this should be the beginning of the period.
+async function waitPromotionPeriodDoesntEnd(helper: DevUniqueHelper, waitBlockLessThan = LOCKING_PERIOD / 3n) {
+ const relayBlockNumber = (await helper.api!.query.parachainSystem.validationData()).value.relayParentNumber.toNumber(); // await helper.chain.getLatestBlockNumber();
+ const currentPeriodBlock = BigInt(relayBlockNumber) % LOCKING_PERIOD;
+
+ if (currentPeriodBlock > waitBlockLessThan) {
+ await helper.wait.forRelayBlockNumber(BigInt(relayBlockNumber) + LOCKING_PERIOD - currentPeriodBlock);
+ }
+}
tests/src/approve.test.tsdiffbeforeafterboth--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -79,11 +79,12 @@
it('[nft] Remove approval by using 0 amount', async () => {
await usingPlaygrounds(async (helper) => {
- const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+ const collectionId = collection.collectionId;
const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
- await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 0n);
+ await helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0).signAndSend(alice);
expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
});
});
@@ -97,7 +98,7 @@
const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountBefore).to.be.equal(BigInt(1));
- await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 0n);
+ await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountAfter).to.be.equal(BigInt(0));
});
@@ -111,7 +112,7 @@
const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountBefore).to.be.equal(BigInt(100));
- await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 0n);
+ await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountAfter).to.be.equal(BigInt(0));
});
@@ -289,7 +290,7 @@
const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
const tokenId = await helper.ft.getLastTokenId(collectionId);
- await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 10n);
+ await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 10n);
const charlieBefore = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address}, 2n);
@@ -321,7 +322,7 @@
const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
- await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 0n);
+ await helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0).signAndSend(alice);
expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
const transferTokenFromTx = async () => helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: bob.address});
await expect(transferTokenFromTx()).to.be.rejected;
@@ -337,7 +338,7 @@
const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountBefore).to.be.equal(BigInt(1));
- await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 0n);
+ await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountAfter).to.be.equal(BigInt(0));
@@ -354,7 +355,7 @@
const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountBefore).to.be.equal(BigInt(100));
- await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 0n);
+ await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
expect(amountAfter).to.be.equal(BigInt(0));
@@ -379,8 +380,7 @@
await usingPlaygrounds(async (helper) => {
const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
- const approveTx = async () => helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}, undefined, 2n);
- await expect(approveTx()).to.be.rejected;
+ await helper.api?.tx.unique.approve({Substrate: charlie.address}, collectionId, tokenId, 2).signAndSend(bob);
expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;
});
});
@@ -390,7 +390,7 @@
const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
const tokenId = await helper.ft.getLastTokenId(collectionId);
- const approveTx = async () => helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 11n);
+ const approveTx = async () => helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 11n);
await expect(approveTx()).to.be.rejected;
});
});
@@ -399,7 +399,7 @@
await usingPlaygrounds(async (helper) => {
const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
- const approveTx = async () => helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, undefined, 101n);
+ const approveTx = async () => helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 101n);
await expect(approveTx()).to.be.rejected;
});
});
@@ -658,9 +658,9 @@
const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
await helper.rft.transferToken(alice, collectionId, tokenId, {Substrate: bob.address}, 100n);
- await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, undefined, 100n);
+ await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 100n);
- const approveTx = async () => helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, undefined, 101n);
+ const approveTx = async () => helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 101n);
await expect(approveTx()).to.be.rejected;
});
});
@@ -672,8 +672,8 @@
const tokenId = await helper.ft.getLastTokenId(collectionId);
await helper.ft.transferToken(alice, collectionId, tokenId, {Substrate: bob.address}, 10n);
- await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, undefined, 10n);
- const approveTx = async () => helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, undefined, 11n);
+ await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 10n);
+ const approveTx = async () => helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 11n);
await expect(approveTx()).to.be.rejected;
});
});
tests/src/eth/api/ContractHelpers.soldiffbeforeafterboth--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -12,9 +12,19 @@
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
+/// @dev inlined interface
+interface ContractHelpersEvents {
+ event ContractSponsorSet(address indexed contractAddress, address sponsor);
+ event ContractSponsorshipConfirmed(
+ address indexed contractAddress,
+ address sponsor
+ );
+ event ContractSponsorRemoved(address indexed contractAddress);
+}
+
/// @title Magic contract, which allows users to reconfigure other contracts
/// @dev the ERC-165 identifier for this interface is 0xd77fab70
-interface ContractHelpers is Dummy, ERC165 {
+interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
/// Get user, which deployed specified contract
/// @dev May return zero address in case if contract is deployed
/// using uniquenetwork evm-migration pallet, or using other terms not
tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth--- a/tests/src/eth/collectionAdmin.test.ts
+++ b/tests/src/eth/collectionAdmin.test.ts
@@ -15,7 +15,7 @@
import {expect} from 'chai';
import privateKey from '../substrate/privateKey';
-import { UNIQUE } from '../util/helpers';
+import {UNIQUE} from '../util/helpers';
import {
createEthAccount,
createEthAccountWithBalance,
@@ -24,7 +24,6 @@
getCollectionAddressFromResult,
itWeb3,
recordEthFee,
- subToEth,
} from './util/helpers';
describe('Add collection admins', () => {
@@ -37,7 +36,7 @@
.send();
const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
- const newAdmin = await createEthAccount(web3);
+ const newAdmin = createEthAccount(web3);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
const adminList = await api.rpc.unique.adminlist(collectionId);
@@ -92,7 +91,7 @@
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
await collectionEvm.methods.addCollectionAdmin(admin).send();
- const user = await createEthAccount(web3);
+ const user = createEthAccount(web3);
await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin}))
.to.be.rejectedWith('NoPermission');
@@ -114,7 +113,7 @@
const notAdmin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
- const user = await createEthAccount(web3);
+ const user = createEthAccount(web3);
await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin}))
.to.be.rejectedWith('NoPermission');
@@ -175,7 +174,7 @@
.send();
const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
- const newAdmin = await createEthAccount(web3);
+ const newAdmin = createEthAccount(web3);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
{
@@ -226,7 +225,7 @@
const admin0 = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
await collectionEvm.methods.addCollectionAdmin(admin0).send();
- const admin1 = await createEthAccount(web3);
+ const admin1 = createEthAccount(web3);
await collectionEvm.methods.addCollectionAdmin(admin1).send();
await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0}))
@@ -253,7 +252,7 @@
const admin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
await collectionEvm.methods.addCollectionAdmin(admin).send();
- const notAdmin = await createEthAccount(web3);
+ const notAdmin = createEthAccount(web3);
await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin}))
.to.be.rejectedWith('NoPermission');
tests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -1,5 +1,5 @@
import {addToAllowListExpectSuccess, bigIntToSub, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';
-import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub, subToEth} from './util/helpers';
+import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub} from './util/helpers';
import nonFungibleAbi from './nonFungibleAbi.json';
import {expect} from 'chai';
import {evmToAddress} from '@polkadot/util-crypto';
tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -15,6 +15,7 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
import {expect} from 'chai';
+import { expectSubstrateEventsAtBlock } from '../util/helpers';
import {
contractHelpers,
createEthAccountWithBalance,
@@ -24,6 +25,7 @@
SponsoringMode,
createEthAccount,
ethBalanceViaSub,
+ normalizeEvents,
} from './util/helpers';
describe('Sponsoring EVM contracts', () => {
@@ -36,6 +38,41 @@
expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
});
+ itWeb3('Set self sponsored events', async ({api, web3, privateKeyWrapper}) => {
+ const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const flipper = await deployFlipper(web3, owner);
+ const helpers = contractHelpers(web3, owner);
+
+ const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
+ // console.log(result);
+ const ethEvents = normalizeEvents(result.events);
+ expect(ethEvents).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorSet',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: flipper.options.address,
+ },
+ },
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorshipConfirmed',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: flipper.options.address,
+ },
+ },
+ ]);
+
+ await expectSubstrateEventsAtBlock(
+ api,
+ result.blockNumber,
+ 'evmContractHelpers',
+ ['ContractSponsorSet','ContractSponsorshipConfirmed'],
+ );
+ });
+
itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -75,6 +112,33 @@
expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;
});
+ itWeb3('Set sponsor event', async ({api, web3, privateKeyWrapper}) => {
+ const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const flipper = await deployFlipper(web3, owner);
+ const helpers = contractHelpers(web3, owner);
+
+ const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ const events = normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorSet',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: sponsor,
+ },
+ },
+ ]);
+
+ await expectSubstrateEventsAtBlock(
+ api,
+ result.blockNumber,
+ 'evmContractHelpers',
+ ['ContractSponsorSet'],
+ );
+ });
+
itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -97,6 +161,33 @@
expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
});
+ itWeb3('Confirm sponsorship event', async ({api, web3, privateKeyWrapper}) => {
+ const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const flipper = await deployFlipper(web3, owner);
+ const helpers = contractHelpers(web3, owner);
+ await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
+ const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+ const events = normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorshipConfirmed',
+ args: {
+ contractAddress: flipper.options.address,
+ sponsor: sponsor,
+ },
+ },
+ ]);
+
+ await expectSubstrateEventsAtBlock(
+ api,
+ result.blockNumber,
+ 'evmContractHelpers',
+ ['ContractSponsorshipConfirmed'],
+ );
+ });
+
itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -160,6 +251,35 @@
expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
});
+ itWeb3('Remove sponsor event', async ({api, web3, privateKeyWrapper}) => {
+ const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+ const flipper = await deployFlipper(web3, owner);
+ const helpers = contractHelpers(web3, owner);
+
+ await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+ await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+
+ const result = await helpers.methods.removeSponsor(flipper.options.address).send();
+ const events = normalizeEvents(result.events);
+ expect(events).to.be.deep.equal([
+ {
+ address: flipper.options.address,
+ event: 'ContractSponsorRemoved',
+ args: {
+ contractAddress: flipper.options.address,
+ },
+ },
+ ]);
+
+ await expectSubstrateEventsAtBlock(
+ api,
+ result.blockNumber,
+ 'evmContractHelpers',
+ ['ContractSponsorRemoved'],
+ );
+ });
+
itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
tests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth--- a/tests/src/eth/createNFTCollection.test.ts
+++ b/tests/src/eth/createNFTCollection.test.ts
@@ -181,7 +181,7 @@
});
itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {
- const owner = await createEthAccount(web3);
+ const owner = createEthAccount(web3);
const helper = evmCollectionHelpers(web3, owner);
const collectionName = 'A';
const description = 'A';
@@ -194,7 +194,7 @@
itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const notOwner = await createEthAccount(web3);
+ const notOwner = createEthAccount(web3);
const collectionHelpers = evmCollectionHelpers(web3, owner);
const result = await collectionHelpers.methods.createNonfungibleCollection('A', 'A', 'A').send();
const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
tests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -189,7 +189,7 @@
});
itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {
- const owner = await createEthAccount(web3);
+ const owner = createEthAccount(web3);
const helper = evmCollectionHelpers(web3, owner);
const collectionName = 'A';
const description = 'A';
@@ -202,7 +202,7 @@
itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const notOwner = await createEthAccount(web3);
+ const notOwner = createEthAccount(web3);
const collectionHelpers = evmCollectionHelpers(web3, owner);
const result = await collectionHelpers.methods.createRefungibleCollection('A', 'A', 'A').send();
const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
tests/src/eth/nesting/nest.test.tsdiffbeforeafterboth--- a/tests/src/eth/nesting/nest.test.ts
+++ b/tests/src/eth/nesting/nest.test.ts
@@ -1,217 +1,220 @@
-import {ApiPromise} from '@polkadot/api';
+import {IKeyringPair} from '@polkadot/types/types';
import {Contract} from 'web3-eth-contract';
-import {expect} from 'chai';
-import Web3 from 'web3';
-import {createEthAccountWithBalance, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, tokenIdToAddress} from '../../eth/util/helpers';
-import nonFungibleAbi from '../nonFungibleAbi.json';
+import {itEth, EthUniqueHelper, usingEthPlaygrounds, expect} from '../util/playgrounds';
+
const createNestingCollection = async (
- api: ApiPromise,
- web3: Web3,
+ helper: EthUniqueHelper,
owner: string,
): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
- const collectionHelper = evmCollectionHelpers(web3, owner);
-
- const result = await collectionHelper.methods
- .createNonfungibleCollection('A', 'B', 'C')
- .send();
- const {collectionIdAddress: collectionAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+ const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C');
- const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionAddress, {from: owner, ...GAS_ARGS});
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
await contract.methods.setCollectionNesting(true).send({from: owner});
return {collectionId, collectionAddress, contract};
};
-describe('Integration Test: EVM Nesting', () => {
- itWeb3('NFT: allows an Owner to nest/unnest their token', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const {collectionId, contract} = await createNestingCollection(api, web3, owner);
- // Create a token to be nested
- const targetNFTTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- targetNFTTokenId,
- ).send({from: owner});
-
- const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId);
-
- // Create a nested token
- const firstTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- targetNftTokenAddress,
- firstTokenId,
- ).send({from: owner});
+describe('EVM nesting tests group', () => {
+ let donor: IKeyringPair;
- expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Create a token to be nested and nest
- const secondTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- secondTokenId,
- ).send({from: owner});
-
- await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
-
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Unnest token back
- await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = privateKey('//Alice');
+ });
});
- itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
- const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);
- await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
-
- // Create a token to nest into
- const targetNftTokenId = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- targetNftTokenId,
- ).send({from: owner});
- const nftTokenAddressA1 = tokenIdToAddress(collectionIdA, targetNftTokenId);
-
- // Create a token for nesting in the same collection as the target
- const nftTokenIdA = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- nftTokenIdA,
- ).send({from: owner});
-
- // Create a token for nesting in a different collection
- const nftTokenIdB = await contractB.methods.nextTokenId().call();
- await contractB.methods.mint(
- owner,
- nftTokenIdB,
- ).send({from: owner});
-
- // Nest
- await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
- expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
-
- await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
- expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
- });
-});
-
-describe('Negative Test: EVM Nesting', async() => {
- itWeb3('NFT: disallows to nest token if nesting is disabled', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId, contract} = await createNestingCollection(api, web3, owner);
- await contract.methods.setCollectionNesting(false).send({from: owner});
-
- // Create a token to nest into
- const targetNftTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- targetNftTokenId,
- ).send({from: owner});
-
- const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNftTokenId);
-
- // Create a token to nest
- const nftTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- nftTokenId,
- ).send({from: owner});
-
- // Try to nest
- await expect(contract.methods
- .transfer(targetNftTokenAddress, nftTokenId)
- .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId, contract} = await createNestingCollection(api, web3, owner);
-
- // Mint a token
- const targetTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- targetTokenId,
- ).send({from: owner});
- const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId);
-
- // Mint a token belonging to a different account
- const tokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- malignant,
- tokenId,
- ).send({from: owner});
-
- // Try to nest one token in another as a non-owner account
- await expect(contract.methods
- .transfer(targetTokenAddress, tokenId)
- .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
- const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);
-
- await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
-
- // Create a token in one collection
- const nftTokenIdA = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- nftTokenIdA,
- ).send({from: owner});
- const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);
-
- // Create a token in another collection belonging to someone else
- const nftTokenIdB = await contractB.methods.nextTokenId().call();
- await contractB.methods.mint(
- malignant,
- nftTokenIdB,
- ).send({from: owner});
-
- // Try to drag someone else's token into the other collection and nest
- await expect(contractB.methods
- .transfer(nftTokenAddressA, nftTokenIdB)
- .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ describe('Integration Test: EVM Nesting', () => {
+ itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Create a token to be nested
+ const targetNFTTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ targetNFTTokenId,
+ ).send({from: owner});
+
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
+
+ // Create a nested token
+ const firstTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ targetNftTokenAddress,
+ firstTokenId,
+ ).send({from: owner});
+
+ expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Create a token to be nested and nest
+ const secondTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ secondTokenId,
+ ).send({from: owner});
+
+ await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
+
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Unnest token back
+ await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
+ });
+
+ itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);
+ await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
+
+ // Create a token to nest into
+ const targetNftTokenId = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ targetNftTokenId,
+ ).send({from: owner});
+ const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);
+
+ // Create a token for nesting in the same collection as the target
+ const nftTokenIdA = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ nftTokenIdA,
+ ).send({from: owner});
+
+ // Create a token for nesting in a different collection
+ const nftTokenIdB = await contractB.methods.nextTokenId().call();
+ await contractB.methods.mint(
+ owner,
+ nftTokenIdB,
+ ).send({from: owner});
+
+ // Nest
+ await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
+ expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
+
+ await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
+ expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
+ });
});
- itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
- const {contract: contractB} = await createNestingCollection(api, web3, owner);
-
- await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});
-
- // Create a token in one collection
- const nftTokenIdA = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- nftTokenIdA,
- ).send({from: owner});
- const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);
-
- // Create a token in another collection
- const nftTokenIdB = await contractB.methods.nextTokenId().call();
- await contractB.methods.mint(
- owner,
- nftTokenIdB,
- ).send({from: owner});
-
- // Try to nest into a token in the other collection, disallowed in the first
- await expect(contractB.methods
- .transfer(nftTokenAddressA, nftTokenIdB)
- .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
+ describe('Negative Test: EVM Nesting', async() => {
+ itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+ await contract.methods.setCollectionNesting(false).send({from: owner});
+
+ // Create a token to nest into
+ const targetNftTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ targetNftTokenId,
+ ).send({from: owner});
+
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNftTokenId);
+
+ // Create a token to nest
+ const nftTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ nftTokenId,
+ ).send({from: owner});
+
+ // Try to nest
+ await expect(contract.methods
+ .transfer(targetNftTokenAddress, nftTokenId)
+ .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malignant = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Mint a token
+ const targetTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ targetTokenId,
+ ).send({from: owner});
+ const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
+
+ // Mint a token belonging to a different account
+ const tokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ malignant,
+ tokenId,
+ ).send({from: owner});
+
+ // Try to nest one token in another as a non-owner account
+ await expect(contract.methods
+ .transfer(targetTokenAddress, tokenId)
+ .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malignant = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);
+
+ await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
+
+ // Create a token in one collection
+ const nftTokenIdA = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ nftTokenIdA,
+ ).send({from: owner});
+ const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
+
+ // Create a token in another collection belonging to someone else
+ const nftTokenIdB = await contractB.methods.nextTokenId().call();
+ await contractB.methods.mint(
+ malignant,
+ nftTokenIdB,
+ ).send({from: owner});
+
+ // Try to drag someone else's token into the other collection and nest
+ await expect(contractB.methods
+ .transfer(nftTokenAddressA, nftTokenIdB)
+ .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {contract: contractB} = await createNestingCollection(helper, owner);
+
+ await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});
+
+ // Create a token in one collection
+ const nftTokenIdA = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ nftTokenIdA,
+ ).send({from: owner});
+ const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
+
+ // Create a token in another collection
+ const nftTokenIdB = await contractB.methods.nextTokenId().call();
+ await contractB.methods.mint(
+ owner,
+ nftTokenIdB,
+ ).send({from: owner});
+
+ // Try to nest into a token in the other collection, disallowed in the first
+ await expect(contractB.methods
+ .transfer(nftTokenAddressA, nftTokenIdB)
+ .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
+ });
});
});
tests/src/eth/payable.test.tsdiffbeforeafterboth--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -14,97 +14,91 @@
// 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 {expect} from 'chai';
-import {submitTransactionAsync} from '../substrate/substrate-api';
-import {createEthAccountWithBalance, deployCollector, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';
-import {evmToAddress} from '@polkadot/util-crypto';
-import {getGenericResult, UNIQUE} from '../util/helpers';
-import {getBalanceSingle, transferBalanceExpectSuccess} from '../substrate/get-balance';
+import {IKeyringPair} from '@polkadot/types/types';
+
+import {itEth, expect, usingEthPlaygrounds} from './util/playgrounds';
describe('EVM payable contracts', () => {
- itWeb3('Evm contract can receive wei from eth account', async ({api, web3, privateKeyWrapper}) => {
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
+ let donor: IKeyringPair;
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', ...GAS_ARGS});
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = privateKey('//Alice');
+ });
+ });
+
+ itEth('Evm contract can receive wei from eth account', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+
+ const web3 = helper.getWeb3();
+
+ await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', gas: helper.eth.DEFAULT_GAS});
expect(await contract.methods.getCollected().call()).to.be.equal('10000');
});
- itWeb3('Evm contract can receive wei from substrate account', async ({api, web3, privateKeyWrapper}) => {
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
- const alice = privateKeyWrapper('//Alice');
+ itEth('Evm contract can receive wei from substrate account', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+
+ const weiCount = '10000';
// Transaction fee/value will be payed from subToEth(sender) evm balance,
// which is backed by evmToAddress(subToEth(sender)) substrate balance
- await transferBalanceToEth(api, alice, subToEth(alice.address));
+ await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address), 5n);
+
- {
- const tx = api.tx.evm.call(
- subToEth(alice.address),
- contract.options.address,
- contract.methods.giveMoney().encodeABI(),
- '10000',
- GAS_ARGS.gas,
- await web3.eth.getGasPrice(),
- null,
- null,
- [],
- );
- const events = await submitTransactionAsync(alice, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
- }
+ await helper.eth.callEVM(alice, contract.options.address, contract.methods.giveMoney().encodeABI(), weiCount);
- expect(await contract.methods.getCollected().call()).to.be.equal('10000');
+ expect(await contract.methods.getCollected().call()).to.be.equal(weiCount);
});
// We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible
- itWeb3('Wei sent directly to backing storage of evm contract balance is unaccounted', async({api, web3, privateKeyWrapper}) => {
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
- const alice = privateKeyWrapper('//Alice');
+ itEth('Wei sent directly to backing storage of evm contract balance is unaccounted', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+
+ const weiCount = 10_000n;
- await transferBalanceExpectSuccess(api, alice, evmToAddress(contract.options.address), '10000');
+ await helper.eth.transferBalanceFromSubstrate(alice, contract.options.address, weiCount, false);
- expect(await contract.methods.getUnaccounted().call()).to.be.equal('10000');
+ expect(await contract.methods.getUnaccounted().call()).to.be.equal(weiCount.toString());
});
- itWeb3('Balance can be retrieved from evm contract', async({api, web3, privateKeyWrapper}) => {
- const FEE_BALANCE = 1000n * UNIQUE;
- const CONTRACT_BALANCE = 1n * UNIQUE;
+ itEth('Balance can be retrieved from evm contract', async({helper, privateKey}) => {
+ const FEE_BALANCE = 10n * helper.balance.getOneTokenNominal();
+ const CONTRACT_BALANCE = 1n * helper.balance.getOneTokenNominal();
+
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([20n], donor);
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
- const alice = privateKeyWrapper('//Alice');
+ const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), ...GAS_ARGS});
+ await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
- const receiver = privateKeyWrapper(`//Receiver${Date.now()}`);
+ const receiver = privateKey(`//Receiver${Date.now()}`);
// First receive balance on eth balance of bob
{
- const ethReceiver = subToEth(receiver.address);
+ const ethReceiver = helper.address.substrateToEth(receiver.address);
expect(await web3.eth.getBalance(ethReceiver)).to.be.equal('0');
await contract.methods.withdraw(ethReceiver).send({from: deployer});
expect(await web3.eth.getBalance(ethReceiver)).to.be.equal(CONTRACT_BALANCE.toString());
}
// Some balance is required to pay fee for evm.withdraw call
- await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString());
+ await helper.balance.transferToSubstrate(alice, receiver.address, FEE_BALANCE);
+ // await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString());
// Withdraw balance from eth to substrate
{
- const initialReceiverBalance = await getBalanceSingle(api, receiver.address);
- const tx = api.tx.evm.withdraw(
- subToEth(receiver.address),
- CONTRACT_BALANCE.toString(),
- );
- const events = await submitTransactionAsync(receiver, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
- const finalReceiverBalance = await getBalanceSingle(api, receiver.address);
+ const initialReceiverBalance = await helper.balance.getSubstrate(receiver.address);
+ await helper.executeExtrinsic(receiver, 'api.tx.evm.withdraw', [helper.address.substrateToEth(receiver.address), CONTRACT_BALANCE.toString()], true);
+ const finalReceiverBalance = await helper.balance.getSubstrate(receiver.address);
expect(finalReceiverBalance > initialReceiverBalance).to.be.true;
}
tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -15,7 +15,7 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
-import {collectionIdFromAddress, collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createNonfungibleCollection, createRefungibleCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueNFT, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRefungibleCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
tests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth--- a/tests/src/eth/util/contractHelpersAbi.json
+++ b/tests/src/eth/util/contractHelpersAbi.json
@@ -1,5 +1,56 @@
[
{
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "ContractSponsorRemoved",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "sponsor",
+ "type": "address"
+ }
+ ],
+ "name": "ContractSponsorSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "contractAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "sponsor",
+ "type": "address"
+ }
+ ],
+ "name": "ContractSponsorshipConfirmed",
+ "type": "event"
+ },
+ {
"inputs": [
{
"internalType": "address",
tests/src/eth/util/playgrounds/index.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/util/playgrounds/index.ts
@@ -0,0 +1,49 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import {IKeyringPair} from '@polkadot/types/types';
+
+import config from '../../../config';
+
+import {EthUniqueHelper} from './unique.dev';
+import {SilentLogger, SilentConsole} from '../../../util/playgrounds/unique.dev';
+
+export {EthUniqueHelper} from './unique.dev';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chai.use(chaiAsPromised);
+export const expect = chai.expect;
+
+export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>) => {
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
+
+ const helper = new EthUniqueHelper(new SilentLogger());
+
+ try {
+ await helper.connect(config.substrateUrl);
+ await helper.connectWeb3(config.substrateUrl);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const privateKey = (seed: string) => helper.util.fromSeed(seed, ss58Format);
+ await code(helper, privateKey);
+ }
+ finally {
+ await helper.disconnect();
+ await helper.disconnectWeb3();
+ silentConsole.disable();
+ }
+};
+
+export async function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) {
+ let i: any = it;
+ if (opts.only) i = i.only;
+ else if (opts.skip) i = i.skip;
+ i(name, async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ await cb({helper, privateKey});
+ });
+ });
+}
+itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itEth(name, cb, {only: true});
+itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itEth(name, cb, {skip: true});
\ No newline at end of file
tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/util/playgrounds/types.ts
@@ -0,0 +1,9 @@
+export interface ContractImports {
+ solPath: string;
+ fsPath: string;
+}
+
+export interface CompiledContract {
+ abi: any;
+ object: string;
+}
\ No newline at end of file
tests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -0,0 +1,268 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+/* eslint-disable function-call-argument-newline */
+
+import {readFile} from 'fs/promises';
+
+import Web3 from 'web3';
+import {WebsocketProvider} from 'web3-core';
+import {Contract} from 'web3-eth-contract';
+
+import * as solc from 'solc';
+
+import {evmToAddress} from '@polkadot/util-crypto';
+import {IKeyringPair} from '@polkadot/types/types';
+
+import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
+
+import {ContractImports, CompiledContract} from './types';
+
+// Native contracts ABI
+import collectionHelpersAbi from '../../collectionHelpersAbi.json';
+import fungibleAbi from '../../fungibleAbi.json';
+import nonFungibleAbi from '../../nonFungibleAbi.json';
+import refungibleAbi from '../../reFungibleAbi.json';
+import refungibleTokenAbi from '../../reFungibleTokenAbi.json';
+import contractHelpersAbi from './../contractHelpersAbi.json';
+
+class EthGroupBase {
+ helper: EthUniqueHelper;
+
+ constructor(helper: EthUniqueHelper) {
+ this.helper = helper;
+ }
+}
+
+
+class ContractGroup extends EthGroupBase {
+ async findImports(imports?: ContractImports[]){
+ if(!imports) return function(path: string) {
+ return {error: `File not found: ${path}`};
+ };
+
+ const knownImports = {} as any;
+ for(const imp of imports) {
+ knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
+ }
+
+ return function(path: string) {
+ if(knownImports.hasOwnPropertyDescriptor(path)) return {contents: knownImports[path]};
+ return {error: `File not found: ${path}`};
+ };
+ }
+
+ async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {
+ const out = JSON.parse(solc.compile(JSON.stringify({
+ language: 'Solidity',
+ sources: {
+ [`${name}.sol`]: {
+ content: src,
+ },
+ },
+ settings: {
+ outputSelection: {
+ '*': {
+ '*': ['*'],
+ },
+ },
+ },
+ }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name];
+
+ return {
+ abi: out.abi,
+ object: '0x' + out.evm.bytecode.object,
+ };
+ }
+
+ async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[]): Promise<Contract> {
+ const compiledContract = await this.compile(name, src, imports);
+ return this.deployByAbi(signer, compiledContract.abi, compiledContract.object);
+ }
+
+ async deployByAbi(signer: string, abi: any, object: string): Promise<Contract> {
+ const web3 = this.helper.getWeb3();
+ const contract = new web3.eth.Contract(abi, undefined, {
+ data: object,
+ from: signer,
+ gas: this.helper.eth.DEFAULT_GAS,
+ });
+ return await contract.deploy({data: object}).send({from: signer});
+ }
+
+}
+
+class NativeContractGroup extends EthGroupBase {
+
+ contractHelpers(caller: string): Contract {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, gas: this.helper.eth.DEFAULT_GAS});
+ }
+
+ collectionHelpers(caller: string) {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS});
+ }
+
+ collection(address: string, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract {
+ const abi = {
+ 'nft': nonFungibleAbi,
+ 'rft': refungibleAbi,
+ 'ft': fungibleAbi,
+ }[mode];
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
+ }
+
+ rftTokenByAddress(address: string, caller?: string): Contract {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
+ }
+
+ rftToken(collectionId: number, tokenId: number, caller?: string): Contract {
+ return this.rftTokenByAddress(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller);
+ }
+}
+
+
+class EthGroup extends EthGroupBase {
+ DEFAULT_GAS = 2_500_000;
+
+ createAccount() {
+ const web3 = this.helper.getWeb3();
+ const account = web3.eth.accounts.create();
+ web3.eth.accounts.wallet.add(account.privateKey);
+ return account.address;
+ }
+
+ async createAccountWithBalance(donor: IKeyringPair, amount=1000n) {
+ const account = this.createAccount();
+ await this.transferBalanceFromSubstrate(donor, account, amount);
+
+ return account;
+ }
+
+ async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount=1000n, inTokens=true) {
+ return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
+ }
+
+ async callEVM(signer: IKeyringPair, contractAddress: string, abi: any, value: string, gasLimit?: number) {
+ if(!gasLimit) gasLimit = this.DEFAULT_GAS;
+ const web3 = this.helper.getWeb3();
+ const gasPrice = await web3.eth.getGasPrice();
+ // TODO: check execution status
+ await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []],
+ true,
+ );
+ }
+
+ async createNonfungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {
+ const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
+
+ const result = await collectionHelper.methods.createNonfungibleCollection(name, description, tokenPrefix).send();
+
+ const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+ const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+
+ return {collectionId, collectionAddress};
+ }
+
+ async deployCollectorContract(signer: string): Promise<Contract> {
+ return await this.helper.ethContract.deployByCode(signer, 'Collector', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract Collector {
+ uint256 collected;
+ fallback() external payable {
+ giveMoney();
+ }
+ function giveMoney() public payable {
+ collected += msg.value;
+ }
+ function getCollected() public view returns (uint256) {
+ return collected;
+ }
+ function getUnaccounted() public view returns (uint256) {
+ return address(this).balance - collected;
+ }
+
+ function withdraw(address payable target) public {
+ target.transfer(collected);
+ collected = 0;
+ }
+ }
+ `);
+ }
+}
+
+
+class EthAddressGroup extends EthGroupBase {
+ extractCollectionId(address: string): number {
+ if (!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
+ return parseInt(address.substr(address.length - 8), 16);
+ }
+
+ fromCollectionId(collectionId: number): string {
+ if (collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow');
+ return Web3.utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`);
+ }
+
+ extractTokenId(address: string): {collectionId: number, tokenId: number} {
+ if (!address.startsWith('0x'))
+ throw 'address not starts with "0x"';
+ if (address.length > 42)
+ throw 'address length is more than 20 bytes';
+ return {
+ collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
+ tokenId: Number('0x' + address.substring(address.length - 8)),
+ };
+ }
+
+ fromTokenId(collectionId: number, tokenId: number): string {
+ return this.helper.util.getNestingTokenAddress(collectionId, tokenId);
+ }
+
+ normalizeAddress(address: string): string {
+ return '0x' + address.substring(address.length - 40);
+ }
+}
+
+
+export class EthUniqueHelper extends DevUniqueHelper {
+ web3: Web3 | null = null;
+ web3Provider: WebsocketProvider | null = null;
+
+ eth: EthGroup;
+ ethAddress: EthAddressGroup;
+ ethNativeContract: NativeContractGroup;
+ ethContract: ContractGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }) {
+ super(logger);
+ this.eth = new EthGroup(this);
+ this.ethAddress = new EthAddressGroup(this);
+ this.ethNativeContract = new NativeContractGroup(this);
+ this.ethContract = new ContractGroup(this);
+ }
+
+ getWeb3(): Web3 {
+ if(this.web3 === null) throw Error('Web3 not connected');
+ return this.web3;
+ }
+
+ async connectWeb3(wsEndpoint: string) {
+ if(this.web3 !== null) return;
+ this.web3Provider = new Web3.providers.WebsocketProvider(wsEndpoint);
+ this.web3 = new Web3(this.web3Provider);
+ }
+
+ async disconnectWeb3() {
+ if(this.web3 === null) return;
+ this.web3Provider?.connection.close();
+ this.web3 = null;
+ }
+}
+
\ No newline at end of file
tests/src/interfaces/appPromotion/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/interfaces/appPromotion/definitions.ts
@@ -0,0 +1,58 @@
+// 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/>.
+
+type RpcParam = {
+ name: string;
+ type: string;
+ isOptional?: true;
+};
+
+const CROSS_ACCOUNT_ID_TYPE = 'PalletEvmAccountBasicCrossAccountIdRepr';
+
+const crossAccountParam = (name = 'account') => ({name, type: CROSS_ACCOUNT_ID_TYPE});
+const atParam = {name: 'at', type: 'Hash', isOptional: true};
+
+const fun = (description: string, params: RpcParam[], type: string) => ({
+ description,
+ params: [...params, atParam],
+ type,
+});
+
+export default {
+ types: {},
+ rpc: {
+ totalStaked: fun(
+ 'Returns the total amount of staked tokens',
+ [{name: 'staker', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
+ 'u128',
+ ),
+ totalStakedPerBlock: fun(
+ 'Returns the total amount of staked tokens per block when staked',
+ [crossAccountParam('staker')],
+ 'Vec<(u32, u128)>',
+ ),
+ pendingUnstake: fun(
+ 'Returns the total amount of unstaked tokens',
+ [{name: 'staker', type: CROSS_ACCOUNT_ID_TYPE, isOptional: true}],
+ 'u128',
+ ),
+ pendingUnstakePerBlock: fun(
+ 'Returns the total amount of unstaked tokens per block',
+ [crossAccountParam('staker')],
+ 'Vec<(u32, u128)>',
+ ),
+ },
+};
tests/src/interfaces/appPromotion/index.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/interfaces/appPromotion/index.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export * from './types';
tests/src/interfaces/appPromotion/types.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/interfaces/appPromotion/types.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export type PHANTOM_APPPROMOTION = 'appPromotion';
tests/src/interfaces/augment-api-consts.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-consts.ts
+++ b/tests/src/interfaces/augment-api-consts.ts
@@ -8,13 +8,39 @@
import type { ApiTypes, AugmentedConst } from '@polkadot/api-base/types';
import type { Option, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
import type { Codec } from '@polkadot/types-codec/types';
-import type { Permill } from '@polkadot/types/interfaces/runtime';
+import type { Perbill, Permill } from '@polkadot/types/interfaces/runtime';
import type { FrameSupportPalletId, FrameSupportWeightsRuntimeDbWeight, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, SpVersionRuntimeVersion } from '@polkadot/types/lookup';
export type __AugmentedConst<ApiType extends ApiTypes> = AugmentedConst<ApiType>;
declare module '@polkadot/api-base/types/consts' {
interface AugmentedConsts<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * Rate of return for interval in blocks defined in `RecalculationInterval`.
+ **/
+ intervalIncome: Perbill & AugmentedConst<ApiType>;
+ /**
+ * Decimals for the `Currency`.
+ **/
+ nominal: u128 & AugmentedConst<ApiType>;
+ /**
+ * The app's pallet id, used for deriving its sovereign account ID.
+ **/
+ palletId: FrameSupportPalletId & AugmentedConst<ApiType>;
+ /**
+ * In parachain blocks.
+ **/
+ pendingInterval: u32 & AugmentedConst<ApiType>;
+ /**
+ * In relay blocks.
+ **/
+ recalculationInterval: u32 & AugmentedConst<ApiType>;
+ /**
+ * Generic const
+ **/
+ [key: string]: Codec;
+ };
balances: {
/**
* The minimum amount required to keep an account open.
tests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -11,6 +11,36 @@
declare module '@polkadot/api-base/types/errors' {
interface AugmentedErrors<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * Error due to action requiring admin to be set.
+ **/
+ AdminNotSet: AugmentedError<ApiType>;
+ /**
+ * Errors caused by incorrect actions with a locked balance.
+ **/
+ IncorrectLockedBalanceOperation: AugmentedError<ApiType>;
+ /**
+ * No permission to perform an action.
+ **/
+ NoPermission: AugmentedError<ApiType>;
+ /**
+ * Insufficient funds to perform an action.
+ **/
+ NotSufficientFunds: AugmentedError<ApiType>;
+ /**
+ * Occurs when a pending unstake cannot be added in this block. PENDING_LIMIT_PER_BLOCK` limits exceeded.
+ **/
+ PendingForBlockOverflow: AugmentedError<ApiType>;
+ /**
+ * The error is due to the fact that the collection/contract must already be sponsored in order to perform the action.
+ **/
+ SponsorNotSet: AugmentedError<ApiType>;
+ /**
+ * Generic error
+ **/
+ [key: string]: AugmentedError<ApiType>;
+ };
balances: {
/**
* Beneficiary account must pre-exist
@@ -265,8 +295,12 @@
};
evmContractHelpers: {
/**
- * This method is only executable by owner
+ * No pending sponsor for contract.
**/
+ NoPendingSponsor: AugmentedError<ApiType>;
+ /**
+ * This method is only executable by contract owner
+ **/
NoPermission: AugmentedError<ApiType>;
/**
* Generic error
@@ -274,7 +308,13 @@
[key: string]: AugmentedError<ApiType>;
};
evmMigration: {
+ /**
+ * Migration of this account is not yet started, or already finished.
+ **/
AccountIsNotMigrating: AugmentedError<ApiType>;
+ /**
+ * Can only migrate to empty address.
+ **/
AccountNotEmpty: AugmentedError<ApiType>;
/**
* Generic error
tests/src/interfaces/augment-api-events.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -15,6 +15,44 @@
declare module '@polkadot/api-base/types/events' {
interface AugmentedEvents<ApiType extends ApiTypes> {
+ appPromotion: {
+ /**
+ * The admin was set
+ *
+ * # Arguments
+ * * AccountId: ID of the admin
+ **/
+ SetAdmin: AugmentedEvent<ApiType, [AccountId32]>;
+ /**
+ * Staking was performed
+ *
+ * # Arguments
+ * * AccountId: ID of the staker
+ * * Balance : staking amount
+ **/
+ Stake: AugmentedEvent<ApiType, [AccountId32, u128]>;
+ /**
+ * Staking recalculation was performed
+ *
+ * # Arguments
+ * * AccountId: ID of the staker.
+ * * Balance : recalculation base
+ * * Balance : total income
+ **/
+ StakingRecalculation: AugmentedEvent<ApiType, [AccountId32, u128, u128]>;
+ /**
+ * Unstaking was performed
+ *
+ * # Arguments
+ * * AccountId: ID of the staker
+ * * Balance : unstaking amount
+ **/
+ Unstake: AugmentedEvent<ApiType, [AccountId32, u128]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
balances: {
/**
* A balance was set by root.
@@ -208,6 +246,24 @@
**/
[key: string]: AugmentedEvent<ApiType>;
};
+ evmContractHelpers: {
+ /**
+ * Collection sponsor was removed.
+ **/
+ ContractSponsorRemoved: AugmentedEvent<ApiType, [H160]>;
+ /**
+ * Contract sponsor was set.
+ **/
+ ContractSponsorSet: AugmentedEvent<ApiType, [H160, AccountId32]>;
+ /**
+ * New sponsor was confirm.
+ **/
+ ContractSponsorshipConfirmed: AugmentedEvent<ApiType, [H160, AccountId32]>;
+ /**
+ * Generic event
+ **/
+ [key: string]: AugmentedEvent<ApiType>;
+ };
parachainSystem: {
/**
* Downward messages were processed using the given weight.
tests/src/interfaces/augment-api-query.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -6,10 +6,10 @@
import '@polkadot/api-base/types/storage';
import type { ApiTypes, AugmentedQuery, QueryableStorageEntry } from '@polkadot/api-base/types';
-import type { BTreeMap, Bytes, Option, U256, U8aFixed, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types-codec';
+import type { BTreeMap, Bytes, Option, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PalletUniqueSchedulerScheduledV3, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsTokenChild } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PalletUniqueSchedulerScheduledV3, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild } from '@polkadot/types/lookup';
import type { Observable } from '@polkadot/types/types';
export type __AugmentedQuery<ApiType extends ApiTypes> = AugmentedQuery<ApiType, () => unknown>;
@@ -17,6 +17,28 @@
declare module '@polkadot/api-base/types/storage' {
interface AugmentedQueries<ApiType extends ApiTypes> {
+ appPromotion: {
+ admin: AugmentedQuery<ApiType, () => Observable<Option<AccountId32>>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Stores a key for record for which the next revenue recalculation would be performed.
+ * If `None`, then recalculation has not yet been performed or calculations have been completed for all stakers.
+ **/
+ nextCalculatedRecord: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[AccountId32, u32]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ pendingUnstake: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<ITuple<[AccountId32, u128]>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+ /**
+ * Amount of tokens staked by account in the blocknumber.
+ **/
+ staked: AugmentedQuery<ApiType, (arg1: AccountId32 | string | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<ITuple<[u128, u32]>>, [AccountId32, u32]> & QueryableStorageEntry<ApiType, [AccountId32, u32]>;
+ /**
+ * Amount of stakes for an Account
+ **/
+ stakesPerAccount: AugmentedQuery<ApiType, (arg: AccountId32 | string | Uint8Array) => Observable<u8>, [AccountId32]> & QueryableStorageEntry<ApiType, [AccountId32]>;
+ totalStaked: AugmentedQuery<ApiType, () => Observable<u128>, []> & QueryableStorageEntry<ApiType, []>;
+ /**
+ * Generic query
+ **/
+ [key: string]: QueryableStorageEntry<ApiType>;
+ };
balances: {
/**
* The Balances pallet example of storing the balance of an account.
@@ -194,12 +216,66 @@
[key: string]: QueryableStorageEntry<ApiType>;
};
evmContractHelpers: {
+ /**
+ * Storage for users that allowed for sponsorship.
+ *
+ * ### Usage
+ * Prefer to delete record from storage if user no more allowed for sponsorship.
+ *
+ * * **Key1** - contract address.
+ * * **Key2** - user that allowed for sponsorship.
+ * * **Value** - allowance for sponsorship.
+ **/
allowlist: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H160 | string | Uint8Array) => Observable<bool>, [H160, H160]> & QueryableStorageEntry<ApiType, [H160, H160]>;
+ /**
+ * Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.
+ *
+ * ### Usage
+ * Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.
+ *
+ * * **Key** - contract address.
+ * * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.
+ **/
allowlistEnabled: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Store owner for contract.
+ *
+ * * **Key** - contract address.
+ * * **Value** - owner for contract.
+ **/
owner: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<H160>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
selfSponsoring: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<bool>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Storage for last sponsored block.
+ *
+ * * **Key1** - contract address.
+ * * **Key2** - sponsored user address.
+ * * **Value** - last sponsored block number.
+ **/
sponsorBasket: AugmentedQuery<ApiType, (arg1: H160 | string | Uint8Array, arg2: H160 | string | Uint8Array) => Observable<Option<u32>>, [H160, H160]> & QueryableStorageEntry<ApiType, [H160, H160]>;
+ /**
+ * Store for contract sponsorship state.
+ *
+ * * **Key** - contract address.
+ * * **Value** - sponsorship state.
+ **/
+ sponsoring: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<UpDataStructsSponsorshipStateBasicCrossAccountIdRepr>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Store for sponsoring mode.
+ *
+ * ### Usage
+ * Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).
+ *
+ * * **Key** - contract address.
+ * * **Value** - [`sponsoring mode`](SponsoringModeT).
+ **/
sponsoringMode: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<Option<PalletEvmContractHelpersSponsoringModeT>>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
+ /**
+ * Storage for sponsoring rate limit in blocks.
+ *
+ * * **Key** - contract address.
+ * * **Value** - amount of sponsored blocks.
+ **/
sponsoringRateLimit: AugmentedQuery<ApiType, (arg: H160 | string | Uint8Array) => Observable<u32>, [H160]> & QueryableStorageEntry<ApiType, [H160]>;
/**
* Generic query
@@ -281,7 +357,7 @@
*
* Currently used to store RMRK data.
**/
- tokenAuxProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: UpDataStructsPropertyScope | 'None' | 'Rmrk' | 'Eth' | number | Uint8Array, arg4: Bytes | string | Uint8Array) => Observable<Option<Bytes>>, [u32, u32, UpDataStructsPropertyScope, Bytes]> & QueryableStorageEntry<ApiType, [u32, u32, UpDataStructsPropertyScope, Bytes]>;
+ 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.
**/
tests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -9,7 +9,7 @@
import type { AugmentedRpc } from '@polkadot/rpc-core/types';
import type { Metadata, StorageKey } from '@polkadot/types';
import type { Bytes, HashMap, Json, Null, Option, Text, U256, U64, Vec, bool, f64, u128, u32, u64 } from '@polkadot/types-codec';
-import type { AnyNumber, Codec } from '@polkadot/types-codec/types';
+import type { AnyNumber, Codec, ITuple } from '@polkadot/types-codec/types';
import type { ExtrinsicOrHash, ExtrinsicStatus } from '@polkadot/types/interfaces/author';
import type { EpochAuthorship } from '@polkadot/types/interfaces/babe';
import type { BeefySignedCommitment } from '@polkadot/types/interfaces/beefy';
@@ -35,6 +35,24 @@
declare module '@polkadot/rpc-core/types/jsonrpc' {
interface RpcInterface {
+ appPromotion: {
+ /**
+ * Returns the total amount of unstaked tokens
+ **/
+ pendingUnstake: AugmentedRpc<(staker?: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
+ /**
+ * Returns the total amount of unstaked tokens per block
+ **/
+ pendingUnstakePerBlock: AugmentedRpc<(staker: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<ITuple<[u32, u128]>>>>;
+ /**
+ * Returns the total amount of staked tokens
+ **/
+ totalStaked: AugmentedRpc<(staker?: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
+ /**
+ * Returns the total amount of staked tokens per block when staked
+ **/
+ totalStakedPerBlock: AugmentedRpc<(staker: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<ITuple<[u32, u128]>>>>;
+ };
author: {
/**
* Returns true if the keystore has private keys for the given public key and key type.
tests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -17,6 +17,20 @@
declare module '@polkadot/api-base/types/submittable' {
interface AugmentedSubmittables<ApiType extends ApiTypes> {
+ appPromotion: {
+ payoutStakers: AugmentedSubmittable<(stakersNumber: Option<u8> | null | Uint8Array | u8 | AnyNumber) => SubmittableExtrinsic<ApiType>, [Option<u8>]>;
+ setAdminAddress: AugmentedSubmittable<(admin: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr]>;
+ sponsorCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ sponsorContract: AugmentedSubmittable<(contractId: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
+ stake: AugmentedSubmittable<(amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u128]>;
+ stopSponsoringCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+ stopSponsoringContract: AugmentedSubmittable<(contractId: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
+ unstake: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
+ /**
+ * Generic tx
+ **/
+ [key: string]: SubmittableExtrinsicFunction<ApiType>;
+ };
balances: {
/**
* Exactly as `transfer`, except the origin must be root and the source account may be
@@ -181,8 +195,21 @@
[key: string]: SubmittableExtrinsicFunction<ApiType>;
};
evmMigration: {
+ /**
+ * Start contract migration, inserts contract stub at target address,
+ * and marks account as pending, allowing to insert storage
+ **/
begin: AugmentedSubmittable<(address: H160 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160]>;
+ /**
+ * Finish contract migration, allows it to be called.
+ * It is not possible to alter contract storage via [`Self::set_data`]
+ * after this call.
+ **/
finish: AugmentedSubmittable<(address: H160 | string | Uint8Array, code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160, Bytes]>;
+ /**
+ * Insert items into contract storage, this method can be called
+ * multiple times
+ **/
setData: AugmentedSubmittable<(address: H160 | string | Uint8Array, data: Vec<ITuple<[H256, H256]>> | ([H256 | string | Uint8Array, H256 | string | Uint8Array])[]) => SubmittableExtrinsic<ApiType>, [H160, Vec<ITuple<[H256, H256]>>]>;
/**
* Generic tx
tests/src/interfaces/augment-types.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -5,7 +5,7 @@
// this is required to allow for ambient/previous definitions
import '@polkadot/types/types/registry';
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportScheduleLookupError, FrameSupportScheduleMaybeHashed, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerCall, PalletUniqueSchedulerError, PalletUniqueSchedulerEvent, PalletUniqueSchedulerScheduledV3, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportScheduleLookupError, FrameSupportScheduleMaybeHashed, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerCall, PalletUniqueSchedulerError, PalletUniqueSchedulerEvent, PalletUniqueSchedulerScheduledV3, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
import type { Data, StorageKey } from '@polkadot/types';
import type { BitVec, Bool, Bytes, F32, F64, I128, I16, I256, I32, I64, I8, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, f32, f64, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec';
import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';
@@ -804,6 +804,9 @@
Owner: Owner;
PageCounter: PageCounter;
PageIndexData: PageIndexData;
+ PalletAppPromotionCall: PalletAppPromotionCall;
+ PalletAppPromotionError: PalletAppPromotionError;
+ PalletAppPromotionEvent: PalletAppPromotionEvent;
PalletBalancesAccountData: PalletBalancesAccountData;
PalletBalancesBalanceLock: PalletBalancesBalanceLock;
PalletBalancesCall: PalletBalancesCall;
@@ -832,6 +835,7 @@
PalletEvmCall: PalletEvmCall;
PalletEvmCoderSubstrateError: PalletEvmCoderSubstrateError;
PalletEvmContractHelpersError: PalletEvmContractHelpersError;
+ PalletEvmContractHelpersEvent: PalletEvmContractHelpersEvent;
PalletEvmContractHelpersSponsoringModeT: PalletEvmContractHelpersSponsoringModeT;
PalletEvmError: PalletEvmError;
PalletEvmEvent: PalletEvmEvent;
@@ -1295,7 +1299,8 @@
UpDataStructsPropertyScope: UpDataStructsPropertyScope;
UpDataStructsRpcCollection: UpDataStructsRpcCollection;
UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
- UpDataStructsSponsorshipState: UpDataStructsSponsorshipState;
+ UpDataStructsSponsorshipStateAccountId32: UpDataStructsSponsorshipStateAccountId32;
+ UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: UpDataStructsSponsorshipStateBasicCrossAccountIdRepr;
UpDataStructsTokenChild: UpDataStructsTokenChild;
UpDataStructsTokenData: UpDataStructsTokenData;
UpgradeGoAhead: UpgradeGoAhead;
tests/src/interfaces/default/types.tsdiffbeforeafterboth--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -806,6 +806,64 @@
readonly perPeriod: Compact<u128>;
}
+/** @name PalletAppPromotionCall */
+export interface PalletAppPromotionCall extends Enum {
+ readonly isSetAdminAddress: boolean;
+ readonly asSetAdminAddress: {
+ readonly admin: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isStake: boolean;
+ readonly asStake: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnstake: boolean;
+ readonly isSponsorCollection: boolean;
+ readonly asSponsorCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isStopSponsoringCollection: boolean;
+ readonly asStopSponsoringCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isSponsorContract: boolean;
+ readonly asSponsorContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isStopSponsoringContract: boolean;
+ readonly asStopSponsoringContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isPayoutStakers: boolean;
+ readonly asPayoutStakers: {
+ readonly stakersNumber: Option<u8>;
+ } & Struct;
+ readonly type: 'SetAdminAddress' | 'Stake' | 'Unstake' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers';
+}
+
+/** @name PalletAppPromotionError */
+export interface PalletAppPromotionError extends Enum {
+ readonly isAdminNotSet: boolean;
+ readonly isNoPermission: boolean;
+ readonly isNotSufficientFunds: boolean;
+ readonly isPendingForBlockOverflow: boolean;
+ readonly isSponsorNotSet: boolean;
+ readonly isIncorrectLockedBalanceOperation: boolean;
+ readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'IncorrectLockedBalanceOperation';
+}
+
+/** @name PalletAppPromotionEvent */
+export interface PalletAppPromotionEvent extends Enum {
+ readonly isStakingRecalculation: boolean;
+ readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
+ readonly isStake: boolean;
+ readonly asStake: ITuple<[AccountId32, u128]>;
+ readonly isUnstake: boolean;
+ readonly asUnstake: ITuple<[AccountId32, u128]>;
+ readonly isSetAdmin: boolean;
+ readonly asSetAdmin: AccountId32;
+ readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
+}
+
/** @name PalletBalancesAccountData */
export interface PalletBalancesAccountData extends Struct {
readonly free: u128;
@@ -1127,7 +1185,19 @@
/** @name PalletEvmContractHelpersError */
export interface PalletEvmContractHelpersError extends Enum {
readonly isNoPermission: boolean;
- readonly type: 'NoPermission';
+ readonly isNoPendingSponsor: boolean;
+ readonly type: 'NoPermission' | 'NoPendingSponsor';
+}
+
+/** @name PalletEvmContractHelpersEvent */
+export interface PalletEvmContractHelpersEvent extends Enum {
+ readonly isContractSponsorSet: boolean;
+ readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorshipConfirmed: boolean;
+ readonly asContractSponsorshipConfirmed: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorRemoved: boolean;
+ readonly asContractSponsorRemoved: H160;
+ readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
}
/** @name PalletEvmContractHelpersSponsoringModeT */
@@ -2419,7 +2489,7 @@
readonly name: Vec<u16>;
readonly description: Vec<u16>;
readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipState;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
readonly limits: UpDataStructsCollectionLimits;
readonly permissions: UpDataStructsCollectionPermissions;
readonly externalCollection: bool;
@@ -2580,8 +2650,7 @@
export interface UpDataStructsPropertyScope extends Enum {
readonly isNone: boolean;
readonly isRmrk: boolean;
- readonly isEth: boolean;
- readonly type: 'None' | 'Rmrk' | 'Eth';
+ readonly type: 'None' | 'Rmrk';
}
/** @name UpDataStructsRpcCollection */
@@ -2591,7 +2660,7 @@
readonly name: Vec<u16>;
readonly description: Vec<u16>;
readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipState;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
readonly limits: UpDataStructsCollectionLimits;
readonly permissions: UpDataStructsCollectionPermissions;
readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
@@ -2607,8 +2676,8 @@
readonly type: 'SponsoringDisabled' | 'Blocks';
}
-/** @name UpDataStructsSponsorshipState */
-export interface UpDataStructsSponsorshipState extends Enum {
+/** @name UpDataStructsSponsorshipStateAccountId32 */
+export interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
readonly isDisabled: boolean;
readonly isUnconfirmed: boolean;
readonly asUnconfirmed: AccountId32;
@@ -2617,6 +2686,16 @@
readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
}
+/** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr */
+export interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
+ readonly isDisabled: boolean;
+ readonly isUnconfirmed: boolean;
+ readonly asUnconfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
+}
+
/** @name UpDataStructsTokenChild */
export interface UpDataStructsTokenChild extends Struct {
readonly token: u32;
tests/src/interfaces/definitions.tsdiffbeforeafterboth--- a/tests/src/interfaces/definitions.ts
+++ b/tests/src/interfaces/definitions.ts
@@ -15,5 +15,6 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
export {default as unique} from './unique/definitions';
+export {default as appPromotion} from './appPromotion/definitions';
export {default as rmrk} from './rmrk/definitions';
export {default as default} from './default/definitions';
\ No newline at end of file
tests/src/interfaces/lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1057,7 +1057,18 @@
}
},
/**
- * Lookup103: pallet_evm::pallet::Event<T>
+ * Lookup103: pallet_app_promotion::pallet::Event<T>
+ **/
+ PalletAppPromotionEvent: {
+ _enum: {
+ StakingRecalculation: '(AccountId32,u128,u128)',
+ Stake: '(AccountId32,u128)',
+ Unstake: '(AccountId32,u128)',
+ SetAdmin: 'AccountId32'
+ }
+ },
+ /**
+ * Lookup104: pallet_evm::pallet::Event<T>
**/
PalletEvmEvent: {
_enum: {
@@ -1071,7 +1082,7 @@
}
},
/**
- * Lookup104: ethereum::log::Log
+ * Lookup105: ethereum::log::Log
**/
EthereumLog: {
address: 'H160',
@@ -1079,7 +1090,7 @@
data: 'Bytes'
},
/**
- * Lookup108: pallet_ethereum::pallet::Event
+ * Lookup109: pallet_ethereum::pallet::Event
**/
PalletEthereumEvent: {
_enum: {
@@ -1087,7 +1098,7 @@
}
},
/**
- * Lookup109: evm_core::error::ExitReason
+ * Lookup110: evm_core::error::ExitReason
**/
EvmCoreErrorExitReason: {
_enum: {
@@ -1098,13 +1109,13 @@
}
},
/**
- * Lookup110: evm_core::error::ExitSucceed
+ * Lookup111: evm_core::error::ExitSucceed
**/
EvmCoreErrorExitSucceed: {
_enum: ['Stopped', 'Returned', 'Suicided']
},
/**
- * Lookup111: evm_core::error::ExitError
+ * Lookup112: evm_core::error::ExitError
**/
EvmCoreErrorExitError: {
_enum: {
@@ -1126,13 +1137,13 @@
}
},
/**
- * Lookup114: evm_core::error::ExitRevert
+ * Lookup115: evm_core::error::ExitRevert
**/
EvmCoreErrorExitRevert: {
_enum: ['Reverted']
},
/**
- * Lookup115: evm_core::error::ExitFatal
+ * Lookup116: evm_core::error::ExitFatal
**/
EvmCoreErrorExitFatal: {
_enum: {
@@ -1143,7 +1154,17 @@
}
},
/**
- * Lookup116: frame_system::Phase
+ * Lookup117: pallet_evm_contract_helpers::pallet::Event<T>
+ **/
+ PalletEvmContractHelpersEvent: {
+ _enum: {
+ ContractSponsorSet: '(H160,AccountId32)',
+ ContractSponsorshipConfirmed: '(H160,AccountId32)',
+ ContractSponsorRemoved: 'H160'
+ }
+ },
+ /**
+ * Lookup118: frame_system::Phase
**/
FrameSystemPhase: {
_enum: {
@@ -1153,14 +1174,14 @@
}
},
/**
- * Lookup118: frame_system::LastRuntimeUpgradeInfo
+ * Lookup120: frame_system::LastRuntimeUpgradeInfo
**/
FrameSystemLastRuntimeUpgradeInfo: {
specVersion: 'Compact<u32>',
specName: 'Text'
},
/**
- * Lookup119: frame_system::pallet::Call<T>
+ * Lookup121: frame_system::pallet::Call<T>
**/
FrameSystemCall: {
_enum: {
@@ -1198,7 +1219,7 @@
}
},
/**
- * Lookup124: frame_system::limits::BlockWeights
+ * Lookup126: frame_system::limits::BlockWeights
**/
FrameSystemLimitsBlockWeights: {
baseBlock: 'u64',
@@ -1206,7 +1227,7 @@
perClass: 'FrameSupportWeightsPerDispatchClassWeightsPerClass'
},
/**
- * Lookup125: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>
+ * Lookup127: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>
**/
FrameSupportWeightsPerDispatchClassWeightsPerClass: {
normal: 'FrameSystemLimitsWeightsPerClass',
@@ -1214,7 +1235,7 @@
mandatory: 'FrameSystemLimitsWeightsPerClass'
},
/**
- * Lookup126: frame_system::limits::WeightsPerClass
+ * Lookup128: frame_system::limits::WeightsPerClass
**/
FrameSystemLimitsWeightsPerClass: {
baseExtrinsic: 'u64',
@@ -1223,13 +1244,13 @@
reserved: 'Option<u64>'
},
/**
- * Lookup128: frame_system::limits::BlockLength
+ * Lookup130: frame_system::limits::BlockLength
**/
FrameSystemLimitsBlockLength: {
max: 'FrameSupportWeightsPerDispatchClassU32'
},
/**
- * Lookup129: frame_support::weights::PerDispatchClass<T>
+ * Lookup131: frame_support::weights::PerDispatchClass<T>
**/
FrameSupportWeightsPerDispatchClassU32: {
normal: 'u32',
@@ -1237,14 +1258,14 @@
mandatory: 'u32'
},
/**
- * Lookup130: frame_support::weights::RuntimeDbWeight
+ * Lookup132: frame_support::weights::RuntimeDbWeight
**/
FrameSupportWeightsRuntimeDbWeight: {
read: 'u64',
write: 'u64'
},
/**
- * Lookup131: sp_version::RuntimeVersion
+ * Lookup133: sp_version::RuntimeVersion
**/
SpVersionRuntimeVersion: {
specName: 'Text',
@@ -1257,13 +1278,13 @@
stateVersion: 'u8'
},
/**
- * Lookup136: frame_system::pallet::Error<T>
+ * Lookup138: frame_system::pallet::Error<T>
**/
FrameSystemError: {
_enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
},
/**
- * Lookup137: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>
+ * Lookup139: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>
**/
PolkadotPrimitivesV2PersistedValidationData: {
parentHead: 'Bytes',
@@ -1272,19 +1293,19 @@
maxPovSize: 'u32'
},
/**
- * Lookup140: polkadot_primitives::v2::UpgradeRestriction
+ * Lookup142: polkadot_primitives::v2::UpgradeRestriction
**/
PolkadotPrimitivesV2UpgradeRestriction: {
_enum: ['Present']
},
/**
- * Lookup141: sp_trie::storage_proof::StorageProof
+ * Lookup143: sp_trie::storage_proof::StorageProof
**/
SpTrieStorageProof: {
trieNodes: 'BTreeSet<Bytes>'
},
/**
- * Lookup143: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
+ * Lookup145: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
**/
CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {
dmqMqcHead: 'H256',
@@ -1293,7 +1314,7 @@
egressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>'
},
/**
- * Lookup146: polkadot_primitives::v2::AbridgedHrmpChannel
+ * Lookup148: polkadot_primitives::v2::AbridgedHrmpChannel
**/
PolkadotPrimitivesV2AbridgedHrmpChannel: {
maxCapacity: 'u32',
@@ -1304,7 +1325,7 @@
mqcHead: 'Option<H256>'
},
/**
- * Lookup147: polkadot_primitives::v2::AbridgedHostConfiguration
+ * Lookup149: polkadot_primitives::v2::AbridgedHostConfiguration
**/
PolkadotPrimitivesV2AbridgedHostConfiguration: {
maxCodeSize: 'u32',
@@ -1318,14 +1339,14 @@
validationUpgradeDelay: 'u32'
},
/**
- * Lookup153: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>
+ * Lookup155: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>
**/
PolkadotCorePrimitivesOutboundHrmpMessage: {
recipient: 'u32',
data: 'Bytes'
},
/**
- * Lookup154: cumulus_pallet_parachain_system::pallet::Call<T>
+ * Lookup156: cumulus_pallet_parachain_system::pallet::Call<T>
**/
CumulusPalletParachainSystemCall: {
_enum: {
@@ -1344,7 +1365,7 @@
}
},
/**
- * Lookup155: cumulus_primitives_parachain_inherent::ParachainInherentData
+ * Lookup157: cumulus_primitives_parachain_inherent::ParachainInherentData
**/
CumulusPrimitivesParachainInherentParachainInherentData: {
validationData: 'PolkadotPrimitivesV2PersistedValidationData',
@@ -1353,27 +1374,27 @@
horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'
},
/**
- * Lookup157: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
+ * Lookup159: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
**/
PolkadotCorePrimitivesInboundDownwardMessage: {
sentAt: 'u32',
msg: 'Bytes'
},
/**
- * Lookup160: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
+ * Lookup162: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
**/
PolkadotCorePrimitivesInboundHrmpMessage: {
sentAt: 'u32',
data: 'Bytes'
},
/**
- * Lookup163: cumulus_pallet_parachain_system::pallet::Error<T>
+ * Lookup165: cumulus_pallet_parachain_system::pallet::Error<T>
**/
CumulusPalletParachainSystemError: {
_enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']
},
/**
- * Lookup165: pallet_balances::BalanceLock<Balance>
+ * Lookup167: pallet_balances::BalanceLock<Balance>
**/
PalletBalancesBalanceLock: {
id: '[u8;8]',
@@ -1381,26 +1402,26 @@
reasons: 'PalletBalancesReasons'
},
/**
- * Lookup166: pallet_balances::Reasons
+ * Lookup168: pallet_balances::Reasons
**/
PalletBalancesReasons: {
_enum: ['Fee', 'Misc', 'All']
},
/**
- * Lookup169: pallet_balances::ReserveData<ReserveIdentifier, Balance>
+ * Lookup171: pallet_balances::ReserveData<ReserveIdentifier, Balance>
**/
PalletBalancesReserveData: {
id: '[u8;16]',
amount: 'u128'
},
/**
- * Lookup171: pallet_balances::Releases
+ * Lookup173: pallet_balances::Releases
**/
PalletBalancesReleases: {
_enum: ['V1_0_0', 'V2_0_0']
},
/**
- * Lookup172: pallet_balances::pallet::Call<T, I>
+ * Lookup174: pallet_balances::pallet::Call<T, I>
**/
PalletBalancesCall: {
_enum: {
@@ -1433,13 +1454,13 @@
}
},
/**
- * Lookup175: pallet_balances::pallet::Error<T, I>
+ * Lookup177: pallet_balances::pallet::Error<T, I>
**/
PalletBalancesError: {
_enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'KeepAlive', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves']
},
/**
- * Lookup177: pallet_timestamp::pallet::Call<T>
+ * Lookup179: pallet_timestamp::pallet::Call<T>
**/
PalletTimestampCall: {
_enum: {
@@ -1449,13 +1470,13 @@
}
},
/**
- * Lookup179: pallet_transaction_payment::Releases
+ * Lookup181: pallet_transaction_payment::Releases
**/
PalletTransactionPaymentReleases: {
_enum: ['V1Ancient', 'V2']
},
/**
- * Lookup180: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
+ * Lookup182: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
**/
PalletTreasuryProposal: {
proposer: 'AccountId32',
@@ -1464,7 +1485,7 @@
bond: 'u128'
},
/**
- * Lookup183: pallet_treasury::pallet::Call<T, I>
+ * Lookup185: pallet_treasury::pallet::Call<T, I>
**/
PalletTreasuryCall: {
_enum: {
@@ -1488,17 +1509,17 @@
}
},
/**
- * Lookup186: frame_support::PalletId
+ * Lookup188: frame_support::PalletId
**/
FrameSupportPalletId: '[u8;8]',
/**
- * Lookup187: pallet_treasury::pallet::Error<T, I>
+ * Lookup189: pallet_treasury::pallet::Error<T, I>
**/
PalletTreasuryError: {
_enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'InsufficientPermission', 'ProposalNotApproved']
},
/**
- * Lookup188: pallet_sudo::pallet::Call<T>
+ * Lookup190: pallet_sudo::pallet::Call<T>
**/
PalletSudoCall: {
_enum: {
@@ -1522,7 +1543,7 @@
}
},
/**
- * Lookup190: orml_vesting::module::Call<T>
+ * Lookup192: orml_vesting::module::Call<T>
**/
OrmlVestingModuleCall: {
_enum: {
@@ -1541,7 +1562,7 @@
}
},
/**
- * Lookup192: cumulus_pallet_xcmp_queue::pallet::Call<T>
+ * Lookup194: cumulus_pallet_xcmp_queue::pallet::Call<T>
**/
CumulusPalletXcmpQueueCall: {
_enum: {
@@ -1590,7 +1611,7 @@
}
},
/**
- * Lookup193: pallet_xcm::pallet::Call<T>
+ * Lookup195: pallet_xcm::pallet::Call<T>
**/
PalletXcmCall: {
_enum: {
@@ -1644,7 +1665,7 @@
}
},
/**
- * Lookup194: xcm::VersionedXcm<Call>
+ * Lookup196: xcm::VersionedXcm<Call>
**/
XcmVersionedXcm: {
_enum: {
@@ -1654,7 +1675,7 @@
}
},
/**
- * Lookup195: xcm::v0::Xcm<Call>
+ * Lookup197: xcm::v0::Xcm<Call>
**/
XcmV0Xcm: {
_enum: {
@@ -1708,7 +1729,7 @@
}
},
/**
- * Lookup197: xcm::v0::order::Order<Call>
+ * Lookup199: xcm::v0::order::Order<Call>
**/
XcmV0Order: {
_enum: {
@@ -1751,7 +1772,7 @@
}
},
/**
- * Lookup199: xcm::v0::Response
+ * Lookup201: xcm::v0::Response
**/
XcmV0Response: {
_enum: {
@@ -1759,7 +1780,7 @@
}
},
/**
- * Lookup200: xcm::v1::Xcm<Call>
+ * Lookup202: xcm::v1::Xcm<Call>
**/
XcmV1Xcm: {
_enum: {
@@ -1818,7 +1839,7 @@
}
},
/**
- * Lookup202: xcm::v1::order::Order<Call>
+ * Lookup204: xcm::v1::order::Order<Call>
**/
XcmV1Order: {
_enum: {
@@ -1863,7 +1884,7 @@
}
},
/**
- * Lookup204: xcm::v1::Response
+ * Lookup206: xcm::v1::Response
**/
XcmV1Response: {
_enum: {
@@ -1872,11 +1893,11 @@
}
},
/**
- * Lookup218: cumulus_pallet_xcm::pallet::Call<T>
+ * Lookup220: cumulus_pallet_xcm::pallet::Call<T>
**/
CumulusPalletXcmCall: 'Null',
/**
- * Lookup219: cumulus_pallet_dmp_queue::pallet::Call<T>
+ * Lookup221: cumulus_pallet_dmp_queue::pallet::Call<T>
**/
CumulusPalletDmpQueueCall: {
_enum: {
@@ -1887,7 +1908,7 @@
}
},
/**
- * Lookup220: pallet_inflation::pallet::Call<T>
+ * Lookup222: pallet_inflation::pallet::Call<T>
**/
PalletInflationCall: {
_enum: {
@@ -1897,7 +1918,7 @@
}
},
/**
- * Lookup221: pallet_unique::Call<T>
+ * Lookup223: pallet_unique::Call<T>
**/
PalletUniqueCall: {
_enum: {
@@ -2029,7 +2050,7 @@
}
},
/**
- * Lookup226: up_data_structs::CollectionMode
+ * Lookup228: up_data_structs::CollectionMode
**/
UpDataStructsCollectionMode: {
_enum: {
@@ -2039,7 +2060,7 @@
}
},
/**
- * Lookup227: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>
+ * Lookup229: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>
**/
UpDataStructsCreateCollectionData: {
mode: 'UpDataStructsCollectionMode',
@@ -2054,13 +2075,13 @@
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup229: up_data_structs::AccessMode
+ * Lookup231: up_data_structs::AccessMode
**/
UpDataStructsAccessMode: {
_enum: ['Normal', 'AllowList']
},
/**
- * Lookup231: up_data_structs::CollectionLimits
+ * Lookup233: up_data_structs::CollectionLimits
**/
UpDataStructsCollectionLimits: {
accountTokenOwnershipLimit: 'Option<u32>',
@@ -2074,7 +2095,7 @@
transfersEnabled: 'Option<bool>'
},
/**
- * Lookup233: up_data_structs::SponsoringRateLimit
+ * Lookup235: up_data_structs::SponsoringRateLimit
**/
UpDataStructsSponsoringRateLimit: {
_enum: {
@@ -2083,7 +2104,7 @@
}
},
/**
- * Lookup236: up_data_structs::CollectionPermissions
+ * Lookup238: up_data_structs::CollectionPermissions
**/
UpDataStructsCollectionPermissions: {
access: 'Option<UpDataStructsAccessMode>',
@@ -2091,7 +2112,7 @@
nesting: 'Option<UpDataStructsNestingPermissions>'
},
/**
- * Lookup238: up_data_structs::NestingPermissions
+ * Lookup240: up_data_structs::NestingPermissions
**/
UpDataStructsNestingPermissions: {
tokenOwner: 'bool',
@@ -2099,18 +2120,18 @@
restricted: 'Option<UpDataStructsOwnerRestrictedSet>'
},
/**
- * Lookup240: up_data_structs::OwnerRestrictedSet
+ * Lookup242: up_data_structs::OwnerRestrictedSet
**/
UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',
/**
- * Lookup245: up_data_structs::PropertyKeyPermission
+ * Lookup247: up_data_structs::PropertyKeyPermission
**/
UpDataStructsPropertyKeyPermission: {
key: 'Bytes',
permission: 'UpDataStructsPropertyPermission'
},
/**
- * Lookup246: up_data_structs::PropertyPermission
+ * Lookup248: up_data_structs::PropertyPermission
**/
UpDataStructsPropertyPermission: {
mutable: 'bool',
@@ -2118,14 +2139,14 @@
tokenOwner: 'bool'
},
/**
- * Lookup249: up_data_structs::Property
+ * Lookup251: up_data_structs::Property
**/
UpDataStructsProperty: {
key: 'Bytes',
value: 'Bytes'
},
/**
- * Lookup252: up_data_structs::CreateItemData
+ * Lookup254: up_data_structs::CreateItemData
**/
UpDataStructsCreateItemData: {
_enum: {
@@ -2135,26 +2156,26 @@
}
},
/**
- * Lookup253: up_data_structs::CreateNftData
+ * Lookup255: up_data_structs::CreateNftData
**/
UpDataStructsCreateNftData: {
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup254: up_data_structs::CreateFungibleData
+ * Lookup256: up_data_structs::CreateFungibleData
**/
UpDataStructsCreateFungibleData: {
value: 'u128'
},
/**
- * Lookup255: up_data_structs::CreateReFungibleData
+ * Lookup257: up_data_structs::CreateReFungibleData
**/
UpDataStructsCreateReFungibleData: {
pieces: 'u128',
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup258: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup260: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsCreateItemExData: {
_enum: {
@@ -2165,14 +2186,14 @@
}
},
/**
- * Lookup260: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup262: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsCreateNftExData: {
properties: 'Vec<UpDataStructsProperty>',
owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
},
/**
- * Lookup267: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup269: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsCreateRefungibleExSingleOwner: {
user: 'PalletEvmAccountBasicCrossAccountIdRepr',
@@ -2180,14 +2201,14 @@
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup269: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup271: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsCreateRefungibleExMultipleOwners: {
users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup270: pallet_unique_scheduler::pallet::Call<T>
+ * Lookup272: pallet_unique_scheduler::pallet::Call<T>
**/
PalletUniqueSchedulerCall: {
_enum: {
@@ -2211,7 +2232,7 @@
}
},
/**
- * Lookup272: frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>
+ * Lookup274: frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>
**/
FrameSupportScheduleMaybeHashed: {
_enum: {
@@ -2220,7 +2241,7 @@
}
},
/**
- * Lookup273: pallet_configuration::pallet::Call<T>
+ * Lookup275: pallet_configuration::pallet::Call<T>
**/
PalletConfigurationCall: {
_enum: {
@@ -2233,15 +2254,15 @@
}
},
/**
- * Lookup274: pallet_template_transaction_payment::Call<T>
+ * Lookup276: pallet_template_transaction_payment::Call<T>
**/
PalletTemplateTransactionPaymentCall: 'Null',
/**
- * Lookup275: pallet_structure::pallet::Call<T>
+ * Lookup277: pallet_structure::pallet::Call<T>
**/
PalletStructureCall: 'Null',
/**
- * Lookup276: pallet_rmrk_core::pallet::Call<T>
+ * Lookup278: pallet_rmrk_core::pallet::Call<T>
**/
PalletRmrkCoreCall: {
_enum: {
@@ -2332,7 +2353,7 @@
}
},
/**
- * Lookup282: rmrk_traits::resource::ResourceTypes<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup284: rmrk_traits::resource::ResourceTypes<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsResourceResourceTypes: {
_enum: {
@@ -2342,7 +2363,7 @@
}
},
/**
- * Lookup284: rmrk_traits::resource::BasicResource<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup286: rmrk_traits::resource::BasicResource<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsResourceBasicResource: {
src: 'Option<Bytes>',
@@ -2351,7 +2372,7 @@
thumb: 'Option<Bytes>'
},
/**
- * Lookup286: rmrk_traits::resource::ComposableResource<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup288: rmrk_traits::resource::ComposableResource<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsResourceComposableResource: {
parts: 'Vec<u32>',
@@ -2362,7 +2383,7 @@
thumb: 'Option<Bytes>'
},
/**
- * Lookup287: rmrk_traits::resource::SlotResource<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup289: rmrk_traits::resource::SlotResource<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsResourceSlotResource: {
base: 'u32',
@@ -2373,7 +2394,7 @@
thumb: 'Option<Bytes>'
},
/**
- * Lookup290: pallet_rmrk_equip::pallet::Call<T>
+ * Lookup292: pallet_rmrk_equip::pallet::Call<T>
**/
PalletRmrkEquipCall: {
_enum: {
@@ -2394,7 +2415,7 @@
}
},
/**
- * Lookup293: rmrk_traits::part::PartType<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup295: rmrk_traits::part::PartType<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsPartPartType: {
_enum: {
@@ -2403,7 +2424,7 @@
}
},
/**
- * Lookup295: rmrk_traits::part::FixedPart<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup297: rmrk_traits::part::FixedPart<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsPartFixedPart: {
id: 'u32',
@@ -2411,7 +2432,7 @@
src: 'Bytes'
},
/**
- * Lookup296: rmrk_traits::part::SlotPart<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup298: rmrk_traits::part::SlotPart<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsPartSlotPart: {
id: 'u32',
@@ -2420,7 +2441,7 @@
z: 'u32'
},
/**
- * Lookup297: rmrk_traits::part::EquippableList<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup299: rmrk_traits::part::EquippableList<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsPartEquippableList: {
_enum: {
@@ -2430,7 +2451,7 @@
}
},
/**
- * Lookup299: rmrk_traits::theme::Theme<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>, S>>
+ * Lookup301: rmrk_traits::theme::Theme<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>, S>>
**/
RmrkTraitsTheme: {
name: 'Bytes',
@@ -2438,14 +2459,43 @@
inherit: 'bool'
},
/**
- * Lookup301: rmrk_traits::theme::ThemeProperty<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup303: rmrk_traits::theme::ThemeProperty<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsThemeThemeProperty: {
key: 'Bytes',
value: 'Bytes'
},
/**
- * Lookup303: pallet_evm::pallet::Call<T>
+ * Lookup305: pallet_app_promotion::pallet::Call<T>
+ **/
+ PalletAppPromotionCall: {
+ _enum: {
+ set_admin_address: {
+ admin: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ },
+ stake: {
+ amount: 'u128',
+ },
+ unstake: 'Null',
+ sponsor_collection: {
+ collectionId: 'u32',
+ },
+ stop_sponsoring_collection: {
+ collectionId: 'u32',
+ },
+ sponsor_contract: {
+ contractId: 'H160',
+ },
+ stop_sponsoring_contract: {
+ contractId: 'H160',
+ },
+ payout_stakers: {
+ stakersNumber: 'Option<u8>'
+ }
+ }
+ },
+ /**
+ * Lookup307: pallet_evm::pallet::Call<T>
**/
PalletEvmCall: {
_enum: {
@@ -2488,7 +2538,7 @@
}
},
/**
- * Lookup307: pallet_ethereum::pallet::Call<T>
+ * Lookup311: pallet_ethereum::pallet::Call<T>
**/
PalletEthereumCall: {
_enum: {
@@ -2498,7 +2548,7 @@
}
},
/**
- * Lookup308: ethereum::transaction::TransactionV2
+ * Lookup312: ethereum::transaction::TransactionV2
**/
EthereumTransactionTransactionV2: {
_enum: {
@@ -2508,7 +2558,7 @@
}
},
/**
- * Lookup309: ethereum::transaction::LegacyTransaction
+ * Lookup313: ethereum::transaction::LegacyTransaction
**/
EthereumTransactionLegacyTransaction: {
nonce: 'U256',
@@ -2520,7 +2570,7 @@
signature: 'EthereumTransactionTransactionSignature'
},
/**
- * Lookup310: ethereum::transaction::TransactionAction
+ * Lookup314: ethereum::transaction::TransactionAction
**/
EthereumTransactionTransactionAction: {
_enum: {
@@ -2529,7 +2579,7 @@
}
},
/**
- * Lookup311: ethereum::transaction::TransactionSignature
+ * Lookup315: ethereum::transaction::TransactionSignature
**/
EthereumTransactionTransactionSignature: {
v: 'u64',
@@ -2537,7 +2587,7 @@
s: 'H256'
},
/**
- * Lookup313: ethereum::transaction::EIP2930Transaction
+ * Lookup317: ethereum::transaction::EIP2930Transaction
**/
EthereumTransactionEip2930Transaction: {
chainId: 'u64',
@@ -2553,14 +2603,14 @@
s: 'H256'
},
/**
- * Lookup315: ethereum::transaction::AccessListItem
+ * Lookup319: ethereum::transaction::AccessListItem
**/
EthereumTransactionAccessListItem: {
address: 'H160',
storageKeys: 'Vec<H256>'
},
/**
- * Lookup316: ethereum::transaction::EIP1559Transaction
+ * Lookup320: ethereum::transaction::EIP1559Transaction
**/
EthereumTransactionEip1559Transaction: {
chainId: 'u64',
@@ -2577,7 +2627,7 @@
s: 'H256'
},
/**
- * Lookup317: pallet_evm_migration::pallet::Call<T>
+ * Lookup321: pallet_evm_migration::pallet::Call<T>
**/
PalletEvmMigrationCall: {
_enum: {
@@ -2595,19 +2645,19 @@
}
},
/**
- * Lookup320: pallet_sudo::pallet::Error<T>
+ * Lookup324: pallet_sudo::pallet::Error<T>
**/
PalletSudoError: {
_enum: ['RequireSudo']
},
/**
- * Lookup322: orml_vesting::module::Error<T>
+ * Lookup326: orml_vesting::module::Error<T>
**/
OrmlVestingModuleError: {
_enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
},
/**
- * Lookup324: cumulus_pallet_xcmp_queue::InboundChannelDetails
+ * Lookup328: cumulus_pallet_xcmp_queue::InboundChannelDetails
**/
CumulusPalletXcmpQueueInboundChannelDetails: {
sender: 'u32',
@@ -2615,19 +2665,19 @@
messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'
},
/**
- * Lookup325: cumulus_pallet_xcmp_queue::InboundState
+ * Lookup329: cumulus_pallet_xcmp_queue::InboundState
**/
CumulusPalletXcmpQueueInboundState: {
_enum: ['Ok', 'Suspended']
},
/**
- * Lookup328: polkadot_parachain::primitives::XcmpMessageFormat
+ * Lookup332: polkadot_parachain::primitives::XcmpMessageFormat
**/
PolkadotParachainPrimitivesXcmpMessageFormat: {
_enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
},
/**
- * Lookup331: cumulus_pallet_xcmp_queue::OutboundChannelDetails
+ * Lookup335: cumulus_pallet_xcmp_queue::OutboundChannelDetails
**/
CumulusPalletXcmpQueueOutboundChannelDetails: {
recipient: 'u32',
@@ -2637,13 +2687,13 @@
lastIndex: 'u16'
},
/**
- * Lookup332: cumulus_pallet_xcmp_queue::OutboundState
+ * Lookup336: cumulus_pallet_xcmp_queue::OutboundState
**/
CumulusPalletXcmpQueueOutboundState: {
_enum: ['Ok', 'Suspended']
},
/**
- * Lookup334: cumulus_pallet_xcmp_queue::QueueConfigData
+ * Lookup338: cumulus_pallet_xcmp_queue::QueueConfigData
**/
CumulusPalletXcmpQueueQueueConfigData: {
suspendThreshold: 'u32',
@@ -2654,29 +2704,29 @@
xcmpMaxIndividualWeight: 'u64'
},
/**
- * Lookup336: cumulus_pallet_xcmp_queue::pallet::Error<T>
+ * Lookup340: cumulus_pallet_xcmp_queue::pallet::Error<T>
**/
CumulusPalletXcmpQueueError: {
_enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
},
/**
- * Lookup337: pallet_xcm::pallet::Error<T>
+ * Lookup341: pallet_xcm::pallet::Error<T>
**/
PalletXcmError: {
_enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']
},
/**
- * Lookup338: cumulus_pallet_xcm::pallet::Error<T>
+ * Lookup342: cumulus_pallet_xcm::pallet::Error<T>
**/
CumulusPalletXcmError: 'Null',
/**
- * Lookup339: cumulus_pallet_dmp_queue::ConfigData
+ * Lookup343: cumulus_pallet_dmp_queue::ConfigData
**/
CumulusPalletDmpQueueConfigData: {
maxIndividual: 'u64'
},
/**
- * Lookup340: cumulus_pallet_dmp_queue::PageIndexData
+ * Lookup344: cumulus_pallet_dmp_queue::PageIndexData
**/
CumulusPalletDmpQueuePageIndexData: {
beginUsed: 'u32',
@@ -2684,19 +2734,19 @@
overweightCount: 'u64'
},
/**
- * Lookup343: cumulus_pallet_dmp_queue::pallet::Error<T>
+ * Lookup347: cumulus_pallet_dmp_queue::pallet::Error<T>
**/
CumulusPalletDmpQueueError: {
_enum: ['Unknown', 'OverLimit']
},
/**
- * Lookup347: pallet_unique::Error<T>
+ * Lookup351: pallet_unique::Error<T>
**/
PalletUniqueError: {
_enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']
},
/**
- * Lookup350: pallet_unique_scheduler::ScheduledV3<frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
+ * Lookup354: pallet_unique_scheduler::ScheduledV3<frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
**/
PalletUniqueSchedulerScheduledV3: {
maybeId: 'Option<[u8;16]>',
@@ -2706,7 +2756,7 @@
origin: 'OpalRuntimeOriginCaller'
},
/**
- * Lookup351: opal_runtime::OriginCaller
+ * Lookup355: opal_runtime::OriginCaller
**/
OpalRuntimeOriginCaller: {
_enum: {
@@ -2815,7 +2865,7 @@
}
},
/**
- * Lookup352: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
+ * Lookup356: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
**/
FrameSupportDispatchRawOrigin: {
_enum: {
@@ -2825,7 +2875,7 @@
}
},
/**
- * Lookup353: pallet_xcm::pallet::Origin
+ * Lookup357: pallet_xcm::pallet::Origin
**/
PalletXcmOrigin: {
_enum: {
@@ -2834,7 +2884,7 @@
}
},
/**
- * Lookup354: cumulus_pallet_xcm::pallet::Origin
+ * Lookup358: cumulus_pallet_xcm::pallet::Origin
**/
CumulusPalletXcmOrigin: {
_enum: {
@@ -2843,7 +2893,7 @@
}
},
/**
- * Lookup355: pallet_ethereum::RawOrigin
+ * Lookup359: pallet_ethereum::RawOrigin
**/
PalletEthereumRawOrigin: {
_enum: {
@@ -2851,17 +2901,17 @@
}
},
/**
- * Lookup356: sp_core::Void
+ * Lookup360: sp_core::Void
**/
SpCoreVoid: 'Null',
/**
- * Lookup357: pallet_unique_scheduler::pallet::Error<T>
+ * Lookup361: pallet_unique_scheduler::pallet::Error<T>
**/
PalletUniqueSchedulerError: {
_enum: ['FailedToSchedule', 'NotFound', 'TargetBlockNumberInPast', 'RescheduleNoChange']
},
/**
- * Lookup358: up_data_structs::Collection<sp_core::crypto::AccountId32>
+ * Lookup362: up_data_structs::Collection<sp_core::crypto::AccountId32>
**/
UpDataStructsCollection: {
owner: 'AccountId32',
@@ -2869,15 +2919,15 @@
name: 'Vec<u16>',
description: 'Vec<u16>',
tokenPrefix: 'Bytes',
- sponsorship: 'UpDataStructsSponsorshipState',
+ sponsorship: 'UpDataStructsSponsorshipStateAccountId32',
limits: 'UpDataStructsCollectionLimits',
permissions: 'UpDataStructsCollectionPermissions',
externalCollection: 'bool'
},
/**
- * Lookup359: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
+ * Lookup363: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
**/
- UpDataStructsSponsorshipState: {
+ UpDataStructsSponsorshipStateAccountId32: {
_enum: {
Disabled: 'Null',
Unconfirmed: 'AccountId32',
@@ -2885,7 +2935,7 @@
}
},
/**
- * Lookup360: up_data_structs::Properties
+ * Lookup364: up_data_structs::Properties
**/
UpDataStructsProperties: {
map: 'UpDataStructsPropertiesMapBoundedVec',
@@ -2893,15 +2943,15 @@
spaceLimit: 'u32'
},
/**
- * Lookup361: up_data_structs::PropertiesMap<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup365: up_data_structs::PropertiesMap<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
/**
- * Lookup366: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
+ * Lookup370: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
**/
UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
/**
- * Lookup373: up_data_structs::CollectionStats
+ * Lookup377: up_data_structs::CollectionStats
**/
UpDataStructsCollectionStats: {
created: 'u32',
@@ -2909,18 +2959,18 @@
alive: 'u32'
},
/**
- * Lookup374: up_data_structs::TokenChild
+ * Lookup378: up_data_structs::TokenChild
**/
UpDataStructsTokenChild: {
token: 'u32',
collection: 'u32'
},
/**
- * Lookup375: PhantomType::up_data_structs<T>
+ * Lookup379: PhantomType::up_data_structs<T>
**/
PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]',
/**
- * Lookup377: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup381: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsTokenData: {
properties: 'Vec<UpDataStructsProperty>',
@@ -2928,7 +2978,7 @@
pieces: 'u128'
},
/**
- * Lookup379: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+ * Lookup383: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
**/
UpDataStructsRpcCollection: {
owner: 'AccountId32',
@@ -2936,7 +2986,7 @@
name: 'Vec<u16>',
description: 'Vec<u16>',
tokenPrefix: 'Bytes',
- sponsorship: 'UpDataStructsSponsorshipState',
+ sponsorship: 'UpDataStructsSponsorshipStateAccountId32',
limits: 'UpDataStructsCollectionLimits',
permissions: 'UpDataStructsCollectionPermissions',
tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
@@ -2944,7 +2994,7 @@
readOnly: 'bool'
},
/**
- * Lookup380: rmrk_traits::collection::CollectionInfo<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
+ * Lookup384: rmrk_traits::collection::CollectionInfo<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
**/
RmrkTraitsCollectionCollectionInfo: {
issuer: 'AccountId32',
@@ -2954,7 +3004,7 @@
nftsCount: 'u32'
},
/**
- * Lookup381: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup385: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsNftNftInfo: {
owner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',
@@ -2964,14 +3014,14 @@
pending: 'bool'
},
/**
- * Lookup383: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
+ * Lookup387: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
**/
RmrkTraitsNftRoyaltyInfo: {
recipient: 'AccountId32',
amount: 'Permill'
},
/**
- * Lookup384: rmrk_traits::resource::ResourceInfo<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup388: rmrk_traits::resource::ResourceInfo<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsResourceResourceInfo: {
id: 'u32',
@@ -2980,14 +3030,14 @@
pendingRemoval: 'bool'
},
/**
- * Lookup385: rmrk_traits::property::PropertyInfo<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup389: rmrk_traits::property::PropertyInfo<sp_runtime::bounded::bounded_vec::BoundedVec<T, S>, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsPropertyPropertyInfo: {
key: 'Bytes',
value: 'Bytes'
},
/**
- * Lookup386: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
+ * Lookup390: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, sp_runtime::bounded::bounded_vec::BoundedVec<T, S>>
**/
RmrkTraitsBaseBaseInfo: {
issuer: 'AccountId32',
@@ -2995,80 +3045,86 @@
symbol: 'Bytes'
},
/**
- * Lookup387: rmrk_traits::nft::NftChild
+ * Lookup391: rmrk_traits::nft::NftChild
**/
RmrkTraitsNftNftChild: {
collectionId: 'u32',
nftId: 'u32'
},
/**
- * Lookup389: pallet_common::pallet::Error<T>
+ * Lookup393: pallet_common::pallet::Error<T>
**/
PalletCommonError: {
_enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal']
},
/**
- * Lookup391: pallet_fungible::pallet::Error<T>
+ * Lookup395: pallet_fungible::pallet::Error<T>
**/
PalletFungibleError: {
_enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
},
/**
- * Lookup392: pallet_refungible::ItemData
+ * Lookup396: pallet_refungible::ItemData
**/
PalletRefungibleItemData: {
constData: 'Bytes'
},
/**
- * Lookup397: pallet_refungible::pallet::Error<T>
+ * Lookup401: pallet_refungible::pallet::Error<T>
**/
PalletRefungibleError: {
_enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
},
/**
- * Lookup398: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup402: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
PalletNonfungibleItemData: {
owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
},
/**
- * Lookup400: up_data_structs::PropertyScope
+ * Lookup404: up_data_structs::PropertyScope
**/
UpDataStructsPropertyScope: {
- _enum: ['None', 'Rmrk', 'Eth']
+ _enum: ['None', 'Rmrk']
},
/**
- * Lookup402: pallet_nonfungible::pallet::Error<T>
+ * Lookup406: pallet_nonfungible::pallet::Error<T>
**/
PalletNonfungibleError: {
_enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
},
/**
- * Lookup403: pallet_structure::pallet::Error<T>
+ * Lookup407: pallet_structure::pallet::Error<T>
**/
PalletStructureError: {
_enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound']
},
/**
- * Lookup404: pallet_rmrk_core::pallet::Error<T>
+ * Lookup408: pallet_rmrk_core::pallet::Error<T>
**/
PalletRmrkCoreError: {
_enum: ['CorruptedCollectionType', 'RmrkPropertyKeyIsTooLong', 'RmrkPropertyValueIsTooLong', 'RmrkPropertyIsNotFound', 'UnableToDecodeRmrkData', 'CollectionNotEmpty', 'NoAvailableCollectionId', 'NoAvailableNftId', 'CollectionUnknown', 'NoPermission', 'NonTransferable', 'CollectionFullOrLocked', 'ResourceDoesntExist', 'CannotSendToDescendentOrSelf', 'CannotAcceptNonOwnedNft', 'CannotRejectNonOwnedNft', 'CannotRejectNonPendingNft', 'ResourceNotPending', 'NoAvailableResourceId']
},
/**
- * Lookup406: pallet_rmrk_equip::pallet::Error<T>
+ * Lookup410: pallet_rmrk_equip::pallet::Error<T>
**/
PalletRmrkEquipError: {
_enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart']
},
/**
- * Lookup409: pallet_evm::pallet::Error<T>
+ * Lookup416: pallet_app_promotion::pallet::Error<T>
**/
+ PalletAppPromotionError: {
+ _enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'IncorrectLockedBalanceOperation']
+ },
+ /**
+ * Lookup419: pallet_evm::pallet::Error<T>
+ **/
PalletEvmError: {
_enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']
},
/**
- * Lookup412: fp_rpc::TransactionStatus
+ * Lookup422: fp_rpc::TransactionStatus
**/
FpRpcTransactionStatus: {
transactionHash: 'H256',
@@ -3080,11 +3136,11 @@
logsBloom: 'EthbloomBloom'
},
/**
- * Lookup414: ethbloom::Bloom
+ * Lookup424: ethbloom::Bloom
**/
EthbloomBloom: '[u8;256]',
/**
- * Lookup416: ethereum::receipt::ReceiptV3
+ * Lookup426: ethereum::receipt::ReceiptV3
**/
EthereumReceiptReceiptV3: {
_enum: {
@@ -3094,7 +3150,7 @@
}
},
/**
- * Lookup417: ethereum::receipt::EIP658ReceiptData
+ * Lookup427: ethereum::receipt::EIP658ReceiptData
**/
EthereumReceiptEip658ReceiptData: {
statusCode: 'u8',
@@ -3103,7 +3159,7 @@
logs: 'Vec<EthereumLog>'
},
/**
- * Lookup418: ethereum::block::Block<ethereum::transaction::TransactionV2>
+ * Lookup428: ethereum::block::Block<ethereum::transaction::TransactionV2>
**/
EthereumBlock: {
header: 'EthereumHeader',
@@ -3111,7 +3167,7 @@
ommers: 'Vec<EthereumHeader>'
},
/**
- * Lookup419: ethereum::header::Header
+ * Lookup429: ethereum::header::Header
**/
EthereumHeader: {
parentHash: 'H256',
@@ -3131,41 +3187,51 @@
nonce: 'EthereumTypesHashH64'
},
/**
- * Lookup420: ethereum_types::hash::H64
+ * Lookup430: ethereum_types::hash::H64
**/
EthereumTypesHashH64: '[u8;8]',
/**
- * Lookup425: pallet_ethereum::pallet::Error<T>
+ * Lookup435: pallet_ethereum::pallet::Error<T>
**/
PalletEthereumError: {
_enum: ['InvalidSignature', 'PreLogExists']
},
/**
- * Lookup426: pallet_evm_coder_substrate::pallet::Error<T>
+ * Lookup436: pallet_evm_coder_substrate::pallet::Error<T>
**/
PalletEvmCoderSubstrateError: {
_enum: ['OutOfGas', 'OutOfFund']
},
/**
- * Lookup427: pallet_evm_contract_helpers::SponsoringModeT
+ * Lookup437: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
+ UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: {
+ _enum: {
+ Disabled: 'Null',
+ Unconfirmed: 'PalletEvmAccountBasicCrossAccountIdRepr',
+ Confirmed: 'PalletEvmAccountBasicCrossAccountIdRepr'
+ }
+ },
+ /**
+ * Lookup438: pallet_evm_contract_helpers::SponsoringModeT
+ **/
PalletEvmContractHelpersSponsoringModeT: {
_enum: ['Disabled', 'Allowlisted', 'Generous']
},
/**
- * Lookup429: pallet_evm_contract_helpers::pallet::Error<T>
+ * Lookup440: pallet_evm_contract_helpers::pallet::Error<T>
**/
PalletEvmContractHelpersError: {
- _enum: ['NoPermission']
+ _enum: ['NoPermission', 'NoPendingSponsor']
},
/**
- * Lookup430: pallet_evm_migration::pallet::Error<T>
+ * Lookup441: pallet_evm_migration::pallet::Error<T>
**/
PalletEvmMigrationError: {
_enum: ['AccountNotEmpty', 'AccountIsNotMigrating']
},
/**
- * Lookup432: sp_runtime::MultiSignature
+ * Lookup443: sp_runtime::MultiSignature
**/
SpRuntimeMultiSignature: {
_enum: {
@@ -3175,43 +3241,43 @@
}
},
/**
- * Lookup433: sp_core::ed25519::Signature
+ * Lookup444: sp_core::ed25519::Signature
**/
SpCoreEd25519Signature: '[u8;64]',
/**
- * Lookup435: sp_core::sr25519::Signature
+ * Lookup446: sp_core::sr25519::Signature
**/
SpCoreSr25519Signature: '[u8;64]',
/**
- * Lookup436: sp_core::ecdsa::Signature
+ * Lookup447: sp_core::ecdsa::Signature
**/
SpCoreEcdsaSignature: '[u8;65]',
/**
- * Lookup439: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+ * Lookup450: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
**/
FrameSystemExtensionsCheckSpecVersion: 'Null',
/**
- * Lookup440: frame_system::extensions::check_genesis::CheckGenesis<T>
+ * Lookup451: frame_system::extensions::check_genesis::CheckGenesis<T>
**/
FrameSystemExtensionsCheckGenesis: 'Null',
/**
- * Lookup443: frame_system::extensions::check_nonce::CheckNonce<T>
+ * Lookup454: frame_system::extensions::check_nonce::CheckNonce<T>
**/
FrameSystemExtensionsCheckNonce: 'Compact<u32>',
/**
- * Lookup444: frame_system::extensions::check_weight::CheckWeight<T>
+ * Lookup455: frame_system::extensions::check_weight::CheckWeight<T>
**/
FrameSystemExtensionsCheckWeight: 'Null',
/**
- * Lookup445: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+ * Lookup456: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
**/
PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
/**
- * Lookup446: opal_runtime::Runtime
+ * Lookup457: opal_runtime::Runtime
**/
OpalRuntimeRuntime: 'Null',
/**
- * Lookup447: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+ * Lookup458: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
**/
PalletEthereumFakeTransactionFinalizer: 'Null'
};
tests/src/interfaces/registry.tsdiffbeforeafterboth--- a/tests/src/interfaces/registry.ts
+++ b/tests/src/interfaces/registry.ts
@@ -5,7 +5,7 @@
// this is required to allow for ambient/previous definitions
import '@polkadot/types/types/registry';
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportScheduleLookupError, FrameSupportScheduleMaybeHashed, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerCall, PalletUniqueSchedulerError, PalletUniqueSchedulerEvent, PalletUniqueSchedulerScheduledV3, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportScheduleLookupError, FrameSupportScheduleMaybeHashed, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerCall, PalletUniqueSchedulerError, PalletUniqueSchedulerEvent, PalletUniqueSchedulerScheduledV3, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
declare module '@polkadot/types/types/registry' {
interface InterfaceTypes {
@@ -83,6 +83,9 @@
OrmlVestingModuleError: OrmlVestingModuleError;
OrmlVestingModuleEvent: OrmlVestingModuleEvent;
OrmlVestingVestingSchedule: OrmlVestingVestingSchedule;
+ PalletAppPromotionCall: PalletAppPromotionCall;
+ PalletAppPromotionError: PalletAppPromotionError;
+ PalletAppPromotionEvent: PalletAppPromotionEvent;
PalletBalancesAccountData: PalletBalancesAccountData;
PalletBalancesBalanceLock: PalletBalancesBalanceLock;
PalletBalancesCall: PalletBalancesCall;
@@ -103,6 +106,7 @@
PalletEvmCall: PalletEvmCall;
PalletEvmCoderSubstrateError: PalletEvmCoderSubstrateError;
PalletEvmContractHelpersError: PalletEvmContractHelpersError;
+ PalletEvmContractHelpersEvent: PalletEvmContractHelpersEvent;
PalletEvmContractHelpersSponsoringModeT: PalletEvmContractHelpersSponsoringModeT;
PalletEvmError: PalletEvmError;
PalletEvmEvent: PalletEvmEvent;
@@ -213,7 +217,8 @@
UpDataStructsPropertyScope: UpDataStructsPropertyScope;
UpDataStructsRpcCollection: UpDataStructsRpcCollection;
UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
- UpDataStructsSponsorshipState: UpDataStructsSponsorshipState;
+ UpDataStructsSponsorshipStateAccountId32: UpDataStructsSponsorshipStateAccountId32;
+ UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: UpDataStructsSponsorshipStateBasicCrossAccountIdRepr;
UpDataStructsTokenChild: UpDataStructsTokenChild;
UpDataStructsTokenData: UpDataStructsTokenData;
XcmDoubleEncoded: XcmDoubleEncoded;
tests/src/interfaces/types-lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1198,7 +1198,20 @@
readonly type: 'BaseCreated' | 'EquippablesUpdated';
}
- /** @name PalletEvmEvent (103) */
+ /** @name PalletAppPromotionEvent (103) */
+ interface PalletAppPromotionEvent extends Enum {
+ readonly isStakingRecalculation: boolean;
+ readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
+ readonly isStake: boolean;
+ readonly asStake: ITuple<[AccountId32, u128]>;
+ readonly isUnstake: boolean;
+ readonly asUnstake: ITuple<[AccountId32, u128]>;
+ readonly isSetAdmin: boolean;
+ readonly asSetAdmin: AccountId32;
+ readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
+ }
+
+ /** @name PalletEvmEvent (104) */
interface PalletEvmEvent extends Enum {
readonly isLog: boolean;
readonly asLog: EthereumLog;
@@ -1217,21 +1230,21 @@
readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw';
}
- /** @name EthereumLog (104) */
+ /** @name EthereumLog (105) */
interface EthereumLog extends Struct {
readonly address: H160;
readonly topics: Vec<H256>;
readonly data: Bytes;
}
- /** @name PalletEthereumEvent (108) */
+ /** @name PalletEthereumEvent (109) */
interface PalletEthereumEvent extends Enum {
readonly isExecuted: boolean;
readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>;
readonly type: 'Executed';
}
- /** @name EvmCoreErrorExitReason (109) */
+ /** @name EvmCoreErrorExitReason (110) */
interface EvmCoreErrorExitReason extends Enum {
readonly isSucceed: boolean;
readonly asSucceed: EvmCoreErrorExitSucceed;
@@ -1244,7 +1257,7 @@
readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
}
- /** @name EvmCoreErrorExitSucceed (110) */
+ /** @name EvmCoreErrorExitSucceed (111) */
interface EvmCoreErrorExitSucceed extends Enum {
readonly isStopped: boolean;
readonly isReturned: boolean;
@@ -1252,7 +1265,7 @@
readonly type: 'Stopped' | 'Returned' | 'Suicided';
}
- /** @name EvmCoreErrorExitError (111) */
+ /** @name EvmCoreErrorExitError (112) */
interface EvmCoreErrorExitError extends Enum {
readonly isStackUnderflow: boolean;
readonly isStackOverflow: boolean;
@@ -1273,13 +1286,13 @@
readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'InvalidCode';
}
- /** @name EvmCoreErrorExitRevert (114) */
+ /** @name EvmCoreErrorExitRevert (115) */
interface EvmCoreErrorExitRevert extends Enum {
readonly isReverted: boolean;
readonly type: 'Reverted';
}
- /** @name EvmCoreErrorExitFatal (115) */
+ /** @name EvmCoreErrorExitFatal (116) */
interface EvmCoreErrorExitFatal extends Enum {
readonly isNotSupported: boolean;
readonly isUnhandledInterrupt: boolean;
@@ -1290,7 +1303,18 @@
readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
}
- /** @name FrameSystemPhase (116) */
+ /** @name PalletEvmContractHelpersEvent (117) */
+ interface PalletEvmContractHelpersEvent extends Enum {
+ readonly isContractSponsorSet: boolean;
+ readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorshipConfirmed: boolean;
+ readonly asContractSponsorshipConfirmed: ITuple<[H160, AccountId32]>;
+ readonly isContractSponsorRemoved: boolean;
+ readonly asContractSponsorRemoved: H160;
+ readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
+ }
+
+ /** @name FrameSystemPhase (118) */
interface FrameSystemPhase extends Enum {
readonly isApplyExtrinsic: boolean;
readonly asApplyExtrinsic: u32;
@@ -1299,13 +1323,13 @@
readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
}
- /** @name FrameSystemLastRuntimeUpgradeInfo (118) */
+ /** @name FrameSystemLastRuntimeUpgradeInfo (120) */
interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
readonly specVersion: Compact<u32>;
readonly specName: Text;
}
- /** @name FrameSystemCall (119) */
+ /** @name FrameSystemCall (121) */
interface FrameSystemCall extends Enum {
readonly isFillBlock: boolean;
readonly asFillBlock: {
@@ -1347,21 +1371,21 @@
readonly type: 'FillBlock' | 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
}
- /** @name FrameSystemLimitsBlockWeights (124) */
+ /** @name FrameSystemLimitsBlockWeights (126) */
interface FrameSystemLimitsBlockWeights extends Struct {
readonly baseBlock: u64;
readonly maxBlock: u64;
readonly perClass: FrameSupportWeightsPerDispatchClassWeightsPerClass;
}
- /** @name FrameSupportWeightsPerDispatchClassWeightsPerClass (125) */
+ /** @name FrameSupportWeightsPerDispatchClassWeightsPerClass (127) */
interface FrameSupportWeightsPerDispatchClassWeightsPerClass extends Struct {
readonly normal: FrameSystemLimitsWeightsPerClass;
readonly operational: FrameSystemLimitsWeightsPerClass;
readonly mandatory: FrameSystemLimitsWeightsPerClass;
}
- /** @name FrameSystemLimitsWeightsPerClass (126) */
+ /** @name FrameSystemLimitsWeightsPerClass (128) */
interface FrameSystemLimitsWeightsPerClass extends Struct {
readonly baseExtrinsic: u64;
readonly maxExtrinsic: Option<u64>;
@@ -1369,25 +1393,25 @@
readonly reserved: Option<u64>;
}
- /** @name FrameSystemLimitsBlockLength (128) */
+ /** @name FrameSystemLimitsBlockLength (130) */
interface FrameSystemLimitsBlockLength extends Struct {
readonly max: FrameSupportWeightsPerDispatchClassU32;
}
- /** @name FrameSupportWeightsPerDispatchClassU32 (129) */
+ /** @name FrameSupportWeightsPerDispatchClassU32 (131) */
interface FrameSupportWeightsPerDispatchClassU32 extends Struct {
readonly normal: u32;
readonly operational: u32;
readonly mandatory: u32;
}
- /** @name FrameSupportWeightsRuntimeDbWeight (130) */
+ /** @name FrameSupportWeightsRuntimeDbWeight (132) */
interface FrameSupportWeightsRuntimeDbWeight extends Struct {
readonly read: u64;
readonly write: u64;
}
- /** @name SpVersionRuntimeVersion (131) */
+ /** @name SpVersionRuntimeVersion (133) */
interface SpVersionRuntimeVersion extends Struct {
readonly specName: Text;
readonly implName: Text;
@@ -1399,7 +1423,7 @@
readonly stateVersion: u8;
}
- /** @name FrameSystemError (136) */
+ /** @name FrameSystemError (138) */
interface FrameSystemError extends Enum {
readonly isInvalidSpecName: boolean;
readonly isSpecVersionNeedsToIncrease: boolean;
@@ -1410,7 +1434,7 @@
readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
}
- /** @name PolkadotPrimitivesV2PersistedValidationData (137) */
+ /** @name PolkadotPrimitivesV2PersistedValidationData (139) */
interface PolkadotPrimitivesV2PersistedValidationData extends Struct {
readonly parentHead: Bytes;
readonly relayParentNumber: u32;
@@ -1418,18 +1442,18 @@
readonly maxPovSize: u32;
}
- /** @name PolkadotPrimitivesV2UpgradeRestriction (140) */
+ /** @name PolkadotPrimitivesV2UpgradeRestriction (142) */
interface PolkadotPrimitivesV2UpgradeRestriction extends Enum {
readonly isPresent: boolean;
readonly type: 'Present';
}
- /** @name SpTrieStorageProof (141) */
+ /** @name SpTrieStorageProof (143) */
interface SpTrieStorageProof extends Struct {
readonly trieNodes: BTreeSet<Bytes>;
}
- /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (143) */
+ /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (145) */
interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
readonly dmqMqcHead: H256;
readonly relayDispatchQueueSize: ITuple<[u32, u32]>;
@@ -1437,7 +1461,7 @@
readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV2AbridgedHrmpChannel]>>;
}
- /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (146) */
+ /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (148) */
interface PolkadotPrimitivesV2AbridgedHrmpChannel extends Struct {
readonly maxCapacity: u32;
readonly maxTotalSize: u32;
@@ -1447,7 +1471,7 @@
readonly mqcHead: Option<H256>;
}
- /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (147) */
+ /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (149) */
interface PolkadotPrimitivesV2AbridgedHostConfiguration extends Struct {
readonly maxCodeSize: u32;
readonly maxHeadDataSize: u32;
@@ -1460,13 +1484,13 @@
readonly validationUpgradeDelay: u32;
}
- /** @name PolkadotCorePrimitivesOutboundHrmpMessage (153) */
+ /** @name PolkadotCorePrimitivesOutboundHrmpMessage (155) */
interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
readonly recipient: u32;
readonly data: Bytes;
}
- /** @name CumulusPalletParachainSystemCall (154) */
+ /** @name CumulusPalletParachainSystemCall (156) */
interface CumulusPalletParachainSystemCall extends Enum {
readonly isSetValidationData: boolean;
readonly asSetValidationData: {
@@ -1487,7 +1511,7 @@
readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
}
- /** @name CumulusPrimitivesParachainInherentParachainInherentData (155) */
+ /** @name CumulusPrimitivesParachainInherentParachainInherentData (157) */
interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
readonly validationData: PolkadotPrimitivesV2PersistedValidationData;
readonly relayChainState: SpTrieStorageProof;
@@ -1495,19 +1519,19 @@
readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
}
- /** @name PolkadotCorePrimitivesInboundDownwardMessage (157) */
+ /** @name PolkadotCorePrimitivesInboundDownwardMessage (159) */
interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
readonly sentAt: u32;
readonly msg: Bytes;
}
- /** @name PolkadotCorePrimitivesInboundHrmpMessage (160) */
+ /** @name PolkadotCorePrimitivesInboundHrmpMessage (162) */
interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
readonly sentAt: u32;
readonly data: Bytes;
}
- /** @name CumulusPalletParachainSystemError (163) */
+ /** @name CumulusPalletParachainSystemError (165) */
interface CumulusPalletParachainSystemError extends Enum {
readonly isOverlappingUpgrades: boolean;
readonly isProhibitedByPolkadot: boolean;
@@ -1520,14 +1544,14 @@
readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
}
- /** @name PalletBalancesBalanceLock (165) */
+ /** @name PalletBalancesBalanceLock (167) */
interface PalletBalancesBalanceLock extends Struct {
readonly id: U8aFixed;
readonly amount: u128;
readonly reasons: PalletBalancesReasons;
}
- /** @name PalletBalancesReasons (166) */
+ /** @name PalletBalancesReasons (168) */
interface PalletBalancesReasons extends Enum {
readonly isFee: boolean;
readonly isMisc: boolean;
@@ -1535,20 +1559,20 @@
readonly type: 'Fee' | 'Misc' | 'All';
}
- /** @name PalletBalancesReserveData (169) */
+ /** @name PalletBalancesReserveData (171) */
interface PalletBalancesReserveData extends Struct {
readonly id: U8aFixed;
readonly amount: u128;
}
- /** @name PalletBalancesReleases (171) */
+ /** @name PalletBalancesReleases (173) */
interface PalletBalancesReleases extends Enum {
readonly isV100: boolean;
readonly isV200: boolean;
readonly type: 'V100' | 'V200';
}
- /** @name PalletBalancesCall (172) */
+ /** @name PalletBalancesCall (174) */
interface PalletBalancesCall extends Enum {
readonly isTransfer: boolean;
readonly asTransfer: {
@@ -1585,7 +1609,7 @@
readonly type: 'Transfer' | 'SetBalance' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve';
}
- /** @name PalletBalancesError (175) */
+ /** @name PalletBalancesError (177) */
interface PalletBalancesError extends Enum {
readonly isVestingBalance: boolean;
readonly isLiquidityRestrictions: boolean;
@@ -1598,7 +1622,7 @@
readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'KeepAlive' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves';
}
- /** @name PalletTimestampCall (177) */
+ /** @name PalletTimestampCall (179) */
interface PalletTimestampCall extends Enum {
readonly isSet: boolean;
readonly asSet: {
@@ -1607,14 +1631,14 @@
readonly type: 'Set';
}
- /** @name PalletTransactionPaymentReleases (179) */
+ /** @name PalletTransactionPaymentReleases (181) */
interface PalletTransactionPaymentReleases extends Enum {
readonly isV1Ancient: boolean;
readonly isV2: boolean;
readonly type: 'V1Ancient' | 'V2';
}
- /** @name PalletTreasuryProposal (180) */
+ /** @name PalletTreasuryProposal (182) */
interface PalletTreasuryProposal extends Struct {
readonly proposer: AccountId32;
readonly value: u128;
@@ -1622,7 +1646,7 @@
readonly bond: u128;
}
- /** @name PalletTreasuryCall (183) */
+ /** @name PalletTreasuryCall (185) */
interface PalletTreasuryCall extends Enum {
readonly isProposeSpend: boolean;
readonly asProposeSpend: {
@@ -1649,10 +1673,10 @@
readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
}
- /** @name FrameSupportPalletId (186) */
+ /** @name FrameSupportPalletId (188) */
interface FrameSupportPalletId extends U8aFixed {}
- /** @name PalletTreasuryError (187) */
+ /** @name PalletTreasuryError (189) */
interface PalletTreasuryError extends Enum {
readonly isInsufficientProposersBalance: boolean;
readonly isInvalidIndex: boolean;
@@ -1662,7 +1686,7 @@
readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
}
- /** @name PalletSudoCall (188) */
+ /** @name PalletSudoCall (190) */
interface PalletSudoCall extends Enum {
readonly isSudo: boolean;
readonly asSudo: {
@@ -1685,7 +1709,7 @@
readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
}
- /** @name OrmlVestingModuleCall (190) */
+ /** @name OrmlVestingModuleCall (192) */
interface OrmlVestingModuleCall extends Enum {
readonly isClaim: boolean;
readonly isVestedTransfer: boolean;
@@ -1705,7 +1729,7 @@
readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
}
- /** @name CumulusPalletXcmpQueueCall (192) */
+ /** @name CumulusPalletXcmpQueueCall (194) */
interface CumulusPalletXcmpQueueCall extends Enum {
readonly isServiceOverweight: boolean;
readonly asServiceOverweight: {
@@ -1741,7 +1765,7 @@
readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
}
- /** @name PalletXcmCall (193) */
+ /** @name PalletXcmCall (195) */
interface PalletXcmCall extends Enum {
readonly isSend: boolean;
readonly asSend: {
@@ -1803,7 +1827,7 @@
readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets';
}
- /** @name XcmVersionedXcm (194) */
+ /** @name XcmVersionedXcm (196) */
interface XcmVersionedXcm extends Enum {
readonly isV0: boolean;
readonly asV0: XcmV0Xcm;
@@ -1814,7 +1838,7 @@
readonly type: 'V0' | 'V1' | 'V2';
}
- /** @name XcmV0Xcm (195) */
+ /** @name XcmV0Xcm (197) */
interface XcmV0Xcm extends Enum {
readonly isWithdrawAsset: boolean;
readonly asWithdrawAsset: {
@@ -1877,7 +1901,7 @@
readonly type: 'WithdrawAsset' | 'ReserveAssetDeposit' | 'TeleportAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom';
}
- /** @name XcmV0Order (197) */
+ /** @name XcmV0Order (199) */
interface XcmV0Order extends Enum {
readonly isNull: boolean;
readonly isDepositAsset: boolean;
@@ -1925,14 +1949,14 @@
readonly type: 'Null' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution';
}
- /** @name XcmV0Response (199) */
+ /** @name XcmV0Response (201) */
interface XcmV0Response extends Enum {
readonly isAssets: boolean;
readonly asAssets: Vec<XcmV0MultiAsset>;
readonly type: 'Assets';
}
- /** @name XcmV1Xcm (200) */
+ /** @name XcmV1Xcm (202) */
interface XcmV1Xcm extends Enum {
readonly isWithdrawAsset: boolean;
readonly asWithdrawAsset: {
@@ -2001,7 +2025,7 @@
readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom' | 'SubscribeVersion' | 'UnsubscribeVersion';
}
- /** @name XcmV1Order (202) */
+ /** @name XcmV1Order (204) */
interface XcmV1Order extends Enum {
readonly isNoop: boolean;
readonly isDepositAsset: boolean;
@@ -2051,7 +2075,7 @@
readonly type: 'Noop' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution';
}
- /** @name XcmV1Response (204) */
+ /** @name XcmV1Response (206) */
interface XcmV1Response extends Enum {
readonly isAssets: boolean;
readonly asAssets: XcmV1MultiassetMultiAssets;
@@ -2060,10 +2084,10 @@
readonly type: 'Assets' | 'Version';
}
- /** @name CumulusPalletXcmCall (218) */
+ /** @name CumulusPalletXcmCall (220) */
type CumulusPalletXcmCall = Null;
- /** @name CumulusPalletDmpQueueCall (219) */
+ /** @name CumulusPalletDmpQueueCall (221) */
interface CumulusPalletDmpQueueCall extends Enum {
readonly isServiceOverweight: boolean;
readonly asServiceOverweight: {
@@ -2073,7 +2097,7 @@
readonly type: 'ServiceOverweight';
}
- /** @name PalletInflationCall (220) */
+ /** @name PalletInflationCall (222) */
interface PalletInflationCall extends Enum {
readonly isStartInflation: boolean;
readonly asStartInflation: {
@@ -2082,7 +2106,7 @@
readonly type: 'StartInflation';
}
- /** @name PalletUniqueCall (221) */
+ /** @name PalletUniqueCall (223) */
interface PalletUniqueCall extends Enum {
readonly isCreateCollection: boolean;
readonly asCreateCollection: {
@@ -2240,7 +2264,7 @@
readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition';
}
- /** @name UpDataStructsCollectionMode (226) */
+ /** @name UpDataStructsCollectionMode (228) */
interface UpDataStructsCollectionMode extends Enum {
readonly isNft: boolean;
readonly isFungible: boolean;
@@ -2249,7 +2273,7 @@
readonly type: 'Nft' | 'Fungible' | 'ReFungible';
}
- /** @name UpDataStructsCreateCollectionData (227) */
+ /** @name UpDataStructsCreateCollectionData (229) */
interface UpDataStructsCreateCollectionData extends Struct {
readonly mode: UpDataStructsCollectionMode;
readonly access: Option<UpDataStructsAccessMode>;
@@ -2263,14 +2287,14 @@
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name UpDataStructsAccessMode (229) */
+ /** @name UpDataStructsAccessMode (231) */
interface UpDataStructsAccessMode extends Enum {
readonly isNormal: boolean;
readonly isAllowList: boolean;
readonly type: 'Normal' | 'AllowList';
}
- /** @name UpDataStructsCollectionLimits (231) */
+ /** @name UpDataStructsCollectionLimits (233) */
interface UpDataStructsCollectionLimits extends Struct {
readonly accountTokenOwnershipLimit: Option<u32>;
readonly sponsoredDataSize: Option<u32>;
@@ -2283,7 +2307,7 @@
readonly transfersEnabled: Option<bool>;
}
- /** @name UpDataStructsSponsoringRateLimit (233) */
+ /** @name UpDataStructsSponsoringRateLimit (235) */
interface UpDataStructsSponsoringRateLimit extends Enum {
readonly isSponsoringDisabled: boolean;
readonly isBlocks: boolean;
@@ -2291,43 +2315,43 @@
readonly type: 'SponsoringDisabled' | 'Blocks';
}
- /** @name UpDataStructsCollectionPermissions (236) */
+ /** @name UpDataStructsCollectionPermissions (238) */
interface UpDataStructsCollectionPermissions extends Struct {
readonly access: Option<UpDataStructsAccessMode>;
readonly mintMode: Option<bool>;
readonly nesting: Option<UpDataStructsNestingPermissions>;
}
- /** @name UpDataStructsNestingPermissions (238) */
+ /** @name UpDataStructsNestingPermissions (240) */
interface UpDataStructsNestingPermissions extends Struct {
readonly tokenOwner: bool;
readonly collectionAdmin: bool;
readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
}
- /** @name UpDataStructsOwnerRestrictedSet (240) */
+ /** @name UpDataStructsOwnerRestrictedSet (242) */
interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
- /** @name UpDataStructsPropertyKeyPermission (245) */
+ /** @name UpDataStructsPropertyKeyPermission (247) */
interface UpDataStructsPropertyKeyPermission extends Struct {
readonly key: Bytes;
readonly permission: UpDataStructsPropertyPermission;
}
- /** @name UpDataStructsPropertyPermission (246) */
+ /** @name UpDataStructsPropertyPermission (248) */
interface UpDataStructsPropertyPermission extends Struct {
readonly mutable: bool;
readonly collectionAdmin: bool;
readonly tokenOwner: bool;
}
- /** @name UpDataStructsProperty (249) */
+ /** @name UpDataStructsProperty (251) */
interface UpDataStructsProperty extends Struct {
readonly key: Bytes;
readonly value: Bytes;
}
- /** @name UpDataStructsCreateItemData (252) */
+ /** @name UpDataStructsCreateItemData (254) */
interface UpDataStructsCreateItemData extends Enum {
readonly isNft: boolean;
readonly asNft: UpDataStructsCreateNftData;
@@ -2338,23 +2362,23 @@
readonly type: 'Nft' | 'Fungible' | 'ReFungible';
}
- /** @name UpDataStructsCreateNftData (253) */
+ /** @name UpDataStructsCreateNftData (255) */
interface UpDataStructsCreateNftData extends Struct {
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name UpDataStructsCreateFungibleData (254) */
+ /** @name UpDataStructsCreateFungibleData (256) */
interface UpDataStructsCreateFungibleData extends Struct {
readonly value: u128;
}
- /** @name UpDataStructsCreateReFungibleData (255) */
+ /** @name UpDataStructsCreateReFungibleData (257) */
interface UpDataStructsCreateReFungibleData extends Struct {
readonly pieces: u128;
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name UpDataStructsCreateItemExData (258) */
+ /** @name UpDataStructsCreateItemExData (260) */
interface UpDataStructsCreateItemExData extends Enum {
readonly isNft: boolean;
readonly asNft: Vec<UpDataStructsCreateNftExData>;
@@ -2367,26 +2391,26 @@
readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
}
- /** @name UpDataStructsCreateNftExData (260) */
+ /** @name UpDataStructsCreateNftExData (262) */
interface UpDataStructsCreateNftExData extends Struct {
readonly properties: Vec<UpDataStructsProperty>;
readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
}
- /** @name UpDataStructsCreateRefungibleExSingleOwner (267) */
+ /** @name UpDataStructsCreateRefungibleExSingleOwner (269) */
interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
readonly pieces: u128;
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name UpDataStructsCreateRefungibleExMultipleOwners (269) */
+ /** @name UpDataStructsCreateRefungibleExMultipleOwners (271) */
interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name PalletUniqueSchedulerCall (270) */
+ /** @name PalletUniqueSchedulerCall (272) */
interface PalletUniqueSchedulerCall extends Enum {
readonly isScheduleNamed: boolean;
readonly asScheduleNamed: {
@@ -2411,7 +2435,7 @@
readonly type: 'ScheduleNamed' | 'CancelNamed' | 'ScheduleNamedAfter';
}
- /** @name FrameSupportScheduleMaybeHashed (272) */
+ /** @name FrameSupportScheduleMaybeHashed (274) */
interface FrameSupportScheduleMaybeHashed extends Enum {
readonly isValue: boolean;
readonly asValue: Call;
@@ -2420,7 +2444,7 @@
readonly type: 'Value' | 'Hash';
}
- /** @name PalletConfigurationCall (273) */
+ /** @name PalletConfigurationCall (275) */
interface PalletConfigurationCall extends Enum {
readonly isSetWeightToFeeCoefficientOverride: boolean;
readonly asSetWeightToFeeCoefficientOverride: {
@@ -2433,13 +2457,13 @@
readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride';
}
- /** @name PalletTemplateTransactionPaymentCall (274) */
+ /** @name PalletTemplateTransactionPaymentCall (276) */
type PalletTemplateTransactionPaymentCall = Null;
- /** @name PalletStructureCall (275) */
+ /** @name PalletStructureCall (277) */
type PalletStructureCall = Null;
- /** @name PalletRmrkCoreCall (276) */
+ /** @name PalletRmrkCoreCall (278) */
interface PalletRmrkCoreCall extends Enum {
readonly isCreateCollection: boolean;
readonly asCreateCollection: {
@@ -2545,7 +2569,7 @@
readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'Send' | 'AcceptNft' | 'RejectNft' | 'AcceptResource' | 'AcceptResourceRemoval' | 'SetProperty' | 'SetPriority' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource' | 'RemoveResource';
}
- /** @name RmrkTraitsResourceResourceTypes (282) */
+ /** @name RmrkTraitsResourceResourceTypes (284) */
interface RmrkTraitsResourceResourceTypes extends Enum {
readonly isBasic: boolean;
readonly asBasic: RmrkTraitsResourceBasicResource;
@@ -2556,7 +2580,7 @@
readonly type: 'Basic' | 'Composable' | 'Slot';
}
- /** @name RmrkTraitsResourceBasicResource (284) */
+ /** @name RmrkTraitsResourceBasicResource (286) */
interface RmrkTraitsResourceBasicResource extends Struct {
readonly src: Option<Bytes>;
readonly metadata: Option<Bytes>;
@@ -2564,7 +2588,7 @@
readonly thumb: Option<Bytes>;
}
- /** @name RmrkTraitsResourceComposableResource (286) */
+ /** @name RmrkTraitsResourceComposableResource (288) */
interface RmrkTraitsResourceComposableResource extends Struct {
readonly parts: Vec<u32>;
readonly base: u32;
@@ -2574,7 +2598,7 @@
readonly thumb: Option<Bytes>;
}
- /** @name RmrkTraitsResourceSlotResource (287) */
+ /** @name RmrkTraitsResourceSlotResource (289) */
interface RmrkTraitsResourceSlotResource extends Struct {
readonly base: u32;
readonly src: Option<Bytes>;
@@ -2584,7 +2608,7 @@
readonly thumb: Option<Bytes>;
}
- /** @name PalletRmrkEquipCall (290) */
+ /** @name PalletRmrkEquipCall (292) */
interface PalletRmrkEquipCall extends Enum {
readonly isCreateBase: boolean;
readonly asCreateBase: {
@@ -2606,7 +2630,7 @@
readonly type: 'CreateBase' | 'ThemeAdd' | 'Equippable';
}
- /** @name RmrkTraitsPartPartType (293) */
+ /** @name RmrkTraitsPartPartType (295) */
interface RmrkTraitsPartPartType extends Enum {
readonly isFixedPart: boolean;
readonly asFixedPart: RmrkTraitsPartFixedPart;
@@ -2615,14 +2639,14 @@
readonly type: 'FixedPart' | 'SlotPart';
}
- /** @name RmrkTraitsPartFixedPart (295) */
+ /** @name RmrkTraitsPartFixedPart (297) */
interface RmrkTraitsPartFixedPart extends Struct {
readonly id: u32;
readonly z: u32;
readonly src: Bytes;
}
- /** @name RmrkTraitsPartSlotPart (296) */
+ /** @name RmrkTraitsPartSlotPart (298) */
interface RmrkTraitsPartSlotPart extends Struct {
readonly id: u32;
readonly equippable: RmrkTraitsPartEquippableList;
@@ -2630,7 +2654,7 @@
readonly z: u32;
}
- /** @name RmrkTraitsPartEquippableList (297) */
+ /** @name RmrkTraitsPartEquippableList (299) */
interface RmrkTraitsPartEquippableList extends Enum {
readonly isAll: boolean;
readonly isEmpty: boolean;
@@ -2639,20 +2663,54 @@
readonly type: 'All' | 'Empty' | 'Custom';
}
- /** @name RmrkTraitsTheme (299) */
+ /** @name RmrkTraitsTheme (301) */
interface RmrkTraitsTheme extends Struct {
readonly name: Bytes;
readonly properties: Vec<RmrkTraitsThemeThemeProperty>;
readonly inherit: bool;
}
- /** @name RmrkTraitsThemeThemeProperty (301) */
+ /** @name RmrkTraitsThemeThemeProperty (303) */
interface RmrkTraitsThemeThemeProperty extends Struct {
readonly key: Bytes;
readonly value: Bytes;
}
- /** @name PalletEvmCall (303) */
+ /** @name PalletAppPromotionCall (305) */
+ interface PalletAppPromotionCall extends Enum {
+ readonly isSetAdminAddress: boolean;
+ readonly asSetAdminAddress: {
+ readonly admin: PalletEvmAccountBasicCrossAccountIdRepr;
+ } & Struct;
+ readonly isStake: boolean;
+ readonly asStake: {
+ readonly amount: u128;
+ } & Struct;
+ readonly isUnstake: boolean;
+ readonly isSponsorCollection: boolean;
+ readonly asSponsorCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isStopSponsoringCollection: boolean;
+ readonly asStopSponsoringCollection: {
+ readonly collectionId: u32;
+ } & Struct;
+ readonly isSponsorContract: boolean;
+ readonly asSponsorContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isStopSponsoringContract: boolean;
+ readonly asStopSponsoringContract: {
+ readonly contractId: H160;
+ } & Struct;
+ readonly isPayoutStakers: boolean;
+ readonly asPayoutStakers: {
+ readonly stakersNumber: Option<u8>;
+ } & Struct;
+ readonly type: 'SetAdminAddress' | 'Stake' | 'Unstake' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers';
+ }
+
+ /** @name PalletEvmCall (307) */
interface PalletEvmCall extends Enum {
readonly isWithdraw: boolean;
readonly asWithdraw: {
@@ -2697,7 +2755,7 @@
readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
}
- /** @name PalletEthereumCall (307) */
+ /** @name PalletEthereumCall (311) */
interface PalletEthereumCall extends Enum {
readonly isTransact: boolean;
readonly asTransact: {
@@ -2706,7 +2764,7 @@
readonly type: 'Transact';
}
- /** @name EthereumTransactionTransactionV2 (308) */
+ /** @name EthereumTransactionTransactionV2 (312) */
interface EthereumTransactionTransactionV2 extends Enum {
readonly isLegacy: boolean;
readonly asLegacy: EthereumTransactionLegacyTransaction;
@@ -2717,7 +2775,7 @@
readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
}
- /** @name EthereumTransactionLegacyTransaction (309) */
+ /** @name EthereumTransactionLegacyTransaction (313) */
interface EthereumTransactionLegacyTransaction extends Struct {
readonly nonce: U256;
readonly gasPrice: U256;
@@ -2728,7 +2786,7 @@
readonly signature: EthereumTransactionTransactionSignature;
}
- /** @name EthereumTransactionTransactionAction (310) */
+ /** @name EthereumTransactionTransactionAction (314) */
interface EthereumTransactionTransactionAction extends Enum {
readonly isCall: boolean;
readonly asCall: H160;
@@ -2736,14 +2794,14 @@
readonly type: 'Call' | 'Create';
}
- /** @name EthereumTransactionTransactionSignature (311) */
+ /** @name EthereumTransactionTransactionSignature (315) */
interface EthereumTransactionTransactionSignature extends Struct {
readonly v: u64;
readonly r: H256;
readonly s: H256;
}
- /** @name EthereumTransactionEip2930Transaction (313) */
+ /** @name EthereumTransactionEip2930Transaction (317) */
interface EthereumTransactionEip2930Transaction extends Struct {
readonly chainId: u64;
readonly nonce: U256;
@@ -2758,13 +2816,13 @@
readonly s: H256;
}
- /** @name EthereumTransactionAccessListItem (315) */
+ /** @name EthereumTransactionAccessListItem (319) */
interface EthereumTransactionAccessListItem extends Struct {
readonly address: H160;
readonly storageKeys: Vec<H256>;
}
- /** @name EthereumTransactionEip1559Transaction (316) */
+ /** @name EthereumTransactionEip1559Transaction (320) */
interface EthereumTransactionEip1559Transaction extends Struct {
readonly chainId: u64;
readonly nonce: U256;
@@ -2780,7 +2838,7 @@
readonly s: H256;
}
- /** @name PalletEvmMigrationCall (317) */
+ /** @name PalletEvmMigrationCall (321) */
interface PalletEvmMigrationCall extends Enum {
readonly isBegin: boolean;
readonly asBegin: {
@@ -2799,13 +2857,13 @@
readonly type: 'Begin' | 'SetData' | 'Finish';
}
- /** @name PalletSudoError (320) */
+ /** @name PalletSudoError (324) */
interface PalletSudoError extends Enum {
readonly isRequireSudo: boolean;
readonly type: 'RequireSudo';
}
- /** @name OrmlVestingModuleError (322) */
+ /** @name OrmlVestingModuleError (326) */
interface OrmlVestingModuleError extends Enum {
readonly isZeroVestingPeriod: boolean;
readonly isZeroVestingPeriodCount: boolean;
@@ -2816,21 +2874,21 @@
readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
}
- /** @name CumulusPalletXcmpQueueInboundChannelDetails (324) */
+ /** @name CumulusPalletXcmpQueueInboundChannelDetails (328) */
interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
readonly sender: u32;
readonly state: CumulusPalletXcmpQueueInboundState;
readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesXcmpMessageFormat]>>;
}
- /** @name CumulusPalletXcmpQueueInboundState (325) */
+ /** @name CumulusPalletXcmpQueueInboundState (329) */
interface CumulusPalletXcmpQueueInboundState extends Enum {
readonly isOk: boolean;
readonly isSuspended: boolean;
readonly type: 'Ok' | 'Suspended';
}
- /** @name PolkadotParachainPrimitivesXcmpMessageFormat (328) */
+ /** @name PolkadotParachainPrimitivesXcmpMessageFormat (332) */
interface PolkadotParachainPrimitivesXcmpMessageFormat extends Enum {
readonly isConcatenatedVersionedXcm: boolean;
readonly isConcatenatedEncodedBlob: boolean;
@@ -2838,7 +2896,7 @@
readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
}
- /** @name CumulusPalletXcmpQueueOutboundChannelDetails (331) */
+ /** @name CumulusPalletXcmpQueueOutboundChannelDetails (335) */
interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
readonly recipient: u32;
readonly state: CumulusPalletXcmpQueueOutboundState;
@@ -2847,14 +2905,14 @@
readonly lastIndex: u16;
}
- /** @name CumulusPalletXcmpQueueOutboundState (332) */
+ /** @name CumulusPalletXcmpQueueOutboundState (336) */
interface CumulusPalletXcmpQueueOutboundState extends Enum {
readonly isOk: boolean;
readonly isSuspended: boolean;
readonly type: 'Ok' | 'Suspended';
}
- /** @name CumulusPalletXcmpQueueQueueConfigData (334) */
+ /** @name CumulusPalletXcmpQueueQueueConfigData (338) */
interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
readonly suspendThreshold: u32;
readonly dropThreshold: u32;
@@ -2864,7 +2922,7 @@
readonly xcmpMaxIndividualWeight: u64;
}
- /** @name CumulusPalletXcmpQueueError (336) */
+ /** @name CumulusPalletXcmpQueueError (340) */
interface CumulusPalletXcmpQueueError extends Enum {
readonly isFailedToSend: boolean;
readonly isBadXcmOrigin: boolean;
@@ -2874,7 +2932,7 @@
readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
}
- /** @name PalletXcmError (337) */
+ /** @name PalletXcmError (341) */
interface PalletXcmError extends Enum {
readonly isUnreachable: boolean;
readonly isSendFailure: boolean;
@@ -2892,29 +2950,29 @@
readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed';
}
- /** @name CumulusPalletXcmError (338) */
+ /** @name CumulusPalletXcmError (342) */
type CumulusPalletXcmError = Null;
- /** @name CumulusPalletDmpQueueConfigData (339) */
+ /** @name CumulusPalletDmpQueueConfigData (343) */
interface CumulusPalletDmpQueueConfigData extends Struct {
readonly maxIndividual: u64;
}
- /** @name CumulusPalletDmpQueuePageIndexData (340) */
+ /** @name CumulusPalletDmpQueuePageIndexData (344) */
interface CumulusPalletDmpQueuePageIndexData extends Struct {
readonly beginUsed: u32;
readonly endUsed: u32;
readonly overweightCount: u64;
}
- /** @name CumulusPalletDmpQueueError (343) */
+ /** @name CumulusPalletDmpQueueError (347) */
interface CumulusPalletDmpQueueError extends Enum {
readonly isUnknown: boolean;
readonly isOverLimit: boolean;
readonly type: 'Unknown' | 'OverLimit';
}
- /** @name PalletUniqueError (347) */
+ /** @name PalletUniqueError (351) */
interface PalletUniqueError extends Enum {
readonly isCollectionDecimalPointLimitExceeded: boolean;
readonly isConfirmUnsetSponsorFail: boolean;
@@ -2923,7 +2981,7 @@
readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
}
- /** @name PalletUniqueSchedulerScheduledV3 (350) */
+ /** @name PalletUniqueSchedulerScheduledV3 (354) */
interface PalletUniqueSchedulerScheduledV3 extends Struct {
readonly maybeId: Option<U8aFixed>;
readonly priority: u8;
@@ -2932,7 +2990,7 @@
readonly origin: OpalRuntimeOriginCaller;
}
- /** @name OpalRuntimeOriginCaller (351) */
+ /** @name OpalRuntimeOriginCaller (355) */
interface OpalRuntimeOriginCaller extends Enum {
readonly isSystem: boolean;
readonly asSystem: FrameSupportDispatchRawOrigin;
@@ -2946,7 +3004,7 @@
readonly type: 'System' | 'Void' | 'PolkadotXcm' | 'CumulusXcm' | 'Ethereum';
}
- /** @name FrameSupportDispatchRawOrigin (352) */
+ /** @name FrameSupportDispatchRawOrigin (356) */
interface FrameSupportDispatchRawOrigin extends Enum {
readonly isRoot: boolean;
readonly isSigned: boolean;
@@ -2955,7 +3013,7 @@
readonly type: 'Root' | 'Signed' | 'None';
}
- /** @name PalletXcmOrigin (353) */
+ /** @name PalletXcmOrigin (357) */
interface PalletXcmOrigin extends Enum {
readonly isXcm: boolean;
readonly asXcm: XcmV1MultiLocation;
@@ -2964,7 +3022,7 @@
readonly type: 'Xcm' | 'Response';
}
- /** @name CumulusPalletXcmOrigin (354) */
+ /** @name CumulusPalletXcmOrigin (358) */
interface CumulusPalletXcmOrigin extends Enum {
readonly isRelay: boolean;
readonly isSiblingParachain: boolean;
@@ -2972,17 +3030,17 @@
readonly type: 'Relay' | 'SiblingParachain';
}
- /** @name PalletEthereumRawOrigin (355) */
+ /** @name PalletEthereumRawOrigin (359) */
interface PalletEthereumRawOrigin extends Enum {
readonly isEthereumTransaction: boolean;
readonly asEthereumTransaction: H160;
readonly type: 'EthereumTransaction';
}
- /** @name SpCoreVoid (356) */
+ /** @name SpCoreVoid (360) */
type SpCoreVoid = Null;
- /** @name PalletUniqueSchedulerError (357) */
+ /** @name PalletUniqueSchedulerError (361) */
interface PalletUniqueSchedulerError extends Enum {
readonly isFailedToSchedule: boolean;
readonly isNotFound: boolean;
@@ -2991,21 +3049,21 @@
readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange';
}
- /** @name UpDataStructsCollection (358) */
+ /** @name UpDataStructsCollection (362) */
interface UpDataStructsCollection extends Struct {
readonly owner: AccountId32;
readonly mode: UpDataStructsCollectionMode;
readonly name: Vec<u16>;
readonly description: Vec<u16>;
readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipState;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
readonly limits: UpDataStructsCollectionLimits;
readonly permissions: UpDataStructsCollectionPermissions;
readonly externalCollection: bool;
}
- /** @name UpDataStructsSponsorshipState (359) */
- interface UpDataStructsSponsorshipState extends Enum {
+ /** @name UpDataStructsSponsorshipStateAccountId32 (363) */
+ interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
readonly isDisabled: boolean;
readonly isUnconfirmed: boolean;
readonly asUnconfirmed: AccountId32;
@@ -3014,50 +3072,50 @@
readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
}
- /** @name UpDataStructsProperties (360) */
+ /** @name UpDataStructsProperties (364) */
interface UpDataStructsProperties extends Struct {
readonly map: UpDataStructsPropertiesMapBoundedVec;
readonly consumedSpace: u32;
readonly spaceLimit: u32;
}
- /** @name UpDataStructsPropertiesMapBoundedVec (361) */
+ /** @name UpDataStructsPropertiesMapBoundedVec (365) */
interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
- /** @name UpDataStructsPropertiesMapPropertyPermission (366) */
+ /** @name UpDataStructsPropertiesMapPropertyPermission (370) */
interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
- /** @name UpDataStructsCollectionStats (373) */
+ /** @name UpDataStructsCollectionStats (377) */
interface UpDataStructsCollectionStats extends Struct {
readonly created: u32;
readonly destroyed: u32;
readonly alive: u32;
}
- /** @name UpDataStructsTokenChild (374) */
+ /** @name UpDataStructsTokenChild (378) */
interface UpDataStructsTokenChild extends Struct {
readonly token: u32;
readonly collection: u32;
}
- /** @name PhantomTypeUpDataStructs (375) */
+ /** @name PhantomTypeUpDataStructs (379) */
interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild]>> {}
- /** @name UpDataStructsTokenData (377) */
+ /** @name UpDataStructsTokenData (381) */
interface UpDataStructsTokenData extends Struct {
readonly properties: Vec<UpDataStructsProperty>;
readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
readonly pieces: u128;
}
- /** @name UpDataStructsRpcCollection (379) */
+ /** @name UpDataStructsRpcCollection (383) */
interface UpDataStructsRpcCollection extends Struct {
readonly owner: AccountId32;
readonly mode: UpDataStructsCollectionMode;
readonly name: Vec<u16>;
readonly description: Vec<u16>;
readonly tokenPrefix: Bytes;
- readonly sponsorship: UpDataStructsSponsorshipState;
+ readonly sponsorship: UpDataStructsSponsorshipStateAccountId32;
readonly limits: UpDataStructsCollectionLimits;
readonly permissions: UpDataStructsCollectionPermissions;
readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
@@ -3065,7 +3123,7 @@
readonly readOnly: bool;
}
- /** @name RmrkTraitsCollectionCollectionInfo (380) */
+ /** @name RmrkTraitsCollectionCollectionInfo (384) */
interface RmrkTraitsCollectionCollectionInfo extends Struct {
readonly issuer: AccountId32;
readonly metadata: Bytes;
@@ -3074,7 +3132,7 @@
readonly nftsCount: u32;
}
- /** @name RmrkTraitsNftNftInfo (381) */
+ /** @name RmrkTraitsNftNftInfo (385) */
interface RmrkTraitsNftNftInfo extends Struct {
readonly owner: RmrkTraitsNftAccountIdOrCollectionNftTuple;
readonly royalty: Option<RmrkTraitsNftRoyaltyInfo>;
@@ -3083,13 +3141,13 @@
readonly pending: bool;
}
- /** @name RmrkTraitsNftRoyaltyInfo (383) */
+ /** @name RmrkTraitsNftRoyaltyInfo (387) */
interface RmrkTraitsNftRoyaltyInfo extends Struct {
readonly recipient: AccountId32;
readonly amount: Permill;
}
- /** @name RmrkTraitsResourceResourceInfo (384) */
+ /** @name RmrkTraitsResourceResourceInfo (388) */
interface RmrkTraitsResourceResourceInfo extends Struct {
readonly id: u32;
readonly resource: RmrkTraitsResourceResourceTypes;
@@ -3097,26 +3155,26 @@
readonly pendingRemoval: bool;
}
- /** @name RmrkTraitsPropertyPropertyInfo (385) */
+ /** @name RmrkTraitsPropertyPropertyInfo (389) */
interface RmrkTraitsPropertyPropertyInfo extends Struct {
readonly key: Bytes;
readonly value: Bytes;
}
- /** @name RmrkTraitsBaseBaseInfo (386) */
+ /** @name RmrkTraitsBaseBaseInfo (390) */
interface RmrkTraitsBaseBaseInfo extends Struct {
readonly issuer: AccountId32;
readonly baseType: Bytes;
readonly symbol: Bytes;
}
- /** @name RmrkTraitsNftNftChild (387) */
+ /** @name RmrkTraitsNftNftChild (391) */
interface RmrkTraitsNftNftChild extends Struct {
readonly collectionId: u32;
readonly nftId: u32;
}
- /** @name PalletCommonError (389) */
+ /** @name PalletCommonError (393) */
interface PalletCommonError extends Enum {
readonly isCollectionNotFound: boolean;
readonly isMustBeTokenOwner: boolean;
@@ -3155,7 +3213,7 @@
readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal';
}
- /** @name PalletFungibleError (391) */
+ /** @name PalletFungibleError (395) */
interface PalletFungibleError extends Enum {
readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isFungibleItemsHaveNoId: boolean;
@@ -3165,12 +3223,12 @@
readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
}
- /** @name PalletRefungibleItemData (392) */
+ /** @name PalletRefungibleItemData (396) */
interface PalletRefungibleItemData extends Struct {
readonly constData: Bytes;
}
- /** @name PalletRefungibleError (397) */
+ /** @name PalletRefungibleError (401) */
interface PalletRefungibleError extends Enum {
readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isWrongRefungiblePieces: boolean;
@@ -3180,20 +3238,19 @@
readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
}
- /** @name PalletNonfungibleItemData (398) */
+ /** @name PalletNonfungibleItemData (402) */
interface PalletNonfungibleItemData extends Struct {
readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
}
- /** @name UpDataStructsPropertyScope (400) */
+ /** @name UpDataStructsPropertyScope (404) */
interface UpDataStructsPropertyScope extends Enum {
readonly isNone: boolean;
readonly isRmrk: boolean;
- readonly isEth: boolean;
- readonly type: 'None' | 'Rmrk' | 'Eth';
+ readonly type: 'None' | 'Rmrk';
}
- /** @name PalletNonfungibleError (402) */
+ /** @name PalletNonfungibleError (406) */
interface PalletNonfungibleError extends Enum {
readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isNonfungibleItemsHaveNoAmount: boolean;
@@ -3201,7 +3258,7 @@
readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
}
- /** @name PalletStructureError (403) */
+ /** @name PalletStructureError (407) */
interface PalletStructureError extends Enum {
readonly isOuroborosDetected: boolean;
readonly isDepthLimit: boolean;
@@ -3210,7 +3267,7 @@
readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound';
}
- /** @name PalletRmrkCoreError (404) */
+ /** @name PalletRmrkCoreError (408) */
interface PalletRmrkCoreError extends Enum {
readonly isCorruptedCollectionType: boolean;
readonly isRmrkPropertyKeyIsTooLong: boolean;
@@ -3234,7 +3291,7 @@
readonly type: 'CorruptedCollectionType' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'RmrkPropertyIsNotFound' | 'UnableToDecodeRmrkData' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'NonTransferable' | 'CollectionFullOrLocked' | 'ResourceDoesntExist' | 'CannotSendToDescendentOrSelf' | 'CannotAcceptNonOwnedNft' | 'CannotRejectNonOwnedNft' | 'CannotRejectNonPendingNft' | 'ResourceNotPending' | 'NoAvailableResourceId';
}
- /** @name PalletRmrkEquipError (406) */
+ /** @name PalletRmrkEquipError (410) */
interface PalletRmrkEquipError extends Enum {
readonly isPermissionError: boolean;
readonly isNoAvailableBaseId: boolean;
@@ -3246,7 +3303,18 @@
readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst' | 'PartDoesntExist' | 'NoEquippableOnFixedPart';
}
- /** @name PalletEvmError (409) */
+ /** @name PalletAppPromotionError (416) */
+ interface PalletAppPromotionError extends Enum {
+ readonly isAdminNotSet: boolean;
+ readonly isNoPermission: boolean;
+ readonly isNotSufficientFunds: boolean;
+ readonly isPendingForBlockOverflow: boolean;
+ readonly isSponsorNotSet: boolean;
+ readonly isIncorrectLockedBalanceOperation: boolean;
+ readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'IncorrectLockedBalanceOperation';
+ }
+
+ /** @name PalletEvmError (419) */
interface PalletEvmError extends Enum {
readonly isBalanceLow: boolean;
readonly isFeeOverflow: boolean;
@@ -3257,7 +3325,7 @@
readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce';
}
- /** @name FpRpcTransactionStatus (412) */
+ /** @name FpRpcTransactionStatus (422) */
interface FpRpcTransactionStatus extends Struct {
readonly transactionHash: H256;
readonly transactionIndex: u32;
@@ -3268,10 +3336,10 @@
readonly logsBloom: EthbloomBloom;
}
- /** @name EthbloomBloom (414) */
+ /** @name EthbloomBloom (424) */
interface EthbloomBloom extends U8aFixed {}
- /** @name EthereumReceiptReceiptV3 (416) */
+ /** @name EthereumReceiptReceiptV3 (426) */
interface EthereumReceiptReceiptV3 extends Enum {
readonly isLegacy: boolean;
readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -3282,7 +3350,7 @@
readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
}
- /** @name EthereumReceiptEip658ReceiptData (417) */
+ /** @name EthereumReceiptEip658ReceiptData (427) */
interface EthereumReceiptEip658ReceiptData extends Struct {
readonly statusCode: u8;
readonly usedGas: U256;
@@ -3290,14 +3358,14 @@
readonly logs: Vec<EthereumLog>;
}
- /** @name EthereumBlock (418) */
+ /** @name EthereumBlock (428) */
interface EthereumBlock extends Struct {
readonly header: EthereumHeader;
readonly transactions: Vec<EthereumTransactionTransactionV2>;
readonly ommers: Vec<EthereumHeader>;
}
- /** @name EthereumHeader (419) */
+ /** @name EthereumHeader (429) */
interface EthereumHeader extends Struct {
readonly parentHash: H256;
readonly ommersHash: H256;
@@ -3316,24 +3384,34 @@
readonly nonce: EthereumTypesHashH64;
}
- /** @name EthereumTypesHashH64 (420) */
+ /** @name EthereumTypesHashH64 (430) */
interface EthereumTypesHashH64 extends U8aFixed {}
- /** @name PalletEthereumError (425) */
+ /** @name PalletEthereumError (435) */
interface PalletEthereumError extends Enum {
readonly isInvalidSignature: boolean;
readonly isPreLogExists: boolean;
readonly type: 'InvalidSignature' | 'PreLogExists';
}
- /** @name PalletEvmCoderSubstrateError (426) */
+ /** @name PalletEvmCoderSubstrateError (436) */
interface PalletEvmCoderSubstrateError extends Enum {
readonly isOutOfGas: boolean;
readonly isOutOfFund: boolean;
readonly type: 'OutOfGas' | 'OutOfFund';
}
- /** @name PalletEvmContractHelpersSponsoringModeT (427) */
+ /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (437) */
+ interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
+ readonly isDisabled: boolean;
+ readonly isUnconfirmed: boolean;
+ readonly asUnconfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly isConfirmed: boolean;
+ readonly asConfirmed: PalletEvmAccountBasicCrossAccountIdRepr;
+ readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
+ }
+
+ /** @name PalletEvmContractHelpersSponsoringModeT (438) */
interface PalletEvmContractHelpersSponsoringModeT extends Enum {
readonly isDisabled: boolean;
readonly isAllowlisted: boolean;
@@ -3341,20 +3419,21 @@
readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
}
- /** @name PalletEvmContractHelpersError (429) */
+ /** @name PalletEvmContractHelpersError (440) */
interface PalletEvmContractHelpersError extends Enum {
readonly isNoPermission: boolean;
- readonly type: 'NoPermission';
+ readonly isNoPendingSponsor: boolean;
+ readonly type: 'NoPermission' | 'NoPendingSponsor';
}
- /** @name PalletEvmMigrationError (430) */
+ /** @name PalletEvmMigrationError (441) */
interface PalletEvmMigrationError extends Enum {
readonly isAccountNotEmpty: boolean;
readonly isAccountIsNotMigrating: boolean;
readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating';
}
- /** @name SpRuntimeMultiSignature (432) */
+ /** @name SpRuntimeMultiSignature (443) */
interface SpRuntimeMultiSignature extends Enum {
readonly isEd25519: boolean;
readonly asEd25519: SpCoreEd25519Signature;
@@ -3365,34 +3444,34 @@
readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
}
- /** @name SpCoreEd25519Signature (433) */
+ /** @name SpCoreEd25519Signature (444) */
interface SpCoreEd25519Signature extends U8aFixed {}
- /** @name SpCoreSr25519Signature (435) */
+ /** @name SpCoreSr25519Signature (446) */
interface SpCoreSr25519Signature extends U8aFixed {}
- /** @name SpCoreEcdsaSignature (436) */
+ /** @name SpCoreEcdsaSignature (447) */
interface SpCoreEcdsaSignature extends U8aFixed {}
- /** @name FrameSystemExtensionsCheckSpecVersion (439) */
+ /** @name FrameSystemExtensionsCheckSpecVersion (450) */
type FrameSystemExtensionsCheckSpecVersion = Null;
- /** @name FrameSystemExtensionsCheckGenesis (440) */
+ /** @name FrameSystemExtensionsCheckGenesis (451) */
type FrameSystemExtensionsCheckGenesis = Null;
- /** @name FrameSystemExtensionsCheckNonce (443) */
+ /** @name FrameSystemExtensionsCheckNonce (454) */
interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
- /** @name FrameSystemExtensionsCheckWeight (444) */
+ /** @name FrameSystemExtensionsCheckWeight (455) */
type FrameSystemExtensionsCheckWeight = Null;
- /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (445) */
+ /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (456) */
interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
- /** @name OpalRuntimeRuntime (446) */
+ /** @name OpalRuntimeRuntime (457) */
type OpalRuntimeRuntime = Null;
- /** @name PalletEthereumFakeTransactionFinalizer (447) */
+ /** @name PalletEthereumFakeTransactionFinalizer (458) */
type PalletEthereumFakeTransactionFinalizer = Null;
} // declare module
tests/src/interfaces/types.tsdiffbeforeafterboth--- a/tests/src/interfaces/types.ts
+++ b/tests/src/interfaces/types.ts
@@ -2,5 +2,6 @@
/* eslint-disable */
export * from './unique/types';
+export * from './appPromotion/types';
export * from './rmrk/types';
export * from './default/types';
tests/src/pallet-presence.test.tsdiffbeforeafterboth--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -68,9 +68,10 @@
const refungible = 'refungible';
const scheduler = 'scheduler';
const rmrkPallets = ['rmrkcore', 'rmrkequip'];
+ const appPromotion = 'apppromotion';
if (chain.eq('OPAL by UNIQUE')) {
- requiredPallets.push(refungible, scheduler, ...rmrkPallets);
+ requiredPallets.push(refungible, scheduler, appPromotion, ...rmrkPallets);
} else if (chain.eq('QUARTZ by UNIQUE')) {
// Insert Quartz additional pallets here
} else if (chain.eq('UNIQUE')) {
tests/src/refungible.test.tsdiffbeforeafterboth--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -245,8 +245,8 @@
section: 'common',
index: '0x4202',
data: [
- collection.collectionId.toString(),
- token.tokenId.toString(),
+ helper.api!.createType('u32', collection.collectionId).toHuman(),
+ helper.api!.createType('u32', token.tokenId).toHuman(),
{Substrate: alice.address},
'100',
],
@@ -265,8 +265,8 @@
section: 'common',
index: '0x4203',
data: [
- collection.collectionId.toString(),
- token.tokenId.toString(),
+ helper.api!.createType('u32', collection.collectionId).toHuman(),
+ helper.api!.createType('u32', token.tokenId).toHuman(),
{Substrate: alice.address},
'50',
],
tests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -27,6 +27,7 @@
const alice = privateKey('//Alice');
const bob = privateKey('//Bob');
const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
const collectionInfo = await collection.getData();
expect(collectionInfo?.raw.owner.toString()).to.be.deep.eq(alice.address);
// first - add collection admin Bob
tests/src/substrate/substrate-api.tsdiffbeforeafterboth--- a/tests/src/substrate/substrate-api.ts
+++ b/tests/src/substrate/substrate-api.ts
@@ -25,6 +25,8 @@
import privateKey from './privateKey';
import promisifySubstrate from './promisify-substrate';
+import {SilentConsole} from '../util/playgrounds/unique.dev';
+
function defaultApiOptions(): ApiOptions {
@@ -42,6 +44,7 @@
},
rpc: {
unique: defs.unique.rpc,
+ appPromotion: defs.appPromotion.rpc,
rmrk: defs.rmrk.rpc,
eth: {
feeHistory: {
@@ -75,25 +78,8 @@
const api: ApiPromise = new ApiPromise(settings);
let result: T = null as unknown as T;
- // TODO: Remove, this is temporary: Filter unneeded API output
- // (Jaco promised it will be removed in the next version)
- const consoleErr = console.error;
- const consoleLog = console.log;
- const consoleWarn = console.warn;
-
- const outFn = (printer: any) => (...args: any[]) => {
- for (const arg of args) {
- if (typeof arg !== 'string')
- continue;
- if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
- return;
- }
- printer(...args);
- };
-
- console.error = outFn(consoleErr.bind(console));
- console.log = outFn(consoleLog.bind(console));
- console.warn = outFn(consoleWarn.bind(console));
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
try {
await promisifySubstrate(api, async () => {
@@ -106,9 +92,7 @@
})();
} finally {
await api.disconnect();
- console.error = consoleErr;
- console.log = consoleLog;
- console.warn = consoleWarn;
+ silentConsole.disable();
}
return result as T;
}
tests/src/util/helpers.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import '../interfaces/augment-api-rpc';18import '../interfaces/augment-api-query';19import {ApiPromise} from '@polkadot/api';20import type {AccountId, EventRecord, Event} from '@polkadot/types/interfaces';21import type {GenericEventData} from '@polkadot/types';22import {AnyTuple, IEvent, IKeyringPair} from '@polkadot/types/types';23import {evmToAddress} from '@polkadot/util-crypto';24import BN from 'bn.js';25import chai from 'chai';26import chaiAsPromised from 'chai-as-promised';27import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';28import {hexToStr, strToUTF16, utf16ToStr} from './util';29import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';30import {UpDataStructsTokenChild} from '../interfaces';31import {Context} from 'mocha';3233chai.use(chaiAsPromised);34const expect = chai.expect;3536export type CrossAccountId = {37 Substrate: string,38} | {39 Ethereum: string,40};414243export enum Pallets {44 Inflation = 'inflation',45 RmrkCore = 'rmrkcore',46 RmrkEquip = 'rmrkequip',47 ReFungible = 'refungible',48 Fungible = 'fungible',49 NFT = 'nonfungible',50 Scheduler = 'scheduler',51}5253export async function isUnique(): Promise<boolean> {54 return usingApi(async api => {55 const chain = await api.rpc.system.chain();5657 return chain.eq('UNIQUE');58 });59}6061export async function isQuartz(): Promise<boolean> {62 return usingApi(async api => {63 const chain = await api.rpc.system.chain();64 65 return chain.eq('QUARTZ');66 });67}6869let modulesNames: any;70export function getModuleNames(api: ApiPromise): string[] {71 if (typeof modulesNames === 'undefined') 72 modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());73 return modulesNames;74}7576export async function missingRequiredPallets(requiredPallets: string[]): Promise<string[]> {77 return await usingApi(async api => {78 const pallets = getModuleNames(api);7980 return requiredPallets.filter(p => !pallets.includes(p));81 });82}8384export async function checkPalletsPresence(requiredPallets: string[]): Promise<boolean> {85 return (await missingRequiredPallets(requiredPallets)).length == 0;86}8788export async function requirePallets(mocha: Context, requiredPallets: string[]) {89 const missingPallets = await missingRequiredPallets(requiredPallets);9091 if (missingPallets.length > 0) {92 const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`;93 const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;94 const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`;9596 console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg);9798 mocha.skip();99 }100}101102export function bigIntToSub(api: ApiPromise, number: bigint) {103 return api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();104}105106export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {107 if (typeof input === 'string') {108 if (input.length >= 47) {109 return {Substrate: input};110 } else if (input.length === 42 && input.startsWith('0x')) {111 return {Ethereum: input.toLowerCase()};112 } else if (input.length === 40 && !input.startsWith('0x')) {113 return {Ethereum: '0x' + input.toLowerCase()};114 } else {115 throw new Error(`Unknown address format: "${input}"`);116 }117 }118 if ('address' in input) {119 return {Substrate: input.address};120 }121 if ('Ethereum' in input) {122 return {123 Ethereum: input.Ethereum.toLowerCase(),124 };125 } else if ('ethereum' in input) {126 return {127 Ethereum: (input as any).ethereum.toLowerCase(),128 };129 } else if ('Substrate' in input) {130 return input;131 } else if ('substrate' in input) {132 return {133 Substrate: (input as any).substrate,134 };135 }136137 // AccountId138 return {Substrate: input.toString()};139}140export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {141 input = normalizeAccountId(input);142 if ('Substrate' in input) {143 return input.Substrate;144 } else {145 return evmToAddress(input.Ethereum);146 }147}148149export const U128_MAX = (1n << 128n) - 1n;150151const MICROUNIQUE = 1_000_000_000_000n;152const MILLIUNIQUE = 1_000n * MICROUNIQUE;153const CENTIUNIQUE = 10n * MILLIUNIQUE;154export const UNIQUE = 100n * CENTIUNIQUE;155156interface GenericResult<T> {157 success: boolean;158 data: T | null;159}160161interface CreateCollectionResult {162 success: boolean;163 collectionId: number;164}165166interface CreateItemResult {167 success: boolean;168 collectionId: number;169 itemId: number;170 recipient?: CrossAccountId;171 amount?: number;172}173174interface DestroyItemResult {175 success: boolean;176 collectionId: number;177 itemId: number;178 owner: CrossAccountId;179 amount: number;180}181182interface TransferResult {183 collectionId: number;184 itemId: number;185 sender?: CrossAccountId;186 recipient?: CrossAccountId;187 value: bigint;188}189190interface IReFungibleOwner {191 fraction: BN;192 owner: number[];193}194195interface IGetMessage {196 checkMsgUnqMethod: string;197 checkMsgTrsMethod: string;198 checkMsgSysMethod: string;199}200201export interface IFungibleTokenDataType {202 value: number;203}204205export interface IChainLimits {206 collectionNumbersLimit: number;207 accountTokenOwnershipLimit: number;208 collectionsAdminsLimit: number;209 customDataLimit: number;210 nftSponsorTransferTimeout: number;211 fungibleSponsorTransferTimeout: number;212 refungibleSponsorTransferTimeout: number;213 //offchainSchemaLimit: number;214 //constOnChainSchemaLimit: number;215}216217export interface IReFungibleTokenDataType {218 owner: IReFungibleOwner[];219}220221export function uniqueEventMessage(events: EventRecord[]): IGetMessage {222 let checkMsgUnqMethod = '';223 let checkMsgTrsMethod = '';224 let checkMsgSysMethod = '';225 events.forEach(({event: {method, section}}) => {226 if (section === 'common') {227 checkMsgUnqMethod = method;228 } else if (section === 'treasury') {229 checkMsgTrsMethod = method;230 } else if (section === 'system') {231 checkMsgSysMethod = method;232 } else { return null; }233 });234 const result: IGetMessage = {235 checkMsgUnqMethod,236 checkMsgTrsMethod,237 checkMsgSysMethod,238 };239 return result;240}241242export function getEvent<T extends Event>(events: EventRecord[], check: (event: IEvent<AnyTuple>) => event is T): T | undefined {243 const event = events.find(r => check(r.event));244 if (!event) return;245 return event.event as T;246}247248export function getGenericResult<T>(events: EventRecord[]): GenericResult<T>;249export function getGenericResult<T>(250 events: EventRecord[],251 expectSection: string,252 expectMethod: string,253 extractAction: (data: GenericEventData) => T254): GenericResult<T>;255256export function getGenericResult<T>(257 events: EventRecord[],258 expectSection?: string,259 expectMethod?: string,260 extractAction?: (data: GenericEventData) => T,261): GenericResult<T> {262 let success = false;263 let successData = null;264265 events.forEach(({event: {data, method, section}}) => {266 // console.log(` ${phase}: ${section}.${method}:: ${data}`);267 if (method === 'ExtrinsicSuccess') {268 success = true;269 } else if ((expectSection == section) && (expectMethod == method)) {270 successData = extractAction!(data as any);271 }272 });273274 const result: GenericResult<T> = {275 success,276 data: successData,277 };278 return result;279}280281export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {282 const genericResult = getGenericResult(events, 'common', 'CollectionCreated', (data) => parseInt(data[0].toString(), 10));283 const result: CreateCollectionResult = {284 success: genericResult.success,285 collectionId: genericResult.data ?? 0,286 };287 return result;288}289290export function getCreateItemsResult(events: EventRecord[]): CreateItemResult[] {291 const results: CreateItemResult[] = [];292 293 const genericResult = getGenericResult<CreateItemResult[]>(events, 'common', 'ItemCreated', (data) => {294 const collectionId = parseInt(data[0].toString(), 10);295 const itemId = parseInt(data[1].toString(), 10);296 const recipient = normalizeAccountId(data[2].toJSON() as any);297 const amount = parseInt(data[3].toString(), 10);298299 const itemRes: CreateItemResult = {300 success: true,301 collectionId,302 itemId,303 recipient,304 amount,305 };306307 results.push(itemRes);308 return results;309 });310311 if (!genericResult.success) return [];312 return results;313}314315export function getCreateItemResult(events: EventRecord[]): CreateItemResult {316 const genericResult = getGenericResult(events, 'common', 'ItemCreated', (data) => data.map(function(value) { return value.toJSON(); }));317 318 if (genericResult.data == null) 319 return {320 success: genericResult.success,321 collectionId: 0,322 itemId: 0,323 amount: 0,324 };325 else 326 return {327 success: genericResult.success,328 collectionId: genericResult.data[0] as number,329 itemId: genericResult.data[1] as number,330 recipient: normalizeAccountId(genericResult.data![2] as any),331 amount: genericResult.data[3] as number,332 };333}334335export function getDestroyItemsResult(events: EventRecord[]): DestroyItemResult[] {336 const results: DestroyItemResult[] = [];337 338 const genericResult = getGenericResult<DestroyItemResult[]>(events, 'common', 'ItemDestroyed', (data) => {339 const collectionId = parseInt(data[0].toString(), 10);340 const itemId = parseInt(data[1].toString(), 10);341 const owner = normalizeAccountId(data[2].toJSON() as any);342 const amount = parseInt(data[3].toString(), 10);343344 const itemRes: DestroyItemResult = {345 success: true,346 collectionId,347 itemId,348 owner,349 amount,350 };351352 results.push(itemRes);353 return results;354 });355356 if (!genericResult.success) return [];357 return results;358}359360export function getTransferResult(api: ApiPromise, events: EventRecord[]): TransferResult {361 for (const {event} of events) {362 if (api.events.common.Transfer.is(event)) {363 const [collection, token, sender, recipient, value] = event.data;364 return {365 collectionId: collection.toNumber(),366 itemId: token.toNumber(),367 sender: normalizeAccountId(sender.toJSON() as any),368 recipient: normalizeAccountId(recipient.toJSON() as any),369 value: value.toBigInt(),370 };371 }372 }373 throw new Error('no transfer event');374}375376interface Nft {377 type: 'NFT';378}379380interface Fungible {381 type: 'Fungible';382 decimalPoints: number;383}384385interface ReFungible {386 type: 'ReFungible';387}388389export type CollectionMode = Nft | Fungible | ReFungible;390391export type Property = {392 key: any,393 value: any,394};395396type Permission = {397 mutable: boolean;398 collectionAdmin: boolean;399 tokenOwner: boolean;400}401402type PropertyPermission = {403 key: any;404 permission: Permission;405}406407export type CreateCollectionParams = {408 mode: CollectionMode,409 name: string,410 description: string,411 tokenPrefix: string,412 properties?: Array<Property>,413 propPerm?: Array<PropertyPermission>414};415416const defaultCreateCollectionParams: CreateCollectionParams = {417 description: 'description',418 mode: {type: 'NFT'},419 name: 'name',420 tokenPrefix: 'prefix',421};422423export async function424createCollection(425 api: ApiPromise,426 sender: IKeyringPair,427 params: Partial<CreateCollectionParams> = {},428): Promise<CreateCollectionResult> {429 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};430431 let modeprm = {};432 if (mode.type === 'NFT') {433 modeprm = {nft: null};434 } else if (mode.type === 'Fungible') {435 modeprm = {fungible: mode.decimalPoints};436 } else if (mode.type === 'ReFungible') {437 modeprm = {refungible: null};438 }439440 const tx = api.tx.unique.createCollectionEx({441 name: strToUTF16(name),442 description: strToUTF16(description),443 tokenPrefix: strToUTF16(tokenPrefix),444 mode: modeprm as any,445 });446 const events = await executeTransaction(api, sender, tx);447 return getCreateCollectionResult(events);448}449450export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {451 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};452453 let collectionId = 0;454 await usingApi(async (api, privateKeyWrapper) => {455 // Get number of collections before the transaction456 const collectionCountBefore = await getCreatedCollectionCount(api);457458 // Run the CreateCollection transaction459 const alicePrivateKey = privateKeyWrapper('//Alice');460461 const result = await createCollection(api, alicePrivateKey, params);462463 // Get number of collections after the transaction464 const collectionCountAfter = await getCreatedCollectionCount(api);465466 // Get the collection467 const collection = await queryCollectionExpectSuccess(api, result.collectionId);468469 // What to expect470 // tslint:disable-next-line:no-unused-expression471 expect(result.success).to.be.true;472 expect(result.collectionId).to.be.equal(collectionCountAfter);473 // tslint:disable-next-line:no-unused-expression474 expect(collection).to.be.not.null;475 expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');476 expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey));477 expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);478 expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);479 expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);480481 collectionId = result.collectionId;482 });483484 return collectionId;485}486487export async function createCollectionWithPropsExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {488 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};489490 let collectionId = 0;491 await usingApi(async (api, privateKeyWrapper) => {492 // Get number of collections before the transaction493 const collectionCountBefore = await getCreatedCollectionCount(api);494495 // Run the CreateCollection transaction496 const alicePrivateKey = privateKeyWrapper('//Alice');497498 let modeprm = {};499 if (mode.type === 'NFT') {500 modeprm = {nft: null};501 } else if (mode.type === 'Fungible') {502 modeprm = {fungible: mode.decimalPoints};503 } else if (mode.type === 'ReFungible') {504 modeprm = {refungible: null};505 }506507 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});508 const events = await submitTransactionAsync(alicePrivateKey, tx);509 const result = getCreateCollectionResult(events);510511 // Get number of collections after the transaction512 const collectionCountAfter = await getCreatedCollectionCount(api);513514 // Get the collection515 const collection = await queryCollectionExpectSuccess(api, result.collectionId);516517 // What to expect518 // tslint:disable-next-line:no-unused-expression519 expect(result.success).to.be.true;520 expect(result.collectionId).to.be.equal(collectionCountAfter);521 // tslint:disable-next-line:no-unused-expression522 expect(collection).to.be.not.null;523 expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');524 expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey));525 expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);526 expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);527 expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);528529530 collectionId = result.collectionId;531 });532533 return collectionId;534}535536export async function createCollectionWithPropsExpectFailure(params: Partial<CreateCollectionParams> = {}) {537 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};538539 await usingApi(async (api, privateKeyWrapper) => {540 // Get number of collections before the transaction541 const collectionCountBefore = await getCreatedCollectionCount(api);542543 // Run the CreateCollection transaction544 const alicePrivateKey = privateKeyWrapper('//Alice');545546 let modeprm = {};547 if (mode.type === 'NFT') {548 modeprm = {nft: null};549 } else if (mode.type === 'Fungible') {550 modeprm = {fungible: mode.decimalPoints};551 } else if (mode.type === 'ReFungible') {552 modeprm = {refungible: null};553 }554555 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});556 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;557558559 // Get number of collections after the transaction560 const collectionCountAfter = await getCreatedCollectionCount(api);561562 expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');563 });564}565566export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {567 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};568569 let modeprm = {};570 if (mode.type === 'NFT') {571 modeprm = {nft: null};572 } else if (mode.type === 'Fungible') {573 modeprm = {fungible: mode.decimalPoints};574 } else if (mode.type === 'ReFungible') {575 modeprm = {refungible: null};576 }577578 await usingApi(async (api, privateKeyWrapper) => {579 // Get number of collections before the transaction580 const collectionCountBefore = await getCreatedCollectionCount(api);581582 // Run the CreateCollection transaction583 const alicePrivateKey = privateKeyWrapper('//Alice');584 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any});585 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;586587 // Get number of collections after the transaction588 const collectionCountAfter = await getCreatedCollectionCount(api);589590 // What to expect591 expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');592 });593}594595export async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise<IKeyringPair> {596 let bal = 0n;597 let unused;598 do {599 const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;600 unused = privateKeyWrapper(`//${randomSeed}`);601 bal = (await api.query.system.account(unused.address)).data.free.toBigInt();602 } while (bal !== 0n);603 return unused;604}605606export async function getAllowance(api: ApiPromise, collectionId: number, owner: CrossAccountId | string | IKeyringPair, approved: CrossAccountId | string | IKeyringPair, tokenId: number) {607 return (await api.rpc.unique.allowance(collectionId, normalizeAccountId(owner), normalizeAccountId(approved), tokenId)).toBigInt();608}609610export function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise<IKeyringPair[]> {611 return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now())));612}613614export async function findNotExistingCollection(api: ApiPromise): Promise<number> {615 const totalNumber = await getCreatedCollectionCount(api);616 const newCollection: number = totalNumber + 1;617 return newCollection;618}619620function getDestroyResult(events: EventRecord[]): boolean {621 let success = false;622 events.forEach(({event: {method}}) => {623 if (method == 'ExtrinsicSuccess') {624 success = true;625 }626 });627 return success;628}629630export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {631 await usingApi(async (api, privateKeyWrapper) => {632 // Run the DestroyCollection transaction633 const alicePrivateKey = privateKeyWrapper(senderSeed);634 const tx = api.tx.unique.destroyCollection(collectionId);635 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;636 });637}638639export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {640 await usingApi(async (api, privateKeyWrapper) => {641 // Run the DestroyCollection transaction642 const alicePrivateKey = privateKeyWrapper(senderSeed);643 const tx = api.tx.unique.destroyCollection(collectionId);644 const events = await submitTransactionAsync(alicePrivateKey, tx);645 const result = getDestroyResult(events);646 expect(result).to.be.true;647648 // What to expect649 expect(await getDetailedCollectionInfo(api, collectionId)).to.be.null;650 });651}652653export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {654 await usingApi(async (api) => {655 const tx = api.tx.unique.setCollectionLimits(collectionId, limits);656 const events = await submitTransactionAsync(sender, tx);657 const result = getGenericResult(events);658659 expect(result.success).to.be.true;660 });661}662663export const setCollectionPermissionsExpectSuccess = async (sender: IKeyringPair, collectionId: number, permissions: any) => {664 await usingApi(async(api) => {665 const tx = api.tx.unique.setCollectionPermissions(collectionId, permissions);666 const events = await submitTransactionAsync(sender, tx);667 const result = getGenericResult(events);668669 expect(result.success).to.be.true;670 });671};672673export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {674 await usingApi(async (api) => {675 const tx = api.tx.unique.setCollectionLimits(collectionId, limits);676 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;677 const result = getGenericResult(events);678679 expect(result.success).to.be.false;680 });681}682683export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {684 await usingApi(async (api, privateKeyWrapper) => {685686 // Run the transaction687 const senderPrivateKey = privateKeyWrapper(sender);688 const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor);689 const events = await submitTransactionAsync(senderPrivateKey, tx);690 const result = getGenericResult(events);691692 // Get the collection693 const collection = await queryCollectionExpectSuccess(api, collectionId);694695 // What to expect696 expect(result.success).to.be.true;697 expect(collection.sponsorship.toJSON()).to.deep.equal({698 unconfirmed: sponsor,699 });700 });701}702703export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {704 await usingApi(async (api, privateKeyWrapper) => {705706 // Run the transaction707 const alicePrivateKey = privateKeyWrapper(sender);708 const tx = api.tx.unique.removeCollectionSponsor(collectionId);709 const events = await submitTransactionAsync(alicePrivateKey, tx);710 const result = getGenericResult(events);711712 // Get the collection713 const collection = await queryCollectionExpectSuccess(api, collectionId);714715 // What to expect716 expect(result.success).to.be.true;717 expect(collection.sponsorship.toJSON()).to.be.deep.equal({disabled: null});718 });719}720721export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {722 await usingApi(async (api, privateKeyWrapper) => {723724 // Run the transaction725 const alicePrivateKey = privateKeyWrapper(senderSeed);726 const tx = api.tx.unique.removeCollectionSponsor(collectionId);727 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;728 });729}730731export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {732 await usingApi(async (api, privateKeyWrapper) => {733734 // Run the transaction735 const alicePrivateKey = privateKeyWrapper(senderSeed);736 const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor);737 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;738 });739}740741export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {742 await usingApi(async (api, privateKeyWrapper) => {743744 // Run the transaction745 const sender = privateKeyWrapper(senderSeed);746 await confirmSponsorshipByKeyExpectSuccess(collectionId, sender);747 });748}749750export async function confirmSponsorshipByKeyExpectSuccess(collectionId: number, sender: IKeyringPair) {751 await usingApi(async (api, privateKeyWrapper) => {752753 // Run the transaction754 const tx = api.tx.unique.confirmSponsorship(collectionId);755 const events = await submitTransactionAsync(sender, tx);756 const result = getGenericResult(events);757758 // Get the collection759 const collection = await queryCollectionExpectSuccess(api, collectionId);760761 // What to expect762 expect(result.success).to.be.true;763 expect(collection.sponsorship.toJSON()).to.be.deep.equal({764 confirmed: sender.address,765 });766 });767}768769770export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {771 await usingApi(async (api, privateKeyWrapper) => {772773 // Run the transaction774 const sender = privateKeyWrapper(senderSeed);775 const tx = api.tx.unique.confirmSponsorship(collectionId);776 await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;777 });778}779780export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {781 await usingApi(async (api) => {782 const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);783 const events = await submitTransactionAsync(sender, tx);784 const result = getGenericResult(events);785786 expect(result.success).to.be.true;787 });788}789790export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {791 await usingApi(async (api) => {792 const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);793 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;794 const result = getGenericResult(events);795796 expect(result.success).to.be.false;797 });798}799800export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {801802 await usingApi(async (api) => {803804 const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled);805 const events = await submitTransactionAsync(sender, tx);806 const result = getGenericResult(events);807808 expect(result.success).to.be.true;809 });810}811812export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {813814 await usingApi(async (api) => {815816 const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled);817 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;818 const result = getGenericResult(events);819820 expect(result.success).to.be.false;821 });822}823824export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {825 await usingApi(async (api) => {826 const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit);827 const events = await submitTransactionAsync(sender, tx);828 const result = getGenericResult(events);829830 expect(result.success).to.be.true;831 });832}833834export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {835 await usingApi(async (api) => {836 const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit);837 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;838 const result = getGenericResult(events);839840 expect(result.success).to.be.false;841 });842}843844export async function getNextSponsored(845 api: ApiPromise,846 collectionId: number,847 account: string | CrossAccountId,848 tokenId: number,849): Promise<number> {850 return Number((await api.rpc.unique.nextSponsored(collectionId, account, tokenId)).unwrapOr(-1));851}852853export async function toggleContractAllowlistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {854 await usingApi(async (api) => {855 const tx = api.tx.unique.toggleContractAllowList(contractAddress, value);856 const events = await submitTransactionAsync(sender, tx);857 const result = getGenericResult(events);858859 expect(result.success).to.be.true;860 });861}862863export async function isAllowlistedInContract(contractAddress: AccountId | string, user: string) {864 let allowlisted = false;865 await usingApi(async (api) => {866 allowlisted = (await api.query.unique.contractAllowList(contractAddress, user)).toJSON() as boolean;867 });868 return allowlisted;869}870871export async function addToContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {872 await usingApi(async (api) => {873 const tx = api.tx.unique.addToContractAllowList(contractAddress.toString(), user.toString());874 const events = await submitTransactionAsync(sender, tx);875 const result = getGenericResult(events);876877 expect(result.success).to.be.true;878 });879}880881export async function removeFromContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {882 await usingApi(async (api) => {883 const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString());884 const events = await submitTransactionAsync(sender, tx);885 const result = getGenericResult(events);886887 expect(result.success).to.be.true;888 });889}890891export async function removeFromContractAllowListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {892 await usingApi(async (api) => {893 const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString());894 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;895 const result = getGenericResult(events);896897 expect(result.success).to.be.false;898 });899}900901export interface CreateFungibleData {902 readonly Value: bigint;903}904905export interface CreateReFungibleData { }906export interface CreateNftData { }907908export type CreateItemData = {909 NFT: CreateNftData;910} | {911 Fungible: CreateFungibleData;912} | {913 ReFungible: CreateReFungibleData;914};915916export async function burnItem(api: ApiPromise, sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint) : Promise<boolean> {917 const tx = api.tx.unique.burnItem(collectionId, tokenId, value);918 const events = await submitTransactionAsync(sender, tx);919 return getGenericResult(events).success;920}921922export async function burnItemExpectSuccess(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) {923 await usingApi(async (api) => {924 const balanceBefore = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId);925 // if burning token by admin - use adminButnItemExpectSuccess926 expect(balanceBefore >= BigInt(value)).to.be.true;927928 expect(await burnItem(api, sender, collectionId, tokenId, value)).to.be.true;929930 const balanceAfter = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId);931 expect(balanceAfter + BigInt(value)).to.be.equal(balanceBefore);932 });933}934935export async function burnItemExpectFailure(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) {936 await usingApi(async (api) => {937 const tx = api.tx.unique.burnItem(collectionId, tokenId, value);938939 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;940 const result = getCreateCollectionResult(events);941 // tslint:disable-next-line:no-unused-expression942 expect(result.success).to.be.false;943 });944}945946export async function burnFromExpectSuccess(sender: IKeyringPair, from: IKeyringPair | CrossAccountId, collectionId: number, tokenId: number, value: number | bigint = 1) {947 await usingApi(async (api) => {948 const tx = api.tx.unique.burnFrom(collectionId, normalizeAccountId(from), tokenId, value);949 const events = await submitTransactionAsync(sender, tx);950 return getGenericResult(events).success;951 });952}953954export async function955approve(956 api: ApiPromise,957 collectionId: number,958 tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string | IKeyringPair, amount: number | bigint,959) {960 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);961 const events = await submitTransactionAsync(owner, approveUniqueTx);962 return getGenericResult(events).success;963}964965export async function966approveExpectSuccess(967 collectionId: number,968 tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string, amount: number | bigint = 1,969) {970 await usingApi(async (api: ApiPromise) => {971 const result = await approve(api, collectionId, tokenId, owner, approved, amount);972 expect(result).to.be.true;973974 expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));975 });976}977978export async function adminApproveFromExpectSuccess(979 collectionId: number,980 tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,981) {982 await usingApi(async (api: ApiPromise) => {983 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);984 const events = await submitTransactionAsync(admin, approveUniqueTx);985 const result = getGenericResult(events);986 expect(result.success).to.be.true;987988 expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));989 });990}991992export async function993transferFrom(994 api: ApiPromise,995 collectionId: number,996 tokenId: number,997 accountApproved: IKeyringPair,998 accountFrom: IKeyringPair | CrossAccountId,999 accountTo: IKeyringPair | CrossAccountId,1000 value: number | bigint,1001) {1002 const from = normalizeAccountId(accountFrom);1003 const to = normalizeAccountId(accountTo);1004 const transferFromTx = api.tx.unique.transferFrom(from, to, collectionId, tokenId, value);1005 const events = await submitTransactionAsync(accountApproved, transferFromTx);1006 return getGenericResult(events).success;1007}10081009export async function1010transferFromExpectSuccess(1011 collectionId: number,1012 tokenId: number,1013 accountApproved: IKeyringPair,1014 accountFrom: IKeyringPair | CrossAccountId,1015 accountTo: IKeyringPair | CrossAccountId,1016 value: number | bigint = 1,1017 type = 'NFT',1018) {1019 await usingApi(async (api: ApiPromise) => {1020 const from = normalizeAccountId(accountFrom);1021 const to = normalizeAccountId(accountTo);1022 let balanceBefore = 0n;1023 if (type === 'Fungible' || type === 'ReFungible') {1024 balanceBefore = await getBalance(api, collectionId, to, tokenId);1025 }1026 expect(await transferFrom(api, collectionId, tokenId, accountApproved, accountFrom, accountTo, value)).to.be.true;1027 if (type === 'NFT') {1028 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);1029 }1030 if (type === 'Fungible') {1031 const balanceAfter = await getBalance(api, collectionId, to, tokenId);1032 if (JSON.stringify(to) !== JSON.stringify(from)) {1033 expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value));1034 } else {1035 expect(balanceAfter).to.be.equal(balanceBefore);1036 }1037 }1038 if (type === 'ReFungible') {1039 expect(await getBalance(api, collectionId, to, tokenId)).to.be.equal(balanceBefore + BigInt(value));1040 }1041 });1042}10431044export async function1045transferFromExpectFail(1046 collectionId: number,1047 tokenId: number,1048 accountApproved: IKeyringPair,1049 accountFrom: IKeyringPair,1050 accountTo: IKeyringPair,1051 value: number | bigint = 1,1052) {1053 await usingApi(async (api: ApiPromise) => {1054 const transferFromTx = api.tx.unique.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);1055 const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;1056 const result = getCreateCollectionResult(events);1057 // tslint:disable-next-line:no-unused-expression1058 expect(result.success).to.be.false;1059 });1060}10611062/* eslint no-async-promise-executor: "off" */1063export async function getBlockNumber(api: ApiPromise): Promise<number> {1064 return new Promise<number>(async (resolve) => {1065 const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {1066 unsubscribe();1067 resolve(head.number.toNumber());1068 });1069 });1070}10711072export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | CrossAccountId) {1073 await usingApi(async (api) => {1074 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(address));1075 const events = await submitTransactionAsync(sender, changeAdminTx);1076 const result = getCreateCollectionResult(events);1077 expect(result.success).to.be.true;1078 });1079}10801081export async function adminApproveFromExpectFail(1082 collectionId: number,1083 tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,1084) {1085 await usingApi(async (api: ApiPromise) => {1086 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);1087 const events = await expect(submitTransactionAsync(admin, approveUniqueTx)).to.be.rejected;1088 const result = getGenericResult(events);1089 expect(result.success).to.be.false;1090 });1091}10921093export async function1094getFreeBalance(account: IKeyringPair): Promise<bigint> {1095 let balance = 0n;1096 await usingApi(async (api) => {1097 balance = BigInt((await api.query.system.account(account.address)).data.free.toString());1098 });10991100 return balance;1101}11021103export async function transferBalanceTo(api: ApiPromise, source: IKeyringPair, target: string, amount = 1000n * UNIQUE) {1104 const tx = api.tx.balances.transfer(target, amount);1105 const events = await submitTransactionAsync(source, tx);1106 const result = getGenericResult(events);1107 expect(result.success).to.be.true;1108}11091110export async function1111scheduleExpectSuccess(1112 operationTx: any,1113 sender: IKeyringPair,1114 blockSchedule: number,1115 scheduledId: string,1116 period = 1,1117 repetitions = 1,1118) {1119 await usingApi(async (api: ApiPromise) => {1120 const blockNumber: number | undefined = await getBlockNumber(api);1121 const expectedBlockNumber = blockNumber + blockSchedule;11221123 expect(blockNumber).to.be.greaterThan(0);1124 const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule1125 scheduledId,1126 expectedBlockNumber, 1127 repetitions > 1 ? [period, repetitions] : null, 1128 0, 1129 {Value: operationTx as any},1130 );11311132 const events = await submitTransactionAsync(sender, scheduleTx);1133 expect(getGenericResult(events).success).to.be.true;1134 });1135}11361137export async function1138scheduleExpectFailure(1139 operationTx: any,1140 sender: IKeyringPair,1141 blockSchedule: number,1142 scheduledId: string,1143 period = 1,1144 repetitions = 1,1145) {1146 await usingApi(async (api: ApiPromise) => {1147 const blockNumber: number | undefined = await getBlockNumber(api);1148 const expectedBlockNumber = blockNumber + blockSchedule;11491150 expect(blockNumber).to.be.greaterThan(0);1151 const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule1152 scheduledId,1153 expectedBlockNumber, 1154 repetitions <= 1 ? null : [period, repetitions], 1155 0, 1156 {Value: operationTx as any},1157 );11581159 //const events = 1160 await expect(submitTransactionExpectFailAsync(sender, scheduleTx)).to.be.rejected;1161 //expect(getGenericResult(events).success).to.be.false;1162 });1163}11641165export async function1166scheduleTransferAndWaitExpectSuccess(1167 collectionId: number,1168 tokenId: number,1169 sender: IKeyringPair,1170 recipient: IKeyringPair,1171 value: number | bigint = 1,1172 blockSchedule: number,1173 scheduledId: string,1174) {1175 await usingApi(async (api: ApiPromise) => {1176 await scheduleTransferExpectSuccess(collectionId, tokenId, sender, recipient, value, blockSchedule, scheduledId);11771178 const recipientBalanceBefore = (await api.query.system.account(recipient.address)).data.free.toBigInt();11791180 // sleep for n + 1 blocks1181 await waitNewBlocks(blockSchedule + 1);11821183 const recipientBalanceAfter = (await api.query.system.account(recipient.address)).data.free.toBigInt();11841185 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(recipient.address));1186 expect(recipientBalanceAfter).to.be.equal(recipientBalanceBefore);1187 });1188}11891190export async function1191scheduleTransferExpectSuccess(1192 collectionId: number,1193 tokenId: number,1194 sender: IKeyringPair,1195 recipient: IKeyringPair,1196 value: number | bigint = 1,1197 blockSchedule: number,1198 scheduledId: string,1199) {1200 await usingApi(async (api: ApiPromise) => {1201 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);12021203 await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId);12041205 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(sender.address));1206 });1207}12081209export async function1210scheduleTransferFundsPeriodicExpectSuccess(1211 amount: bigint,1212 sender: IKeyringPair,1213 recipient: IKeyringPair,1214 blockSchedule: number,1215 scheduledId: string,1216 period: number,1217 repetitions: number,1218) {1219 await usingApi(async (api: ApiPromise) => {1220 const transferTx = api.tx.balances.transfer(recipient.address, amount);12211222 const balanceBefore = await getFreeBalance(recipient);1223 1224 await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId, period, repetitions);12251226 expect(await getFreeBalance(recipient)).to.be.equal(balanceBefore);1227 });1228}12291230export async function1231transfer(1232 api: ApiPromise,1233 collectionId: number,1234 tokenId: number,1235 sender: IKeyringPair,1236 recipient: IKeyringPair | CrossAccountId,1237 value: number | bigint,1238) : Promise<boolean> {1239 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);1240 const events = await executeTransaction(api, sender, transferTx);1241 return getGenericResult(events).success;1242}12431244export async function1245transferExpectSuccess(1246 collectionId: number,1247 tokenId: number,1248 sender: IKeyringPair,1249 recipient: IKeyringPair | CrossAccountId,1250 value: number | bigint = 1,1251 type = 'NFT',1252) {1253 await usingApi(async (api: ApiPromise) => {1254 const from = normalizeAccountId(sender);1255 const to = normalizeAccountId(recipient);12561257 let balanceBefore = 0n;1258 if (type === 'Fungible' || type === 'ReFungible') {1259 balanceBefore = await getBalance(api, collectionId, to, tokenId);1260 }12611262 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);1263 const events = await executeTransaction(api, sender, transferTx);1264 const result = getTransferResult(api, events);12651266 expect(result.collectionId).to.be.equal(collectionId);1267 expect(result.itemId).to.be.equal(tokenId);1268 expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));1269 expect(result.recipient).to.be.deep.equal(to);1270 expect(result.value).to.be.equal(BigInt(value));12711272 if (type === 'NFT') {1273 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);1274 }1275 if (type === 'Fungible' || type === 'ReFungible') {1276 const balanceAfter = await getBalance(api, collectionId, to, tokenId);1277 if (JSON.stringify(to) !== JSON.stringify(from)) {1278 expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value));1279 } else {1280 expect(balanceAfter).to.be.equal(balanceBefore);1281 }1282 }1283 });1284}12851286export async function1287transferExpectFailure(1288 collectionId: number,1289 tokenId: number,1290 sender: IKeyringPair,1291 recipient: IKeyringPair | CrossAccountId,1292 value: number | bigint = 1,1293) {1294 await usingApi(async (api: ApiPromise) => {1295 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);1296 const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;1297 const result = getGenericResult(events);1298 // if (events && Array.isArray(events)) {1299 // const result = getCreateCollectionResult(events);1300 // tslint:disable-next-line:no-unused-expression1301 expect(result.success).to.be.false;1302 //}1303 });1304}13051306export async function1307approveExpectFail(1308 collectionId: number,1309 tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,1310) {1311 await usingApi(async (api: ApiPromise) => {1312 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);1313 const events = await expect(submitTransactionExpectFailAsync(owner, approveUniqueTx)).to.be.rejected;1314 const result = getCreateCollectionResult(events);1315 // tslint:disable-next-line:no-unused-expression1316 expect(result.success).to.be.false;1317 });1318}13191320export async function getBalance(1321 api: ApiPromise,1322 collectionId: number,1323 owner: string | CrossAccountId | IKeyringPair,1324 token: number,1325): Promise<bigint> {1326 return (await api.rpc.unique.balance(collectionId, normalizeAccountId(owner), token)).toBigInt();1327}1328export async function getTokenOwner(1329 api: ApiPromise,1330 collectionId: number,1331 token: number,1332): Promise<CrossAccountId> {1333 const owner = (await api.rpc.unique.tokenOwner(collectionId, token)).toJSON() as any;1334 if (owner == null) throw new Error('owner == null');1335 return normalizeAccountId(owner);1336}1337export async function getTopmostTokenOwner(1338 api: ApiPromise,1339 collectionId: number,1340 token: number,1341): Promise<CrossAccountId> {1342 const owner = (await api.rpc.unique.topmostTokenOwner(collectionId, token)).toJSON() as any;1343 if (owner == null) throw new Error('owner == null');1344 return normalizeAccountId(owner);1345}1346export async function getTokenChildren(1347 api: ApiPromise,1348 collectionId: number,1349 tokenId: number,1350): Promise<UpDataStructsTokenChild[]> {1351 return (await api.rpc.unique.tokenChildren(collectionId, tokenId)).toJSON() as any;1352}1353export async function isTokenExists(1354 api: ApiPromise,1355 collectionId: number,1356 token: number,1357): Promise<boolean> {1358 return (await api.rpc.unique.tokenExists(collectionId, token)).toJSON();1359}1360export async function getLastTokenId(1361 api: ApiPromise,1362 collectionId: number,1363): Promise<number> {1364 return (await api.rpc.unique.lastTokenId(collectionId)).toJSON();1365}1366export async function getAdminList(1367 api: ApiPromise,1368 collectionId: number,1369): Promise<string[]> {1370 return (await api.rpc.unique.adminlist(collectionId)).toHuman() as any;1371}1372export async function getTokenProperties(1373 api: ApiPromise,1374 collectionId: number,1375 tokenId: number,1376 propertyKeys: string[],1377): Promise<UpDataStructsProperty[]> {1378 return (await api.rpc.unique.tokenProperties(collectionId, tokenId, propertyKeys)).toHuman() as any;1379}13801381export async function createFungibleItemExpectSuccess(1382 sender: IKeyringPair,1383 collectionId: number,1384 data: CreateFungibleData,1385 owner: CrossAccountId | string = sender.address,1386) {1387 return await usingApi(async (api) => {1388 const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), {Fungible: data});13891390 const events = await submitTransactionAsync(sender, tx);1391 const result = getCreateItemResult(events);13921393 expect(result.success).to.be.true;1394 return result.itemId;1395 });1396}13971398export async function createMultipleItemsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {1399 await usingApi(async (api) => {1400 const to = normalizeAccountId(owner);1401 const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);14021403 const events = await submitTransactionAsync(sender, tx);1404 expect(getGenericResult(events).success).to.be.true;1405 });1406}14071408export async function createMultipleItemsWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {1409 await usingApi(async (api) => {1410 const to = normalizeAccountId(owner);1411 const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);14121413 const events = await submitTransactionAsync(sender, tx);1414 const result = getCreateItemsResult(events);14151416 for (const res of result) {1417 expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty;1418 }1419 });1420}14211422export async function createMultipleItemsExWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any) {1423 await usingApi(async (api) => {1424 const tx = api.tx.unique.createMultipleItemsEx(collectionId, itemsData);14251426 const events = await submitTransactionAsync(sender, tx);1427 const result = getCreateItemsResult(events);14281429 for (const res of result) {1430 expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty;1431 }1432 });1433}14341435export async function createItemWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, props: Array<Property>, owner: CrossAccountId | string = sender.address) {1436 let newItemId = 0;1437 await usingApi(async (api) => {1438 const to = normalizeAccountId(owner);1439 const itemCountBefore = await getLastTokenId(api, collectionId);1440 const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId);14411442 let tx;1443 if (createMode === 'Fungible') {1444 const createData = {fungible: {value: 10}};1445 tx = api.tx.unique.createItem(collectionId, to, createData as any);1446 } else if (createMode === 'ReFungible') {1447 const createData = {refungible: {pieces: 100}};1448 tx = api.tx.unique.createItem(collectionId, to, createData as any);1449 } else {1450 const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}});1451 tx = api.tx.unique.createItem(collectionId, to, data as UpDataStructsCreateItemData);1452 }14531454 const events = await submitTransactionAsync(sender, tx);1455 const result = getCreateItemResult(events);14561457 const itemCountAfter = await getLastTokenId(api, collectionId);1458 const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId);14591460 if (createMode === 'NFT') {1461 expect(await api.rpc.unique.tokenProperties(collectionId, result.itemId)).not.to.be.empty;1462 }14631464 // What to expect1465 // tslint:disable-next-line:no-unused-expression1466 expect(result.success).to.be.true;1467 if (createMode === 'Fungible') {1468 expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);1469 } else {1470 expect(itemCountAfter).to.be.equal(itemCountBefore + 1);1471 }1472 expect(collectionId).to.be.equal(result.collectionId);1473 expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());1474 expect(to).to.be.deep.equal(result.recipient);1475 newItemId = result.itemId;1476 });1477 return newItemId;1478}14791480export async function createItemWithPropsExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, props: Array<Property>, owner: CrossAccountId | string = sender.address) {1481 await usingApi(async (api) => {14821483 let tx;1484 if (createMode === 'NFT') {1485 const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}}) as UpDataStructsCreateItemData;1486 tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), data);1487 } else {1488 tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);1489 }149014911492 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1493 if(events.message && events.message.toString().indexOf('1002: Verification Error') > -1) return;1494 const result = getCreateItemResult(events);14951496 expect(result.success).to.be.false;1497 });1498}14991500export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {1501 let newItemId = 0;1502 await usingApi(async (api) => {1503 const to = normalizeAccountId(owner);1504 const itemCountBefore = await getLastTokenId(api, collectionId);1505 const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId);15061507 let tx;1508 if (createMode === 'Fungible') {1509 const createData = {fungible: {value: 10}};1510 tx = api.tx.unique.createItem(collectionId, to, createData as any);1511 } else if (createMode === 'ReFungible') {1512 const createData = {refungible: {pieces: 100}};1513 tx = api.tx.unique.createItem(collectionId, to, createData as any);1514 } else {1515 const createData = {nft: {}};1516 tx = api.tx.unique.createItem(collectionId, to, createData as any);1517 }15181519 const events = await executeTransaction(api, sender, tx);1520 const result = getCreateItemResult(events);15211522 const itemCountAfter = await getLastTokenId(api, collectionId);1523 const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId);15241525 // What to expect1526 // tslint:disable-next-line:no-unused-expression1527 expect(result.success).to.be.true;1528 if (createMode === 'Fungible') {1529 expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);1530 } else {1531 expect(itemCountAfter).to.be.equal(itemCountBefore + 1);1532 }1533 expect(collectionId).to.be.equal(result.collectionId);1534 expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());1535 expect(to).to.be.deep.equal(result.recipient);1536 newItemId = result.itemId;1537 });1538 return newItemId;1539}15401541export async function createRefungibleToken(api: ApiPromise, sender: IKeyringPair, collectionId: number, amount: bigint, owner: CrossAccountId | IKeyringPair | string = sender.address) : Promise<CreateItemResult> {1542 const createData = {refungible: {pieces: amount}};1543 const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createData as any);15441545 const events = await submitTransactionAsync(sender, tx);1546 return getCreateItemResult(events);1547}15481549export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {1550 await usingApi(async (api) => {1551 const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);15521553 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1554 const result = getCreateItemResult(events);15551556 expect(result.success).to.be.false;1557 });1558}15591560export async function setPublicAccessModeExpectSuccess(1561 sender: IKeyringPair, collectionId: number,1562 accessMode: 'Normal' | 'AllowList',1563) {1564 await usingApi(async (api) => {15651566 // Run the transaction1567 const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode});1568 const events = await submitTransactionAsync(sender, tx);1569 const result = getGenericResult(events);15701571 // Get the collection1572 const collection = await queryCollectionExpectSuccess(api, collectionId);15731574 // What to expect1575 // tslint:disable-next-line:no-unused-expression1576 expect(result.success).to.be.true;1577 expect(collection.permissions.access.toHuman()).to.be.equal(accessMode);1578 });1579}15801581export async function setPublicAccessModeExpectFail(1582 sender: IKeyringPair, collectionId: number,1583 accessMode: 'Normal' | 'AllowList',1584) {1585 await usingApi(async (api) => {15861587 // Run the transaction1588 const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode});1589 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1590 const result = getGenericResult(events);15911592 // What to expect1593 // tslint:disable-next-line:no-unused-expression1594 expect(result.success).to.be.false;1595 });1596}15971598export async function enableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) {1599 await setPublicAccessModeExpectSuccess(sender, collectionId, 'AllowList');1600}16011602export async function enableAllowListExpectFail(sender: IKeyringPair, collectionId: number) {1603 await setPublicAccessModeExpectFail(sender, collectionId, 'AllowList');1604}16051606export async function disableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) {1607 await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');1608}16091610export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {1611 await usingApi(async (api) => {16121613 // Run the transaction1614 const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled});1615 const events = await submitTransactionAsync(sender, tx);1616 const result = getGenericResult(events);1617 expect(result.success).to.be.true;16181619 // Get the collection1620 const collection = await queryCollectionExpectSuccess(api, collectionId);16211622 expect(collection.permissions.mintMode.toHuman()).to.be.equal(enabled);1623 });1624}16251626export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {1627 await setMintPermissionExpectSuccess(sender, collectionId, true);1628}16291630export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {1631 await usingApi(async (api) => {1632 // Run the transaction1633 const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled});1634 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1635 const result = getCreateCollectionResult(events);1636 // tslint:disable-next-line:no-unused-expression1637 expect(result.success).to.be.false;1638 });1639}16401641export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {1642 await usingApi(async (api) => {1643 // Run the transaction1644 const tx = api.tx.unique.setChainLimits(limits);1645 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1646 const result = getCreateCollectionResult(events);1647 // tslint:disable-next-line:no-unused-expression1648 expect(result.success).to.be.false;1649 });1650}16511652export async function isAllowlisted(api: ApiPromise, collectionId: number, address: string | CrossAccountId) {1653 return (await api.rpc.unique.allowed(collectionId, normalizeAccountId(address))).toJSON();1654}16551656export async function addToAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId | CrossAccountId) {1657 await usingApi(async (api) => {1658 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.false;16591660 // Run the transaction1661 const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));1662 const events = await submitTransactionAsync(sender, tx);1663 const result = getGenericResult(events);1664 expect(result.success).to.be.true;16651666 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;1667 });1668}16691670export async function addToAllowListAgainExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1671 await usingApi(async (api) => {16721673 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;16741675 // Run the transaction1676 const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));1677 const events = await submitTransactionAsync(sender, tx);1678 const result = getGenericResult(events);1679 expect(result.success).to.be.true;16801681 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;1682 });1683}16841685export async function addToAllowListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1686 await usingApi(async (api) => {16871688 // Run the transaction1689 const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));1690 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1691 const result = getGenericResult(events);16921693 // What to expect1694 // tslint:disable-next-line:no-unused-expression1695 expect(result.success).to.be.false;1696 });1697}16981699export async function removeFromAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1700 await usingApi(async (api) => {1701 // Run the transaction1702 const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address));1703 const events = await submitTransactionAsync(sender, tx);1704 const result = getGenericResult(events);17051706 // What to expect1707 // tslint:disable-next-line:no-unused-expression1708 expect(result.success).to.be.true;1709 });1710}17111712export async function removeFromAllowListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1713 await usingApi(async (api) => {1714 // Run the transaction1715 const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address));1716 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1717 const result = getGenericResult(events);17181719 // What to expect1720 // tslint:disable-next-line:no-unused-expression1721 expect(result.success).to.be.false;1722 });1723}17241725export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1726 : Promise<UpDataStructsRpcCollection | null> => {1727 return (await api.rpc.unique.collectionById(collectionId)).unwrapOr(null);1728};17291730export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1731 // set global object - collectionsCount1732 return (await api.rpc.unique.collectionStats()).created.toNumber();1733};17341735export async function queryCollectionExpectSuccess(api: ApiPromise, collectionId: number): Promise<UpDataStructsRpcCollection> {1736 return (await api.rpc.unique.collectionById(collectionId)).unwrap();1737}17381739export async function waitNewBlocks(blocksCount = 1): Promise<void> {1740 await usingApi(async (api) => {1741 const promise = new Promise<void>(async (resolve) => {1742 const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {1743 if (blocksCount > 0) {1744 blocksCount--;1745 } else {1746 unsubscribe();1747 resolve();1748 }1749 });1750 });1751 return promise;1752 });1753}17541755export async function repartitionRFT(1756 api: ApiPromise,1757 collectionId: number,1758 sender: IKeyringPair,1759 tokenId: number,1760 amount: bigint,1761): Promise<boolean> {1762 const tx = api.tx.unique.repartition(collectionId, tokenId, amount);1763 const events = await submitTransactionAsync(sender, tx);1764 const result = getGenericResult(events);17651766 return result.success;1767}17681769export async function itApi(name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) {1770 let i: any = it;1771 if (opts.only) i = i.only;1772 else if (opts.skip) i = i.skip;1773 i(name, async () => {1774 await usingApi(async (api, privateKeyWrapper) => {1775 await cb({api, privateKeyWrapper});1776 });1777 });1778}17791780itApi.only = (name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itApi(name, cb, {only: true});1781itApi.skip = (name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itApi(name, cb, {skip: true});1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import '../interfaces/augment-api-rpc';18import '../interfaces/augment-api-query';19import {ApiPromise} from '@polkadot/api';20import type {AccountId, EventRecord, Event, BlockNumber} from '@polkadot/types/interfaces';21import type {GenericEventData} from '@polkadot/types';22import {AnyTuple, IEvent, IKeyringPair} from '@polkadot/types/types';23import {evmToAddress} from '@polkadot/util-crypto';24import {AnyNumber} from '@polkadot/types-codec/types';25import BN from 'bn.js';26import chai from 'chai';27import chaiAsPromised from 'chai-as-promised';28import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';29import {hexToStr, strToUTF16, utf16ToStr} from './util';30import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';31import {UpDataStructsTokenChild} from '../interfaces';32import {Context} from 'mocha';3334chai.use(chaiAsPromised);35const expect = chai.expect;3637export type CrossAccountId = {38 Substrate: string,39} | {40 Ethereum: string,41};424344export enum Pallets {45 Inflation = 'inflation',46 RmrkCore = 'rmrkcore',47 RmrkEquip = 'rmrkequip',48 ReFungible = 'refungible',49 Fungible = 'fungible',50 NFT = 'nonfungible',51 Scheduler = 'scheduler',52 AppPromotion = 'apppromotion',53}5455export async function isUnique(): Promise<boolean> {56 return usingApi(async api => {57 const chain = await api.rpc.system.chain();5859 return chain.eq('UNIQUE');60 });61}6263export async function isQuartz(): Promise<boolean> {64 return usingApi(async api => {65 const chain = await api.rpc.system.chain();66 67 return chain.eq('QUARTZ');68 });69}7071let modulesNames: any;72export function getModuleNames(api: ApiPromise): string[] {73 if (typeof modulesNames === 'undefined') 74 modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());75 return modulesNames;76}7778export async function missingRequiredPallets(requiredPallets: string[]): Promise<string[]> {79 return await usingApi(async api => {80 const pallets = getModuleNames(api);8182 return requiredPallets.filter(p => !pallets.includes(p));83 });84}8586export async function checkPalletsPresence(requiredPallets: string[]): Promise<boolean> {87 return (await missingRequiredPallets(requiredPallets)).length == 0;88}8990export async function requirePallets(mocha: Context, requiredPallets: string[]) {91 const missingPallets = await missingRequiredPallets(requiredPallets);9293 if (missingPallets.length > 0) {94 const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`;95 const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;96 const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`;9798 console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg);99100 mocha.skip();101 }102}103104export function bigIntToSub(api: ApiPromise, number: bigint) {105 return api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();106}107108export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {109 if (typeof input === 'string') {110 if (input.length >= 47) {111 return {Substrate: input};112 } else if (input.length === 42 && input.startsWith('0x')) {113 return {Ethereum: input.toLowerCase()};114 } else if (input.length === 40 && !input.startsWith('0x')) {115 return {Ethereum: '0x' + input.toLowerCase()};116 } else {117 throw new Error(`Unknown address format: "${input}"`);118 }119 }120 if ('address' in input) {121 return {Substrate: input.address};122 }123 if ('Ethereum' in input) {124 return {125 Ethereum: input.Ethereum.toLowerCase(),126 };127 } else if ('ethereum' in input) {128 return {129 Ethereum: (input as any).ethereum.toLowerCase(),130 };131 } else if ('Substrate' in input) {132 return input;133 } else if ('substrate' in input) {134 return {135 Substrate: (input as any).substrate,136 };137 }138139 // AccountId140 return {Substrate: input.toString()};141}142export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {143 input = normalizeAccountId(input);144 if ('Substrate' in input) {145 return input.Substrate;146 } else {147 return evmToAddress(input.Ethereum);148 }149}150151export const U128_MAX = (1n << 128n) - 1n;152153const MICROUNIQUE = 1_000_000_000_000n;154const MILLIUNIQUE = 1_000n * MICROUNIQUE;155const CENTIUNIQUE = 10n * MILLIUNIQUE;156export const UNIQUE = 100n * CENTIUNIQUE;157158interface GenericResult<T> {159 success: boolean;160 data: T | null;161}162163interface CreateCollectionResult {164 success: boolean;165 collectionId: number;166}167168interface CreateItemResult {169 success: boolean;170 collectionId: number;171 itemId: number;172 recipient?: CrossAccountId;173 amount?: number;174}175176interface DestroyItemResult {177 success: boolean;178 collectionId: number;179 itemId: number;180 owner: CrossAccountId;181 amount: number;182}183184interface TransferResult {185 collectionId: number;186 itemId: number;187 sender?: CrossAccountId;188 recipient?: CrossAccountId;189 value: bigint;190}191192interface IReFungibleOwner {193 fraction: BN;194 owner: number[];195}196197interface IGetMessage {198 checkMsgUnqMethod: string;199 checkMsgTrsMethod: string;200 checkMsgSysMethod: string;201}202203export interface IFungibleTokenDataType {204 value: number;205}206207export interface IChainLimits {208 collectionNumbersLimit: number;209 accountTokenOwnershipLimit: number;210 collectionsAdminsLimit: number;211 customDataLimit: number;212 nftSponsorTransferTimeout: number;213 fungibleSponsorTransferTimeout: number;214 refungibleSponsorTransferTimeout: number;215 //offchainSchemaLimit: number;216 //constOnChainSchemaLimit: number;217}218219export interface IReFungibleTokenDataType {220 owner: IReFungibleOwner[];221}222223export function uniqueEventMessage(events: EventRecord[]): IGetMessage {224 let checkMsgUnqMethod = '';225 let checkMsgTrsMethod = '';226 let checkMsgSysMethod = '';227 events.forEach(({event: {method, section}}) => {228 if (section === 'common') {229 checkMsgUnqMethod = method;230 } else if (section === 'treasury') {231 checkMsgTrsMethod = method;232 } else if (section === 'system') {233 checkMsgSysMethod = method;234 } else { return null; }235 });236 const result: IGetMessage = {237 checkMsgUnqMethod,238 checkMsgTrsMethod,239 checkMsgSysMethod,240 };241 return result;242}243244export function getEvent<T extends Event>(events: EventRecord[], check: (event: IEvent<AnyTuple>) => event is T): T | undefined {245 const event = events.find(r => check(r.event));246 if (!event) return;247 return event.event as T;248}249250export function getGenericResult<T>(events: EventRecord[]): GenericResult<T>;251export function getGenericResult<T>(252 events: EventRecord[],253 expectSection: string,254 expectMethod: string,255 extractAction: (data: GenericEventData) => T256): GenericResult<T>;257258export function getGenericResult<T>(259 events: EventRecord[],260 expectSection?: string,261 expectMethod?: string,262 extractAction?: (data: GenericEventData) => T,263): GenericResult<T> {264 let success = false;265 let successData = null;266267 events.forEach(({event: {data, method, section}}) => {268 // console.log(` ${phase}: ${section}.${method}:: ${data}`);269 if (method === 'ExtrinsicSuccess') {270 success = true;271 } else if ((expectSection == section) && (expectMethod == method)) {272 successData = extractAction!(data as any);273 }274 });275276 const result: GenericResult<T> = {277 success,278 data: successData,279 };280 return result;281}282283export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {284 const genericResult = getGenericResult(events, 'common', 'CollectionCreated', (data) => parseInt(data[0].toString(), 10));285 const result: CreateCollectionResult = {286 success: genericResult.success,287 collectionId: genericResult.data ?? 0,288 };289 return result;290}291292export function getCreateItemsResult(events: EventRecord[]): CreateItemResult[] {293 const results: CreateItemResult[] = [];294 295 const genericResult = getGenericResult<CreateItemResult[]>(events, 'common', 'ItemCreated', (data) => {296 const collectionId = parseInt(data[0].toString(), 10);297 const itemId = parseInt(data[1].toString(), 10);298 const recipient = normalizeAccountId(data[2].toJSON() as any);299 const amount = parseInt(data[3].toString(), 10);300301 const itemRes: CreateItemResult = {302 success: true,303 collectionId,304 itemId,305 recipient,306 amount,307 };308309 results.push(itemRes);310 return results;311 });312313 if (!genericResult.success) return [];314 return results;315}316317export function getCreateItemResult(events: EventRecord[]): CreateItemResult {318 const genericResult = getGenericResult(events, 'common', 'ItemCreated', (data) => data.map(function(value) { return value.toJSON(); }));319 320 if (genericResult.data == null) 321 return {322 success: genericResult.success,323 collectionId: 0,324 itemId: 0,325 amount: 0,326 };327 else 328 return {329 success: genericResult.success,330 collectionId: genericResult.data[0] as number,331 itemId: genericResult.data[1] as number,332 recipient: normalizeAccountId(genericResult.data![2] as any),333 amount: genericResult.data[3] as number,334 };335}336337export function getDestroyItemsResult(events: EventRecord[]): DestroyItemResult[] {338 const results: DestroyItemResult[] = [];339 340 const genericResult = getGenericResult<DestroyItemResult[]>(events, 'common', 'ItemDestroyed', (data) => {341 const collectionId = parseInt(data[0].toString(), 10);342 const itemId = parseInt(data[1].toString(), 10);343 const owner = normalizeAccountId(data[2].toJSON() as any);344 const amount = parseInt(data[3].toString(), 10);345346 const itemRes: DestroyItemResult = {347 success: true,348 collectionId,349 itemId,350 owner,351 amount,352 };353354 results.push(itemRes);355 return results;356 });357358 if (!genericResult.success) return [];359 return results;360}361362export function getTransferResult(api: ApiPromise, events: EventRecord[]): TransferResult {363 for (const {event} of events) {364 if (api.events.common.Transfer.is(event)) {365 const [collection, token, sender, recipient, value] = event.data;366 return {367 collectionId: collection.toNumber(),368 itemId: token.toNumber(),369 sender: normalizeAccountId(sender.toJSON() as any),370 recipient: normalizeAccountId(recipient.toJSON() as any),371 value: value.toBigInt(),372 };373 }374 }375 throw new Error('no transfer event');376}377378interface Nft {379 type: 'NFT';380}381382interface Fungible {383 type: 'Fungible';384 decimalPoints: number;385}386387interface ReFungible {388 type: 'ReFungible';389}390391export type CollectionMode = Nft | Fungible | ReFungible;392393export type Property = {394 key: any,395 value: any,396};397398type Permission = {399 mutable: boolean;400 collectionAdmin: boolean;401 tokenOwner: boolean;402}403404type PropertyPermission = {405 key: any;406 permission: Permission;407}408409export type CreateCollectionParams = {410 mode: CollectionMode,411 name: string,412 description: string,413 tokenPrefix: string,414 properties?: Array<Property>,415 propPerm?: Array<PropertyPermission>416};417418const defaultCreateCollectionParams: CreateCollectionParams = {419 description: 'description',420 mode: {type: 'NFT'},421 name: 'name',422 tokenPrefix: 'prefix',423};424425export async function426createCollection(427 api: ApiPromise,428 sender: IKeyringPair,429 params: Partial<CreateCollectionParams> = {},430): Promise<CreateCollectionResult> {431 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};432433 let modeprm = {};434 if (mode.type === 'NFT') {435 modeprm = {nft: null};436 } else if (mode.type === 'Fungible') {437 modeprm = {fungible: mode.decimalPoints};438 } else if (mode.type === 'ReFungible') {439 modeprm = {refungible: null};440 }441442 const tx = api.tx.unique.createCollectionEx({443 name: strToUTF16(name),444 description: strToUTF16(description),445 tokenPrefix: strToUTF16(tokenPrefix),446 mode: modeprm as any,447 });448 const events = await executeTransaction(api, sender, tx);449 return getCreateCollectionResult(events);450}451452export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {453 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};454455 let collectionId = 0;456 await usingApi(async (api, privateKeyWrapper) => {457 // Get number of collections before the transaction458 const collectionCountBefore = await getCreatedCollectionCount(api);459460 // Run the CreateCollection transaction461 const alicePrivateKey = privateKeyWrapper('//Alice');462463 const result = await createCollection(api, alicePrivateKey, params);464465 // Get number of collections after the transaction466 const collectionCountAfter = await getCreatedCollectionCount(api);467468 // Get the collection469 const collection = await queryCollectionExpectSuccess(api, result.collectionId);470471 // What to expect472 // tslint:disable-next-line:no-unused-expression473 expect(result.success).to.be.true;474 expect(result.collectionId).to.be.equal(collectionCountAfter);475 // tslint:disable-next-line:no-unused-expression476 expect(collection).to.be.not.null;477 expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');478 expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey));479 expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);480 expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);481 expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);482483 collectionId = result.collectionId;484 });485486 return collectionId;487}488489export async function createCollectionWithPropsExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {490 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};491492 let collectionId = 0;493 await usingApi(async (api, privateKeyWrapper) => {494 // Get number of collections before the transaction495 const collectionCountBefore = await getCreatedCollectionCount(api);496497 // Run the CreateCollection transaction498 const alicePrivateKey = privateKeyWrapper('//Alice');499500 let modeprm = {};501 if (mode.type === 'NFT') {502 modeprm = {nft: null};503 } else if (mode.type === 'Fungible') {504 modeprm = {fungible: mode.decimalPoints};505 } else if (mode.type === 'ReFungible') {506 modeprm = {refungible: null};507 }508509 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});510 const events = await submitTransactionAsync(alicePrivateKey, tx);511 const result = getCreateCollectionResult(events);512513 // Get number of collections after the transaction514 const collectionCountAfter = await getCreatedCollectionCount(api);515516 // Get the collection517 const collection = await queryCollectionExpectSuccess(api, result.collectionId);518519 // What to expect520 // tslint:disable-next-line:no-unused-expression521 expect(result.success).to.be.true;522 expect(result.collectionId).to.be.equal(collectionCountAfter);523 // tslint:disable-next-line:no-unused-expression524 expect(collection).to.be.not.null;525 expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');526 expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey));527 expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);528 expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);529 expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);530531532 collectionId = result.collectionId;533 });534535 return collectionId;536}537538export async function createCollectionWithPropsExpectFailure(params: Partial<CreateCollectionParams> = {}) {539 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};540541 await usingApi(async (api, privateKeyWrapper) => {542 // Get number of collections before the transaction543 const collectionCountBefore = await getCreatedCollectionCount(api);544545 // Run the CreateCollection transaction546 const alicePrivateKey = privateKeyWrapper('//Alice');547548 let modeprm = {};549 if (mode.type === 'NFT') {550 modeprm = {nft: null};551 } else if (mode.type === 'Fungible') {552 modeprm = {fungible: mode.decimalPoints};553 } else if (mode.type === 'ReFungible') {554 modeprm = {refungible: null};555 }556557 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});558 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;559560561 // Get number of collections after the transaction562 const collectionCountAfter = await getCreatedCollectionCount(api);563564 expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');565 });566}567568export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {569 const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};570571 let modeprm = {};572 if (mode.type === 'NFT') {573 modeprm = {nft: null};574 } else if (mode.type === 'Fungible') {575 modeprm = {fungible: mode.decimalPoints};576 } else if (mode.type === 'ReFungible') {577 modeprm = {refungible: null};578 }579580 await usingApi(async (api, privateKeyWrapper) => {581 // Get number of collections before the transaction582 const collectionCountBefore = await getCreatedCollectionCount(api);583584 // Run the CreateCollection transaction585 const alicePrivateKey = privateKeyWrapper('//Alice');586 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any});587 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;588589 // Get number of collections after the transaction590 const collectionCountAfter = await getCreatedCollectionCount(api);591592 // What to expect593 expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');594 });595}596597export async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise<IKeyringPair> {598 let bal = 0n;599 let unused;600 do {601 const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;602 unused = privateKeyWrapper(`//${randomSeed}`);603 bal = (await api.query.system.account(unused.address)).data.free.toBigInt();604 } while (bal !== 0n);605 return unused;606}607608export async function getAllowance(api: ApiPromise, collectionId: number, owner: CrossAccountId | string | IKeyringPair, approved: CrossAccountId | string | IKeyringPair, tokenId: number) {609 return (await api.rpc.unique.allowance(collectionId, normalizeAccountId(owner), normalizeAccountId(approved), tokenId)).toBigInt();610}611612export function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise<IKeyringPair[]> {613 return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now())));614}615616export async function findNotExistingCollection(api: ApiPromise): Promise<number> {617 const totalNumber = await getCreatedCollectionCount(api);618 const newCollection: number = totalNumber + 1;619 return newCollection;620}621622function getDestroyResult(events: EventRecord[]): boolean {623 let success = false;624 events.forEach(({event: {method}}) => {625 if (method == 'ExtrinsicSuccess') {626 success = true;627 }628 });629 return success;630}631632export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {633 await usingApi(async (api, privateKeyWrapper) => {634 // Run the DestroyCollection transaction635 const alicePrivateKey = privateKeyWrapper(senderSeed);636 const tx = api.tx.unique.destroyCollection(collectionId);637 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;638 });639}640641export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {642 await usingApi(async (api, privateKeyWrapper) => {643 // Run the DestroyCollection transaction644 const alicePrivateKey = privateKeyWrapper(senderSeed);645 const tx = api.tx.unique.destroyCollection(collectionId);646 const events = await submitTransactionAsync(alicePrivateKey, tx);647 const result = getDestroyResult(events);648 expect(result).to.be.true;649650 // What to expect651 expect(await getDetailedCollectionInfo(api, collectionId)).to.be.null;652 });653}654655export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {656 await usingApi(async (api) => {657 const tx = api.tx.unique.setCollectionLimits(collectionId, limits);658 const events = await submitTransactionAsync(sender, tx);659 const result = getGenericResult(events);660661 expect(result.success).to.be.true;662 });663}664665export const setCollectionPermissionsExpectSuccess = async (sender: IKeyringPair, collectionId: number, permissions: any) => {666 await usingApi(async(api) => {667 const tx = api.tx.unique.setCollectionPermissions(collectionId, permissions);668 const events = await submitTransactionAsync(sender, tx);669 const result = getGenericResult(events);670671 expect(result.success).to.be.true;672 });673};674675export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {676 await usingApi(async (api) => {677 const tx = api.tx.unique.setCollectionLimits(collectionId, limits);678 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;679 const result = getGenericResult(events);680681 expect(result.success).to.be.false;682 });683}684685export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {686 await usingApi(async (api, privateKeyWrapper) => {687688 // Run the transaction689 const senderPrivateKey = privateKeyWrapper(sender);690 const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor);691 const events = await submitTransactionAsync(senderPrivateKey, tx);692 const result = getGenericResult(events);693694 // Get the collection695 const collection = await queryCollectionExpectSuccess(api, collectionId);696697 // What to expect698 expect(result.success).to.be.true;699 expect(collection.sponsorship.toJSON()).to.deep.equal({700 unconfirmed: sponsor,701 });702 });703}704705export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {706 await usingApi(async (api, privateKeyWrapper) => {707708 // Run the transaction709 const alicePrivateKey = privateKeyWrapper(sender);710 const tx = api.tx.unique.removeCollectionSponsor(collectionId);711 const events = await submitTransactionAsync(alicePrivateKey, tx);712 const result = getGenericResult(events);713714 // Get the collection715 const collection = await queryCollectionExpectSuccess(api, collectionId);716717 // What to expect718 expect(result.success).to.be.true;719 expect(collection.sponsorship.toJSON()).to.be.deep.equal({disabled: null});720 });721}722723export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {724 await usingApi(async (api, privateKeyWrapper) => {725726 // Run the transaction727 const alicePrivateKey = privateKeyWrapper(senderSeed);728 const tx = api.tx.unique.removeCollectionSponsor(collectionId);729 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;730 });731}732733export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {734 await usingApi(async (api, privateKeyWrapper) => {735736 // Run the transaction737 const alicePrivateKey = privateKeyWrapper(senderSeed);738 const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor);739 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;740 });741}742743export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {744 await usingApi(async (api, privateKeyWrapper) => {745746 // Run the transaction747 const sender = privateKeyWrapper(senderSeed);748 await confirmSponsorshipByKeyExpectSuccess(collectionId, sender);749 });750}751752export async function confirmSponsorshipByKeyExpectSuccess(collectionId: number, sender: IKeyringPair) {753 await usingApi(async (api, privateKeyWrapper) => {754755 // Run the transaction756 const tx = api.tx.unique.confirmSponsorship(collectionId);757 const events = await submitTransactionAsync(sender, tx);758 const result = getGenericResult(events);759760 // Get the collection761 const collection = await queryCollectionExpectSuccess(api, collectionId);762763 // What to expect764 expect(result.success).to.be.true;765 expect(collection.sponsorship.toJSON()).to.be.deep.equal({766 confirmed: sender.address,767 });768 });769}770771772export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {773 await usingApi(async (api, privateKeyWrapper) => {774775 // Run the transaction776 const sender = privateKeyWrapper(senderSeed);777 const tx = api.tx.unique.confirmSponsorship(collectionId);778 await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;779 });780}781782export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {783 await usingApi(async (api) => {784 const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);785 const events = await submitTransactionAsync(sender, tx);786 const result = getGenericResult(events);787788 expect(result.success).to.be.true;789 });790}791792export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {793 await usingApi(async (api) => {794 const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);795 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;796 const result = getGenericResult(events);797798 expect(result.success).to.be.false;799 });800}801802export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {803804 await usingApi(async (api) => {805806 const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled);807 const events = await submitTransactionAsync(sender, tx);808 const result = getGenericResult(events);809810 expect(result.success).to.be.true;811 });812}813814export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {815816 await usingApi(async (api) => {817818 const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled);819 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;820 const result = getGenericResult(events);821822 expect(result.success).to.be.false;823 });824}825826export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {827 await usingApi(async (api) => {828 const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit);829 const events = await submitTransactionAsync(sender, tx);830 const result = getGenericResult(events);831832 expect(result.success).to.be.true;833 });834}835836export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {837 await usingApi(async (api) => {838 const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit);839 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;840 const result = getGenericResult(events);841842 expect(result.success).to.be.false;843 });844}845846export async function getNextSponsored(847 api: ApiPromise,848 collectionId: number,849 account: string | CrossAccountId,850 tokenId: number,851): Promise<number> {852 return Number((await api.rpc.unique.nextSponsored(collectionId, account, tokenId)).unwrapOr(-1));853}854855export async function toggleContractAllowlistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {856 await usingApi(async (api) => {857 const tx = api.tx.unique.toggleContractAllowList(contractAddress, value);858 const events = await submitTransactionAsync(sender, tx);859 const result = getGenericResult(events);860861 expect(result.success).to.be.true;862 });863}864865export async function isAllowlistedInContract(contractAddress: AccountId | string, user: string) {866 let allowlisted = false;867 await usingApi(async (api) => {868 allowlisted = (await api.query.unique.contractAllowList(contractAddress, user)).toJSON() as boolean;869 });870 return allowlisted;871}872873export async function addToContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {874 await usingApi(async (api) => {875 const tx = api.tx.unique.addToContractAllowList(contractAddress.toString(), user.toString());876 const events = await submitTransactionAsync(sender, tx);877 const result = getGenericResult(events);878879 expect(result.success).to.be.true;880 });881}882883export async function removeFromContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {884 await usingApi(async (api) => {885 const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString());886 const events = await submitTransactionAsync(sender, tx);887 const result = getGenericResult(events);888889 expect(result.success).to.be.true;890 });891}892893export async function removeFromContractAllowListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {894 await usingApi(async (api) => {895 const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString());896 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;897 const result = getGenericResult(events);898899 expect(result.success).to.be.false;900 });901}902903export interface CreateFungibleData {904 readonly Value: bigint;905}906907export interface CreateReFungibleData { }908export interface CreateNftData { }909910export type CreateItemData = {911 NFT: CreateNftData;912} | {913 Fungible: CreateFungibleData;914} | {915 ReFungible: CreateReFungibleData;916};917918export async function burnItem(api: ApiPromise, sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint) : Promise<boolean> {919 const tx = api.tx.unique.burnItem(collectionId, tokenId, value);920 const events = await submitTransactionAsync(sender, tx);921 return getGenericResult(events).success;922}923924export async function burnItemExpectSuccess(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) {925 await usingApi(async (api) => {926 const balanceBefore = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId);927 // if burning token by admin - use adminButnItemExpectSuccess928 expect(balanceBefore >= BigInt(value)).to.be.true;929930 expect(await burnItem(api, sender, collectionId, tokenId, value)).to.be.true;931932 const balanceAfter = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId);933 expect(balanceAfter + BigInt(value)).to.be.equal(balanceBefore);934 });935}936937export async function burnItemExpectFailure(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) {938 await usingApi(async (api) => {939 const tx = api.tx.unique.burnItem(collectionId, tokenId, value);940941 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;942 const result = getCreateCollectionResult(events);943 // tslint:disable-next-line:no-unused-expression944 expect(result.success).to.be.false;945 });946}947948export async function burnFromExpectSuccess(sender: IKeyringPair, from: IKeyringPair | CrossAccountId, collectionId: number, tokenId: number, value: number | bigint = 1) {949 await usingApi(async (api) => {950 const tx = api.tx.unique.burnFrom(collectionId, normalizeAccountId(from), tokenId, value);951 const events = await submitTransactionAsync(sender, tx);952 return getGenericResult(events).success;953 });954}955956export async function957approve(958 api: ApiPromise,959 collectionId: number,960 tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string | IKeyringPair, amount: number | bigint,961) {962 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);963 const events = await submitTransactionAsync(owner, approveUniqueTx);964 return getGenericResult(events).success;965}966967export async function968approveExpectSuccess(969 collectionId: number,970 tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string, amount: number | bigint = 1,971) {972 await usingApi(async (api: ApiPromise) => {973 const result = await approve(api, collectionId, tokenId, owner, approved, amount);974 expect(result).to.be.true;975976 expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));977 });978}979980export async function adminApproveFromExpectSuccess(981 collectionId: number,982 tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,983) {984 await usingApi(async (api: ApiPromise) => {985 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);986 const events = await submitTransactionAsync(admin, approveUniqueTx);987 const result = getGenericResult(events);988 expect(result.success).to.be.true;989990 expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));991 });992}993994export async function995transferFrom(996 api: ApiPromise,997 collectionId: number,998 tokenId: number,999 accountApproved: IKeyringPair,1000 accountFrom: IKeyringPair | CrossAccountId,1001 accountTo: IKeyringPair | CrossAccountId,1002 value: number | bigint,1003) {1004 const from = normalizeAccountId(accountFrom);1005 const to = normalizeAccountId(accountTo);1006 const transferFromTx = api.tx.unique.transferFrom(from, to, collectionId, tokenId, value);1007 const events = await submitTransactionAsync(accountApproved, transferFromTx);1008 return getGenericResult(events).success;1009}10101011export async function1012transferFromExpectSuccess(1013 collectionId: number,1014 tokenId: number,1015 accountApproved: IKeyringPair,1016 accountFrom: IKeyringPair | CrossAccountId,1017 accountTo: IKeyringPair | CrossAccountId,1018 value: number | bigint = 1,1019 type = 'NFT',1020) {1021 await usingApi(async (api: ApiPromise) => {1022 const from = normalizeAccountId(accountFrom);1023 const to = normalizeAccountId(accountTo);1024 let balanceBefore = 0n;1025 if (type === 'Fungible' || type === 'ReFungible') {1026 balanceBefore = await getBalance(api, collectionId, to, tokenId);1027 }1028 expect(await transferFrom(api, collectionId, tokenId, accountApproved, accountFrom, accountTo, value)).to.be.true;1029 if (type === 'NFT') {1030 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);1031 }1032 if (type === 'Fungible') {1033 const balanceAfter = await getBalance(api, collectionId, to, tokenId);1034 if (JSON.stringify(to) !== JSON.stringify(from)) {1035 expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value));1036 } else {1037 expect(balanceAfter).to.be.equal(balanceBefore);1038 }1039 }1040 if (type === 'ReFungible') {1041 expect(await getBalance(api, collectionId, to, tokenId)).to.be.equal(balanceBefore + BigInt(value));1042 }1043 });1044}10451046export async function1047transferFromExpectFail(1048 collectionId: number,1049 tokenId: number,1050 accountApproved: IKeyringPair,1051 accountFrom: IKeyringPair,1052 accountTo: IKeyringPair,1053 value: number | bigint = 1,1054) {1055 await usingApi(async (api: ApiPromise) => {1056 const transferFromTx = api.tx.unique.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);1057 const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;1058 const result = getCreateCollectionResult(events);1059 // tslint:disable-next-line:no-unused-expression1060 expect(result.success).to.be.false;1061 });1062}10631064/* eslint no-async-promise-executor: "off" */1065export async function getBlockNumber(api: ApiPromise): Promise<number> {1066 return new Promise<number>(async (resolve) => {1067 const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {1068 unsubscribe();1069 resolve(head.number.toNumber());1070 });1071 });1072}10731074export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | CrossAccountId) {1075 await usingApi(async (api) => {1076 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(address));1077 const events = await submitTransactionAsync(sender, changeAdminTx);1078 const result = getCreateCollectionResult(events);1079 expect(result.success).to.be.true;1080 });1081}10821083export async function adminApproveFromExpectFail(1084 collectionId: number,1085 tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,1086) {1087 await usingApi(async (api: ApiPromise) => {1088 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);1089 const events = await expect(submitTransactionAsync(admin, approveUniqueTx)).to.be.rejected;1090 const result = getGenericResult(events);1091 expect(result.success).to.be.false;1092 });1093}10941095export async function1096getFreeBalance(account: IKeyringPair): Promise<bigint> {1097 let balance = 0n;1098 await usingApi(async (api) => {1099 balance = BigInt((await api.query.system.account(account.address)).data.free.toString());1100 });11011102 return balance;1103}11041105export async function transferBalanceTo(api: ApiPromise, source: IKeyringPair, target: string, amount = 1000n * UNIQUE) {1106 const tx = api.tx.balances.transfer(target, amount);1107 const events = await submitTransactionAsync(source, tx);1108 const result = getGenericResult(events);1109 expect(result.success).to.be.true;1110}11111112export async function1113scheduleExpectSuccess(1114 operationTx: any,1115 sender: IKeyringPair,1116 blockSchedule: number,1117 scheduledId: string,1118 period = 1,1119 repetitions = 1,1120) {1121 await usingApi(async (api: ApiPromise) => {1122 const blockNumber: number | undefined = await getBlockNumber(api);1123 const expectedBlockNumber = blockNumber + blockSchedule;11241125 expect(blockNumber).to.be.greaterThan(0);1126 const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule1127 scheduledId,1128 expectedBlockNumber, 1129 repetitions > 1 ? [period, repetitions] : null, 1130 0, 1131 {Value: operationTx as any},1132 );11331134 const events = await submitTransactionAsync(sender, scheduleTx);1135 expect(getGenericResult(events).success).to.be.true;1136 });1137}11381139export async function1140scheduleExpectFailure(1141 operationTx: any,1142 sender: IKeyringPair,1143 blockSchedule: number,1144 scheduledId: string,1145 period = 1,1146 repetitions = 1,1147) {1148 await usingApi(async (api: ApiPromise) => {1149 const blockNumber: number | undefined = await getBlockNumber(api);1150 const expectedBlockNumber = blockNumber + blockSchedule;11511152 expect(blockNumber).to.be.greaterThan(0);1153 const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule1154 scheduledId,1155 expectedBlockNumber, 1156 repetitions <= 1 ? null : [period, repetitions], 1157 0, 1158 {Value: operationTx as any},1159 );11601161 //const events = 1162 await expect(submitTransactionExpectFailAsync(sender, scheduleTx)).to.be.rejected;1163 //expect(getGenericResult(events).success).to.be.false;1164 });1165}11661167export async function1168scheduleTransferAndWaitExpectSuccess(1169 collectionId: number,1170 tokenId: number,1171 sender: IKeyringPair,1172 recipient: IKeyringPair,1173 value: number | bigint = 1,1174 blockSchedule: number,1175 scheduledId: string,1176) {1177 await usingApi(async (api: ApiPromise) => {1178 await scheduleTransferExpectSuccess(collectionId, tokenId, sender, recipient, value, blockSchedule, scheduledId);11791180 const recipientBalanceBefore = (await api.query.system.account(recipient.address)).data.free.toBigInt();11811182 // sleep for n + 1 blocks1183 await waitNewBlocks(blockSchedule + 1);11841185 const recipientBalanceAfter = (await api.query.system.account(recipient.address)).data.free.toBigInt();11861187 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(recipient.address));1188 expect(recipientBalanceAfter).to.be.equal(recipientBalanceBefore);1189 });1190}11911192export async function1193scheduleTransferExpectSuccess(1194 collectionId: number,1195 tokenId: number,1196 sender: IKeyringPair,1197 recipient: IKeyringPair,1198 value: number | bigint = 1,1199 blockSchedule: number,1200 scheduledId: string,1201) {1202 await usingApi(async (api: ApiPromise) => {1203 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);12041205 await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId);12061207 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(sender.address));1208 });1209}12101211export async function1212scheduleTransferFundsPeriodicExpectSuccess(1213 amount: bigint,1214 sender: IKeyringPair,1215 recipient: IKeyringPair,1216 blockSchedule: number,1217 scheduledId: string,1218 period: number,1219 repetitions: number,1220) {1221 await usingApi(async (api: ApiPromise) => {1222 const transferTx = api.tx.balances.transfer(recipient.address, amount);12231224 const balanceBefore = await getFreeBalance(recipient);1225 1226 await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId, period, repetitions);12271228 expect(await getFreeBalance(recipient)).to.be.equal(balanceBefore);1229 });1230}12311232export async function1233transfer(1234 api: ApiPromise,1235 collectionId: number,1236 tokenId: number,1237 sender: IKeyringPair,1238 recipient: IKeyringPair | CrossAccountId,1239 value: number | bigint,1240) : Promise<boolean> {1241 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);1242 const events = await executeTransaction(api, sender, transferTx);1243 return getGenericResult(events).success;1244}12451246export async function1247transferExpectSuccess(1248 collectionId: number,1249 tokenId: number,1250 sender: IKeyringPair,1251 recipient: IKeyringPair | CrossAccountId,1252 value: number | bigint = 1,1253 type = 'NFT',1254) {1255 await usingApi(async (api: ApiPromise) => {1256 const from = normalizeAccountId(sender);1257 const to = normalizeAccountId(recipient);12581259 let balanceBefore = 0n;1260 if (type === 'Fungible' || type === 'ReFungible') {1261 balanceBefore = await getBalance(api, collectionId, to, tokenId);1262 }12631264 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);1265 const events = await executeTransaction(api, sender, transferTx);1266 const result = getTransferResult(api, events);12671268 expect(result.collectionId).to.be.equal(collectionId);1269 expect(result.itemId).to.be.equal(tokenId);1270 expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));1271 expect(result.recipient).to.be.deep.equal(to);1272 expect(result.value).to.be.equal(BigInt(value));12731274 if (type === 'NFT') {1275 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);1276 }1277 if (type === 'Fungible' || type === 'ReFungible') {1278 const balanceAfter = await getBalance(api, collectionId, to, tokenId);1279 if (JSON.stringify(to) !== JSON.stringify(from)) {1280 expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value));1281 } else {1282 expect(balanceAfter).to.be.equal(balanceBefore);1283 }1284 }1285 });1286}12871288export async function1289transferExpectFailure(1290 collectionId: number,1291 tokenId: number,1292 sender: IKeyringPair,1293 recipient: IKeyringPair | CrossAccountId,1294 value: number | bigint = 1,1295) {1296 await usingApi(async (api: ApiPromise) => {1297 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);1298 const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;1299 const result = getGenericResult(events);1300 // if (events && Array.isArray(events)) {1301 // const result = getCreateCollectionResult(events);1302 // tslint:disable-next-line:no-unused-expression1303 expect(result.success).to.be.false;1304 //}1305 });1306}13071308export async function1309approveExpectFail(1310 collectionId: number,1311 tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,1312) {1313 await usingApi(async (api: ApiPromise) => {1314 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);1315 const events = await expect(submitTransactionExpectFailAsync(owner, approveUniqueTx)).to.be.rejected;1316 const result = getCreateCollectionResult(events);1317 // tslint:disable-next-line:no-unused-expression1318 expect(result.success).to.be.false;1319 });1320}13211322export async function getBalance(1323 api: ApiPromise,1324 collectionId: number,1325 owner: string | CrossAccountId | IKeyringPair,1326 token: number,1327): Promise<bigint> {1328 return (await api.rpc.unique.balance(collectionId, normalizeAccountId(owner), token)).toBigInt();1329}1330export async function getTokenOwner(1331 api: ApiPromise,1332 collectionId: number,1333 token: number,1334): Promise<CrossAccountId> {1335 const owner = (await api.rpc.unique.tokenOwner(collectionId, token)).toJSON() as any;1336 if (owner == null) throw new Error('owner == null');1337 return normalizeAccountId(owner);1338}1339export async function getTopmostTokenOwner(1340 api: ApiPromise,1341 collectionId: number,1342 token: number,1343): Promise<CrossAccountId> {1344 const owner = (await api.rpc.unique.topmostTokenOwner(collectionId, token)).toJSON() as any;1345 if (owner == null) throw new Error('owner == null');1346 return normalizeAccountId(owner);1347}1348export async function getTokenChildren(1349 api: ApiPromise,1350 collectionId: number,1351 tokenId: number,1352): Promise<UpDataStructsTokenChild[]> {1353 return (await api.rpc.unique.tokenChildren(collectionId, tokenId)).toJSON() as any;1354}1355export async function isTokenExists(1356 api: ApiPromise,1357 collectionId: number,1358 token: number,1359): Promise<boolean> {1360 return (await api.rpc.unique.tokenExists(collectionId, token)).toJSON();1361}1362export async function getLastTokenId(1363 api: ApiPromise,1364 collectionId: number,1365): Promise<number> {1366 return (await api.rpc.unique.lastTokenId(collectionId)).toJSON();1367}1368export async function getAdminList(1369 api: ApiPromise,1370 collectionId: number,1371): Promise<string[]> {1372 return (await api.rpc.unique.adminlist(collectionId)).toHuman() as any;1373}1374export async function getTokenProperties(1375 api: ApiPromise,1376 collectionId: number,1377 tokenId: number,1378 propertyKeys: string[],1379): Promise<UpDataStructsProperty[]> {1380 return (await api.rpc.unique.tokenProperties(collectionId, tokenId, propertyKeys)).toHuman() as any;1381}13821383export async function createFungibleItemExpectSuccess(1384 sender: IKeyringPair,1385 collectionId: number,1386 data: CreateFungibleData,1387 owner: CrossAccountId | string = sender.address,1388) {1389 return await usingApi(async (api) => {1390 const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), {Fungible: data});13911392 const events = await submitTransactionAsync(sender, tx);1393 const result = getCreateItemResult(events);13941395 expect(result.success).to.be.true;1396 return result.itemId;1397 });1398}13991400export async function createMultipleItemsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {1401 await usingApi(async (api) => {1402 const to = normalizeAccountId(owner);1403 const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);14041405 const events = await submitTransactionAsync(sender, tx);1406 expect(getGenericResult(events).success).to.be.true;1407 });1408}14091410export async function createMultipleItemsWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {1411 await usingApi(async (api) => {1412 const to = normalizeAccountId(owner);1413 const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);14141415 const events = await submitTransactionAsync(sender, tx);1416 const result = getCreateItemsResult(events);14171418 for (const res of result) {1419 expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty;1420 }1421 });1422}14231424export async function createMultipleItemsExWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any) {1425 await usingApi(async (api) => {1426 const tx = api.tx.unique.createMultipleItemsEx(collectionId, itemsData);14271428 const events = await submitTransactionAsync(sender, tx);1429 const result = getCreateItemsResult(events);14301431 for (const res of result) {1432 expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty;1433 }1434 });1435}14361437export async function createItemWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, props: Array<Property>, owner: CrossAccountId | string = sender.address) {1438 let newItemId = 0;1439 await usingApi(async (api) => {1440 const to = normalizeAccountId(owner);1441 const itemCountBefore = await getLastTokenId(api, collectionId);1442 const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId);14431444 let tx;1445 if (createMode === 'Fungible') {1446 const createData = {fungible: {value: 10}};1447 tx = api.tx.unique.createItem(collectionId, to, createData as any);1448 } else if (createMode === 'ReFungible') {1449 const createData = {refungible: {pieces: 100}};1450 tx = api.tx.unique.createItem(collectionId, to, createData as any);1451 } else {1452 const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}});1453 tx = api.tx.unique.createItem(collectionId, to, data as UpDataStructsCreateItemData);1454 }14551456 const events = await submitTransactionAsync(sender, tx);1457 const result = getCreateItemResult(events);14581459 const itemCountAfter = await getLastTokenId(api, collectionId);1460 const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId);14611462 if (createMode === 'NFT') {1463 expect(await api.rpc.unique.tokenProperties(collectionId, result.itemId)).not.to.be.empty;1464 }14651466 // What to expect1467 // tslint:disable-next-line:no-unused-expression1468 expect(result.success).to.be.true;1469 if (createMode === 'Fungible') {1470 expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);1471 } else {1472 expect(itemCountAfter).to.be.equal(itemCountBefore + 1);1473 }1474 expect(collectionId).to.be.equal(result.collectionId);1475 expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());1476 expect(to).to.be.deep.equal(result.recipient);1477 newItemId = result.itemId;1478 });1479 return newItemId;1480}14811482export async function createItemWithPropsExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, props: Array<Property>, owner: CrossAccountId | string = sender.address) {1483 await usingApi(async (api) => {14841485 let tx;1486 if (createMode === 'NFT') {1487 const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}}) as UpDataStructsCreateItemData;1488 tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), data);1489 } else {1490 tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);1491 }149214931494 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1495 if(events.message && events.message.toString().indexOf('1002: Verification Error') > -1) return;1496 const result = getCreateItemResult(events);14971498 expect(result.success).to.be.false;1499 });1500}15011502export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {1503 let newItemId = 0;1504 await usingApi(async (api) => {1505 const to = normalizeAccountId(owner);1506 const itemCountBefore = await getLastTokenId(api, collectionId);1507 const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId);15081509 let tx;1510 if (createMode === 'Fungible') {1511 const createData = {fungible: {value: 10}};1512 tx = api.tx.unique.createItem(collectionId, to, createData as any);1513 } else if (createMode === 'ReFungible') {1514 const createData = {refungible: {pieces: 100}};1515 tx = api.tx.unique.createItem(collectionId, to, createData as any);1516 } else {1517 const createData = {nft: {}};1518 tx = api.tx.unique.createItem(collectionId, to, createData as any);1519 }15201521 const events = await executeTransaction(api, sender, tx);1522 const result = getCreateItemResult(events);15231524 const itemCountAfter = await getLastTokenId(api, collectionId);1525 const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId);15261527 // What to expect1528 // tslint:disable-next-line:no-unused-expression1529 expect(result.success).to.be.true;1530 if (createMode === 'Fungible') {1531 expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);1532 } else {1533 expect(itemCountAfter).to.be.equal(itemCountBefore + 1);1534 }1535 expect(collectionId).to.be.equal(result.collectionId);1536 expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());1537 expect(to).to.be.deep.equal(result.recipient);1538 newItemId = result.itemId;1539 });1540 return newItemId;1541}15421543export async function createRefungibleToken(api: ApiPromise, sender: IKeyringPair, collectionId: number, amount: bigint, owner: CrossAccountId | IKeyringPair | string = sender.address) : Promise<CreateItemResult> {1544 const createData = {refungible: {pieces: amount}};1545 const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createData as any);15461547 const events = await submitTransactionAsync(sender, tx);1548 return getCreateItemResult(events);1549}15501551export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {1552 await usingApi(async (api) => {1553 const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);15541555 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1556 const result = getCreateItemResult(events);15571558 expect(result.success).to.be.false;1559 });1560}15611562export async function setPublicAccessModeExpectSuccess(1563 sender: IKeyringPair, collectionId: number,1564 accessMode: 'Normal' | 'AllowList',1565) {1566 await usingApi(async (api) => {15671568 // Run the transaction1569 const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode});1570 const events = await submitTransactionAsync(sender, tx);1571 const result = getGenericResult(events);15721573 // Get the collection1574 const collection = await queryCollectionExpectSuccess(api, collectionId);15751576 // What to expect1577 // tslint:disable-next-line:no-unused-expression1578 expect(result.success).to.be.true;1579 expect(collection.permissions.access.toHuman()).to.be.equal(accessMode);1580 });1581}15821583export async function setPublicAccessModeExpectFail(1584 sender: IKeyringPair, collectionId: number,1585 accessMode: 'Normal' | 'AllowList',1586) {1587 await usingApi(async (api) => {15881589 // Run the transaction1590 const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode});1591 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1592 const result = getGenericResult(events);15931594 // What to expect1595 // tslint:disable-next-line:no-unused-expression1596 expect(result.success).to.be.false;1597 });1598}15991600export async function enableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) {1601 await setPublicAccessModeExpectSuccess(sender, collectionId, 'AllowList');1602}16031604export async function enableAllowListExpectFail(sender: IKeyringPair, collectionId: number) {1605 await setPublicAccessModeExpectFail(sender, collectionId, 'AllowList');1606}16071608export async function disableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) {1609 await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');1610}16111612export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {1613 await usingApi(async (api) => {16141615 // Run the transaction1616 const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled});1617 const events = await submitTransactionAsync(sender, tx);1618 const result = getGenericResult(events);1619 expect(result.success).to.be.true;16201621 // Get the collection1622 const collection = await queryCollectionExpectSuccess(api, collectionId);16231624 expect(collection.permissions.mintMode.toHuman()).to.be.equal(enabled);1625 });1626}16271628export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {1629 await setMintPermissionExpectSuccess(sender, collectionId, true);1630}16311632export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {1633 await usingApi(async (api) => {1634 // Run the transaction1635 const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled});1636 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1637 const result = getCreateCollectionResult(events);1638 // tslint:disable-next-line:no-unused-expression1639 expect(result.success).to.be.false;1640 });1641}16421643export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {1644 await usingApi(async (api) => {1645 // Run the transaction1646 const tx = api.tx.unique.setChainLimits(limits);1647 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1648 const result = getCreateCollectionResult(events);1649 // tslint:disable-next-line:no-unused-expression1650 expect(result.success).to.be.false;1651 });1652}16531654export async function isAllowlisted(api: ApiPromise, collectionId: number, address: string | CrossAccountId) {1655 return (await api.rpc.unique.allowed(collectionId, normalizeAccountId(address))).toJSON();1656}16571658export async function addToAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId | CrossAccountId) {1659 await usingApi(async (api) => {1660 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.false;16611662 // Run the transaction1663 const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));1664 const events = await submitTransactionAsync(sender, tx);1665 const result = getGenericResult(events);1666 expect(result.success).to.be.true;16671668 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;1669 });1670}16711672export async function addToAllowListAgainExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1673 await usingApi(async (api) => {16741675 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;16761677 // Run the transaction1678 const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));1679 const events = await submitTransactionAsync(sender, tx);1680 const result = getGenericResult(events);1681 expect(result.success).to.be.true;16821683 expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;1684 });1685}16861687export async function addToAllowListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1688 await usingApi(async (api) => {16891690 // Run the transaction1691 const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));1692 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1693 const result = getGenericResult(events);16941695 // What to expect1696 // tslint:disable-next-line:no-unused-expression1697 expect(result.success).to.be.false;1698 });1699}17001701export async function removeFromAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1702 await usingApi(async (api) => {1703 // Run the transaction1704 const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address));1705 const events = await submitTransactionAsync(sender, tx);1706 const result = getGenericResult(events);17071708 // What to expect1709 // tslint:disable-next-line:no-unused-expression1710 expect(result.success).to.be.true;1711 });1712}17131714export async function removeFromAllowListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1715 await usingApi(async (api) => {1716 // Run the transaction1717 const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address));1718 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1719 const result = getGenericResult(events);17201721 // What to expect1722 // tslint:disable-next-line:no-unused-expression1723 expect(result.success).to.be.false;1724 });1725}17261727export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1728 : Promise<UpDataStructsRpcCollection | null> => {1729 return (await api.rpc.unique.collectionById(collectionId)).unwrapOr(null);1730};17311732export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1733 // set global object - collectionsCount1734 return (await api.rpc.unique.collectionStats()).created.toNumber();1735};17361737export async function queryCollectionExpectSuccess(api: ApiPromise, collectionId: number): Promise<UpDataStructsRpcCollection> {1738 return (await api.rpc.unique.collectionById(collectionId)).unwrap();1739}17401741export async function waitNewBlocks(blocksCount = 1): Promise<void> {1742 await usingApi(async (api) => {1743 const promise = new Promise<void>(async (resolve) => {1744 const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {1745 if (blocksCount > 0) {1746 blocksCount--;1747 } else {1748 unsubscribe();1749 resolve();1750 }1751 });1752 });1753 return promise;1754 });1755}17561757export async function repartitionRFT(1758 api: ApiPromise,1759 collectionId: number,1760 sender: IKeyringPair,1761 tokenId: number,1762 amount: bigint,1763): Promise<boolean> {1764 const tx = api.tx.unique.repartition(collectionId, tokenId, amount);1765 const events = await submitTransactionAsync(sender, tx);1766 const result = getGenericResult(events);17671768 return result.success;1769}17701771export async function itApi(name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) {1772 let i: any = it;1773 if (opts.only) i = i.only;1774 else if (opts.skip) i = i.skip;1775 i(name, async () => {1776 await usingApi(async (api, privateKeyWrapper) => {1777 await cb({api, privateKeyWrapper});1778 });1779 });1780}17811782itApi.only = (name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itApi(name, cb, {only: true});1783itApi.skip = (name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itApi(name, cb, {skip: true});178417851786export async function expectSubstrateEventsAtBlock(api: ApiPromise, blockNumber: AnyNumber | BlockNumber, section: string, methods: string[], dryRun = false) {1787 const blockHash = await api.rpc.chain.getBlockHash(blockNumber);1788 const subEvents = (await api.query.system.events.at(blockHash))1789 .filter(x => x.event.section === section)1790 .map((x) => x.toHuman());1791 const events = methods.map((m) => {1792 return {1793 event: {1794 method: m,1795 section,1796 },1797 };1798 });1799 if (!dryRun) {1800 expect(subEvents).to.be.like(events);1801 }1802 return subEvents;1803}tests/src/util/playgrounds/index.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/index.ts
+++ b/tests/src/util/playgrounds/index.ts
@@ -2,39 +2,16 @@
// SPDX-License-Identifier: Apache-2.0
import {IKeyringPair} from '@polkadot/types/types';
+import {Context} from 'mocha';
import config from '../../config';
import '../../interfaces/augment-api-events';
-import {DevUniqueHelper} from './unique.dev';
+import {DevUniqueHelper, SilentLogger, SilentConsole} from './unique.dev';
-class SilentLogger {
- log(msg: any, level: any): void { }
- level = {
- ERROR: 'ERROR' as const,
- WARNING: 'WARNING' as const,
- INFO: 'INFO' as const,
- };
-}
export const usingPlaygrounds = async (code: (helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>) => {
- // TODO: Remove, this is temporary: Filter unneeded API output
- // (Jaco promised it will be removed in the next version)
- const consoleErr = console.error;
- const consoleLog = console.log;
- const consoleWarn = console.warn;
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
- const outFn = (printer: any) => (...args: any[]) => {
- for (const arg of args) {
- if (typeof arg !== 'string')
- continue;
- if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
- return;
- }
- printer(...args);
- };
-
- console.error = outFn(consoleErr.bind(console));
- console.log = outFn(consoleLog.bind(console));
- console.warn = outFn(consoleWarn.bind(console));
const helper = new DevUniqueHelper(new SilentLogger());
try {
@@ -45,8 +22,42 @@
}
finally {
await helper.disconnect();
- console.error = consoleErr;
- console.log = consoleLog;
- console.warn = consoleWarn;
+ silentConsole.disable();
}
};
+
+export enum Pallets {
+ Inflation = 'inflation',
+ RmrkCore = 'rmrkcore',
+ RmrkEquip = 'rmrkequip',
+ ReFungible = 'refungible',
+ Fungible = 'fungible',
+ NFT = 'nonfungible',
+ Scheduler = 'scheduler',
+}
+
+export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) {
+ const missingPallets = helper.fetchMissingPalletNames(requiredPallets);
+
+ if (missingPallets.length > 0) {
+ const skipMsg = `\tSkipping test '${test.test?.title}'.\n\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
+ console.warn('\x1b[38:5:208m%s\x1b[0m', skipMsg);
+ test.skip();
+ }
+}
+
+export async function itSub(name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+ (opts.only ? it.only :
+ opts.skip ? it.skip : it)(name, async function () {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ if (opts.requiredPallets) {
+ requirePalletsOrSkip(this, helper, opts.requiredPallets);
+ }
+
+ await cb({helper, privateKey});
+ });
+ });
+}
+itSub.only = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itSub(name, cb, {only: true});
+itSub.skip = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itSub(name, cb, {skip: true});
+itSub.ifWithPallets = (name: string, required: string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itSub(name, cb, {requiredPallets: required});
tests/src/util/playgrounds/types.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/types.ts
+++ b/tests/src/util/playgrounds/types.ts
@@ -101,10 +101,27 @@
tokenId: number;
}
+export interface IBlock {
+ extrinsics: IExtrinsic[]
+ header: {
+ parentHash: string,
+ number: number,
+ };
+}
+
+export interface IExtrinsic {
+ isSigned: boolean,
+ method: {
+ method: string,
+ section: string,
+ args: any[]
+ }
+}
+
export interface ICollectionCreationOptions {
- name: string | number[];
- description: string | number[];
- tokenPrefix: string | number[];
+ name?: string | number[];
+ description?: string | number[];
+ tokenPrefix?: string | number[];
mode?: {
nft?: null;
refungible?: null;
@@ -123,8 +140,15 @@
tokenSymbol: string[]
}
+export interface ISubstrateBalance {
+ free: bigint,
+ reserved: bigint,
+ miscFrozen: bigint,
+ feeFrozen: bigint
+}
+
export type TSubstrateAccount = string;
export type TEthereumAccount = string;
export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
-export type TSigner = IKeyringPair; // | 'string'
\ No newline at end of file
+export type TSigner = IKeyringPair; // | 'string'
tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -5,22 +5,69 @@
import {UniqueHelper} from './unique';
import {ApiPromise, WsProvider} from '@polkadot/api';
import * as defs from '../../interfaces/definitions';
-import {TSigner} from './types';
import {IKeyringPair} from '@polkadot/types/types';
+export class SilentLogger {
+ log(_msg: any, _level: any): void { }
+ level = {
+ ERROR: 'ERROR' as const,
+ WARNING: 'WARNING' as const,
+ INFO: 'INFO' as const,
+ };
+}
+
+export class SilentConsole {
+ // TODO: Remove, this is temporary: Filter unneeded API output
+ // (Jaco promised it will be removed in the next version)
+ consoleErr: any;
+ consoleLog: any;
+ consoleWarn: any;
+
+ constructor() {
+ this.consoleErr = console.error;
+ this.consoleLog = console.log;
+ this.consoleWarn = console.warn;
+ }
+
+ enable() {
+ const outFn = (printer: any) => (...args: any[]) => {
+ for (const arg of args) {
+ if (typeof arg !== 'string')
+ continue;
+ if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
+ return;
+ }
+ printer(...args);
+ };
+
+ console.error = outFn(this.consoleErr.bind(console));
+ console.log = outFn(this.consoleLog.bind(console));
+ console.warn = outFn(this.consoleWarn.bind(console));
+ }
+
+ disable() {
+ console.error = this.consoleErr;
+ console.log = this.consoleLog;
+ console.warn = this.consoleWarn;
+ }
+}
+
+
export class DevUniqueHelper extends UniqueHelper {
/**
* Arrange methods for tests
*/
arrange: ArrangeGroup;
+ wait: WaitGroup;
constructor(logger: { log: (msg: any, level: any) => void, level: any }) {
super(logger);
this.arrange = new ArrangeGroup(this);
+ this.wait = new WaitGroup(this);
}
- async connect(wsEndpoint: string, listeners?: any): Promise<void> {
+ async connect(wsEndpoint: string, _listeners?: any): Promise<void> {
const wsProvider = new WsProvider(wsEndpoint);
this.api = new ApiPromise({
provider: wsProvider,
@@ -36,6 +83,7 @@
},
rpc: {
unique: defs.unique.rpc,
+ appPromotion: defs.appPromotion.rpc,
rmrk: defs.rmrk.rpc,
eth: {
feeHistory: {
@@ -72,20 +120,21 @@
*/
createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {
let nonce = await this.helper.chain.getNonce(donor.address);
+ const ss58Format = this.helper.chain.getChainProperties().ss58Format;
const tokenNominal = this.helper.balance.getOneTokenNominal();
const transactions = [];
const accounts: IKeyringPair[] = [];
for (const balance of balances) {
- const recepient = this.helper.util.fromSeed(mnemonicGenerate());
- accounts.push(recepient);
+ const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
+ accounts.push(recipient);
if (balance !== 0n) {
- const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);
+ const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, balance * tokenNominal]);
transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));
nonce++;
}
}
- await Promise.all(transactions).catch(e => {});
+ await Promise.all(transactions).catch(_e => {});
//#region TODO remove this region, when nonce problem will be solved
const checkBalances = async () => {
@@ -105,7 +154,7 @@
for (let index = 0; index < 5; index++) {
accountsCreated = await checkBalances();
if(accountsCreated) break;
- await this.waitNewBlocks(1);
+
}
if (!accountsCreated) throw Error('Accounts generation failed');
@@ -114,12 +163,86 @@
return accounts;
};
+ // TODO combine this method and createAccounts into one
+ createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {
+ const createAsManyAsCan = async () => {
+ let transactions: any = [];
+ const accounts: IKeyringPair[] = [];
+ let nonce = await this.helper.chain.getNonce(donor.address);
+ const tokenNominal = this.helper.balance.getOneTokenNominal();
+ for (let i = 0; i < accountsToCreate; i++) {
+ if (i === 500) { // if there are too many accounts to create
+ await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled
+ transactions = []; //
+ nonce = await this.helper.chain.getNonce(donor.address); // update nonce
+ }
+ const recepient = this.helper.util.fromSeed(mnemonicGenerate());
+ accounts.push(recepient);
+ if (withBalance !== 0n) {
+ const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, withBalance * tokenNominal]);
+ transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));
+ nonce++;
+ }
+ }
+
+ const fullfilledAccounts = [];
+ await Promise.allSettled(transactions);
+ for (const account of accounts) {
+ const accountBalance = await this.helper.balance.getSubstrate(account.address);
+ if (accountBalance === withBalance * tokenNominal) {
+ fullfilledAccounts.push(account);
+ }
+ }
+ return fullfilledAccounts;
+ };
+
+
+ const crowd: IKeyringPair[] = [];
+ // do up to 5 retries
+ for (let index = 0; index < 5 && accountsToCreate !== 0; index++) {
+ const asManyAsCan = await createAsManyAsCan();
+ crowd.push(...asManyAsCan);
+ accountsToCreate -= asManyAsCan.length;
+ }
+
+ if (accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);
+
+ return crowd;
+ };
+
+ isDevNode = async () => {
+ const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));
+ const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));
+ const findCreationDate = async (block: any) => {
+ const humanBlock = block.toHuman();
+ let date;
+ humanBlock.block.extrinsics.forEach((ext: any) => {
+ if(ext.method.section === 'timestamp') {
+ date = Number(ext.method.args.now.replaceAll(',', ''));
+ }
+ });
+ return date;
+ };
+ const block1date = await findCreationDate(block1);
+ const block2date = await findCreationDate(block2);
+ if(block2date! - block1date! < 9000) return true;
+ };
+}
+
+class WaitGroup {
+ helper: UniqueHelper;
+
+ constructor(helper: UniqueHelper) {
+ this.helper = helper;
+ }
+
/**
* Wait for specified bnumber of blocks
* @param blocksCount number of blocks to wait
* @returns
*/
- async waitNewBlocks(blocksCount = 1): Promise<void> {
+ async newBlocks(blocksCount = 1): Promise<void> {
+ // eslint-disable-next-line no-async-promise-executor
const promise = new Promise<void>(async (resolve) => {
const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {
if (blocksCount > 0) {
@@ -132,4 +255,27 @@
});
return promise;
}
-}
\ No newline at end of file
+
+ async forParachainBlockNumber(blockNumber: bigint) {
+ return new Promise<void>(async (resolve) => {
+ const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(async (data: any) => {
+ if (data.number.toNumber() >= blockNumber) {
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ }
+
+ async forRelayBlockNumber(blockNumber: bigint) {
+ return new Promise<void>(async (resolve) => {
+ const unsubscribe = await this.helper.api!.query.parachainSystem.validationData(async (data: any) => {
+ if (data.value.relayParentNumber.toNumber() >= blockNumber) {
+ // @ts-ignore
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ }
+}
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -9,15 +9,14 @@
import {ApiInterfaceEvents} from '@polkadot/api/types';
import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
import {IKeyringPair} from '@polkadot/types/types';
-import {IApiListeners, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
+import {IApiListeners, IBlock, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
-const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
+export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
const address = {} as ICrossAccountId;
if(lowerAddress.substrate) address.Substrate = lowerAddress.substrate;
if(lowerAddress.ethereum) address.Ethereum = lowerAddress.ethereum;
return address;
};
-
const nesting = {
toChecksumAddress(address: string): string {
@@ -91,9 +90,9 @@
return encodeAddress(decodeAddress(address), ss58Format);
}
- static extractCollectionIdFromCreationResult(creationResult: ITransactionResult, label = 'new collection') {
+ static extractCollectionIdFromCreationResult(creationResult: ITransactionResult) {
if (creationResult.status !== this.transactionStatus.SUCCESS) {
- throw Error(`Unable to create collection for ${label}`);
+ throw Error('Unable to create collection!');
}
let collectionId = null;
@@ -104,15 +103,15 @@
});
if (collectionId === null) {
- throw Error(`No CollectionCreated event for ${label}`);
+ throw Error('No CollectionCreated event was found!');
}
return collectionId;
}
- static extractTokensFromCreationResult(creationResult: ITransactionResult, label = 'new tokens') {
+ static extractTokensFromCreationResult(creationResult: ITransactionResult) {
if (creationResult.status !== this.transactionStatus.SUCCESS) {
- throw Error(`Unable to create tokens for ${label}`);
+ throw Error('Unable to create tokens!');
}
let success = false;
const tokens = [] as any;
@@ -130,9 +129,9 @@
return {success, tokens};
}
- static extractTokensFromBurnResult(burnResult: ITransactionResult, label = 'burned tokens') {
+ static extractTokensFromBurnResult(burnResult: ITransactionResult) {
if (burnResult.status !== this.transactionStatus.SUCCESS) {
- throw Error(`Unable to burn tokens for ${label}`);
+ throw Error('Unable to burn tokens!');
}
let success = false;
const tokens = [] as any;
@@ -150,7 +149,7 @@
return {success, tokens};
}
- static findCollectionInEvents(events: {event: IChainEvent}[], collectionId: number, expectedSection: string, expectedMethod: string, label?: string) {
+ static findCollectionInEvents(events: {event: IChainEvent}[], collectionId: number, expectedSection: string, expectedMethod: string) {
let eventId = null;
events.forEach(({event: {data, method, section}}) => {
if ((section === expectedSection) && (method === expectedMethod)) {
@@ -159,7 +158,7 @@
});
if (eventId === null) {
- throw Error(`No ${expectedMethod} event for ${label}`);
+ throw Error(`No ${expectedMethod} event was found!`);
}
return eventId === collectionId;
}
@@ -317,6 +316,7 @@
if(options !== null) return transaction.signAndSend(sender, options, callback);
return transaction.signAndSend(sender, callback);
};
+ // eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
const unsub = await sign((result: any) => {
@@ -364,7 +364,7 @@
return call(...params);
}
- async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=false, failureMessage='expected success') {
+ async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=false/*, failureMessage='expected success'*/) {
if(this.api === null) throw Error('API not initialized');
if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);
@@ -388,6 +388,7 @@
type: this.chainLogType.EXTRINSIC,
status: result.status,
call: extrinsic,
+ signer: this.getSignerAddress(sender),
params,
} as IUniqueHelperLog;
@@ -396,7 +397,7 @@
this.chainLog.push(log);
- if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) throw Error(failureMessage);
+ if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) throw Error(`${result.moduleError}`);
return result;
}
@@ -438,6 +439,16 @@
if(typeof signer === 'string') return signer;
return signer.address;
}
+
+ fetchAllPalletNames(): string[] {
+ if(this.api === null) throw Error('API not initialized');
+ return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());
+ }
+
+ fetchMissingPalletNames(requiredPallets: string[]): string[] {
+ const palletNames = this.fetchAllPalletNames();
+ return requiredPallets.filter(p => !palletNames.includes(p));
+ }
}
@@ -474,7 +485,9 @@
}
/**
- * Get information about the collection with additional data, including the number of tokens it contains, its administrators, the normalized address of the collection's owner, and decoded name and description.
+ * Get information about the collection with additional data,
+ * including the number of tokens it contains, its administrators,
+ * the normalized address of the collection's owner, and decoded name and description.
*
* @param collectionId ID of collection
* @example await getData(2)
@@ -502,42 +515,50 @@
collectionData[key] = this.helper.util.vec2str(humanCollection[key]);
}
- collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode)) ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId) : 0;
+ collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))
+ ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)
+ : 0;
collectionData.admins = await this.getAdmins(collectionId);
return collectionData;
}
/**
- * Get the normalized addresses of the collection's administrators.
+ * Get the addresses of the collection's administrators, optionally normalized.
*
* @param collectionId ID of collection
+ * @param normalize whether to normalize the addresses to the default ss58 format
* @example await getAdmins(1)
* @returns array of administrators
*/
- async getAdmins(collectionId: number): Promise<ICrossAccountId[]> {
- const normalized = [];
- for(const admin of (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman()) {
- if(admin.Substrate) normalized.push({Substrate: this.helper.address.normalizeSubstrate(admin.Substrate)});
- else normalized.push(admin);
- }
- return normalized;
+ async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
+ const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();
+
+ return normalize
+ ? admins.map((address: any) => {
+ return address.Substrate
+ ? {Substrate: this.helper.address.normalizeSubstrate(address.Substrate)}
+ : address;
+ })
+ : admins;
}
/**
- * Get the normalized addresses added to the collection allow-list.
+ * Get the addresses added to the collection allow-list, optionally normalized.
* @param collectionId ID of collection
+ * @param normalize whether to normalize the addresses to the default ss58 format
* @example await getAllowList(1)
* @returns array of allow-listed addresses
*/
- async getAllowList(collectionId: number): Promise<ICrossAccountId[]> {
- const normalized = [];
+ async getAllowList(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();
- for (const address of allowListed) {
- if (address.Substrate) normalized.push({Substrate: this.helper.address.normalizeSubstrate(address.Substrate)});
- else normalized.push(address);
- }
- return normalized;
+ return normalize
+ ? allowListed.map((address: any) => {
+ return address.Substrate
+ ? {Substrate: this.helper.address.normalizeSubstrate(address.Substrate)}
+ : address;
+ })
+ : allowListed;
}
/**
@@ -556,40 +577,36 @@
*
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param label extra label for log
* @example await helper.collection.burn(aliceKeyring, 3);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async burn(signer: TSigner, collectionId: number, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async burn(signer: TSigner, collectionId: number): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.destroyCollection', [collectionId],
- true, `Unable to burn collection for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');
}
/**
- * Sets the sponsor for the collection (Requires the Substrate address).
+ * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.
*
* @param signer keyring of signer
* @param collectionId ID of collection
* @param sponsorAddress Sponsor substrate address
- * @param label extra label for log
* @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],
- true, `Unable to set collection sponsor for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet');
}
/**
@@ -597,19 +614,35 @@
*
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param label extra label for log
* @example confirmSponsorship(aliceKeyring, 10)
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async confirmSponsorship(signer: TSigner, collectionId: number, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.confirmSponsorship', [collectionId],
- true, `Unable to confirm collection sponsorship for ${label}`,
+ true,
+ );
+
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed');
+ }
+
+ /**
+ * Removes the sponsor of a collection, regardless if it consented or not.
+ *
+ * @param signer keyring of signer
+ * @param collectionId ID of collection
+ * @example removeSponsor(aliceKeyring, 10)
+ * @returns ```true``` if extrinsic success, otherwise ```false```
+ */
+ async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {
+ const result = await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.unique.removeCollectionSponsor', [collectionId],
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved');
}
/**
@@ -618,7 +651,6 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param limits collection limits object
- * @param label extra label for log
* @example
* await setLimits(
* aliceKeyring,
@@ -630,15 +662,14 @@
* )
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.setCollectionLimits', [collectionId, limits],
- true, `Unable to set collection limits for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet');
}
/**
@@ -647,19 +678,17 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param ownerAddress substrate address of new owner
- * @param label extra label for log
* @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],
- true, `Unable to change collection owner for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged');
}
/**
@@ -668,80 +697,71 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param adminAddressObj Administrator address (substrate or ethereum)
- * @param label extra label for log
* @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],
- true, `Unable to add collection admin for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded');
}
/**
- * Adds an address to allow list
+ * Removes a collection administrator.
+ *
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param addressObj address to add to the allow list
- * @param label extra label for log
+ * @param adminAddressObj Administrator address (substrate or ethereum)
+ * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
- 'api.tx.unique.addToAllowList', [collectionId, addressObj],
- true, `Unable to add address to allow list for ${label}`,
+ 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');
}
/**
- * Removes an address from allow list.
- *
+ * Adds an address to allow list
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param addressObj address to be removed from allow list (substrate or ethereum)
- * @param label extra label for log
- * @example removeFromAllowList(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @param addressObj address to add to the allow list
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
- 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],
- true, `Unable to remove address from allow list for ${label}`,
+ 'api.tx.unique.addToAllowList', [collectionId, addressObj],
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');
}
/**
- * Removes a collection administrator.
+ * Removes an address from allow list
*
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param adminAddressObj Administrator address (substrate or ethereum)
- * @param label extra label for log
- * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
+ * @param addressObj address to remove from the allow list
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
- 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],
- true, `Unable to remove collection admin for ${label}`,
+ 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved');
}
/**
@@ -750,19 +770,17 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param permissions collection permissions object
- * @param label extra label for log
* @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.setCollectionPermissions', [collectionId, permissions],
- true, `Unable to set collection permissions for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet');
}
/**
@@ -771,12 +789,11 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param permissions nesting permissions object
- * @param label extra label for log
* @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions, label?: string): Promise<boolean> {
- return await this.setPermissions(signer, collectionId, {nesting: permissions}, label);
+ async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {
+ return await this.setPermissions(signer, collectionId, {nesting: permissions});
}
/**
@@ -784,12 +801,11 @@
*
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param label extra label for log
* @example disableNesting(aliceKeyring, 10);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async disableNesting(signer: TSigner, collectionId: number, label?: string): Promise<boolean> {
- return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}}, label);
+ async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {
+ return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});
}
/**
@@ -798,19 +814,17 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param properties array of property objects
- * @param label extra label for log
* @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async setProperties(signer: TSigner, collectionId: number, properties: IProperty[], label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.setCollectionProperties', [collectionId, properties],
- true, `Unable to set collection properties for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');
}
/**
@@ -819,19 +833,17 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param propertyKeys array of property keys to delete
- * @param label
* @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[], label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],
- true, `Unable to delete collection properties for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');
}
/**
@@ -849,7 +861,7 @@
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],
- true, `Unable to transfer token #${tokenId} from collection #${collectionId}`,
+ true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,
);
return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);
@@ -872,7 +884,7 @@
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],
- true, `Unable to transfer token #${tokenId} from collection #${collectionId}`,
+ true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,
);
return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
}
@@ -884,22 +896,20 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param label
* @param amount amount of tokens to be burned. For NFT must be set to 1n
* @example burnToken(aliceKeyring, 10, 5);
* @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null```
*/
- async burnToken(signer: TSigner, collectionId: number, tokenId: number, label?: string, amount=1n): Promise<{
+ async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<{
success: boolean,
token: number | null
}> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
const burnResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.burnItem', [collectionId, tokenId, amount],
- true, `Unable to burn token for ${label}`,
+ true, // `Unable to burn token for ${label}`,
);
- const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult, label);
+ const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);
if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');
return {success: burnedTokens.success, token: burnedTokens.tokens.length > 0 ? burnedTokens.tokens[0] : null};
}
@@ -911,19 +921,17 @@
* @param collectionId ID of collection
* @param fromAddressObj address on behalf of which the token will be burnt
* @param tokenId ID of token
- * @param label
* @param amount amount of tokens to be burned. For NFT must be set to 1n
* @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async burnTokenFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, tokenId: number, label?: string, amount=1n): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async burnTokenFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, tokenId: number, amount=1n): Promise<boolean> {
const burnResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],
- true, `Unable to burn token from for ${label}`,
+ true, // `Unable to burn token from for ${label}`,
);
- const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult, label);
+ const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);
return burnedTokens.success && burnedTokens.tokens.length > 0;
}
@@ -933,28 +941,27 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param toAddressObj
- * @param label
+ * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
* @param amount amount of token to be approved. For NFT must be set to 1n
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, label?: string, amount=1n) {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {
const approveResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],
- true, `Unable to approve token for ${label}`,
+ true, // `Unable to approve token for ${label}`,
);
- return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved', label);
+ return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');
}
/**
- * Get the amount of token pieces approved to transfer
+ * Get the amount of token pieces approved to transfer or burn. Normally 0.
+ *
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param toAccountObj
- * @param fromAccountObj
+ * @param toAccountObj address which is approved to use token pieces
+ * @param fromAccountObj address which may have allowed the use of its owned tokens
* @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})
* @returns number of approved to transfer pieces
*/
@@ -963,7 +970,8 @@
}
/**
- * Get the last created token id
+ * Get the last created token ID in a collection
+ *
* @param collectionId ID of collection
* @example getLastTokenId(10);
* @returns id of the last created token
@@ -974,6 +982,7 @@
/**
* Check if token exists
+ *
* @param collectionId ID of collection
* @param tokenId ID of token
* @example isTokenExists(10, 20);
@@ -999,14 +1008,15 @@
/**
* Get token data
+ *
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param blockHashAt
- * @param propertyKeys
+ * @param propertyKeys optionally filter the token properties to only these keys
+ * @param blockHashAt optionally query the data at some block with this hash
* @example getToken(10, 5);
* @returns human readable token data
*/
- async getToken(collectionId: number, tokenId: number, blockHashAt?: string, propertyKeys?: string[]): Promise<{
+ async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{
properties: IProperty[];
owner: ICrossAccountId;
normalizedOwner: ICrossAccountId;
@@ -1016,7 +1026,7 @@
tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);
}
else {
- if(typeof propertyKeys === 'undefined') {
+ if(propertyKeys.length == 0) {
const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();
if(!collection) return null;
propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);
@@ -1035,45 +1045,43 @@
/**
* Set permissions to change token properties
+ *
* @param signer keyring of signer
* @param collectionId ID of collection
* @param permissions permissions to change a property by the collection owner or admin
- * @param label
* @example setTokenPropertyPermissions(
* aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]
* )
* @returns true if extrinsic success otherwise false
*/
- async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[], label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],
- true, `Unable to set token property permissions for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');
}
/**
* Set token properties
+ *
* @param signer keyring of signer
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param properties
- * @param label
+ * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection
* @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[], label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `token #${tokenId} from collection #${collectionId}`;
+ async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],
- true, `Unable to set token properties for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');
}
/**
@@ -1082,31 +1090,29 @@
* @param collectionId ID of collection
* @param tokenId ID of token
* @param propertyKeys property keys to be deleted
- * @param label
* @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[], label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `token #${tokenId} from collection #${collectionId}`;
+ async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {
const result = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],
- true, `Unable to delete token properties for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted', label);
+ return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');
}
/**
* Mint new collection
+ *
* @param signer keyring of signer
* @param collectionOptions basic collection options and properties
* @param mode NFT or RFT type of a collection
- * @param errorLabel
* @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")
* @returns object of the created collection
*/
- async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT', errorLabel = 'Unable to mint collection'): Promise<UniqueCollectionBase> {
+ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueCollectionBase> {
collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};
for (const key of ['name', 'description', 'tokenPrefix']) {
@@ -1115,16 +1121,16 @@
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createCollectionEx', [collectionOptions],
- true, errorLabel,
+ true, // errorLabel,
);
- return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult, errorLabel));
+ return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
}
- getCollectionObject(collectionId: number): any {
+ getCollectionObject(_collectionId: number): any {
return null;
}
- getTokenObject(collectionId: number, tokenId: number): any {
+ getTokenObject(_collectionId: number, _tokenId: number): any {
return null;
}
}
@@ -1156,7 +1162,7 @@
* Get token's owner
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param blockHashAt
+ * @param blockHashAt optionally query the data at the block with this hash
* @example getTokenOwner(10, 5);
* @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}
*/
@@ -1238,7 +1244,7 @@
* Get tokens nested in the provided token
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param blockHashAt
+ * @param blockHashAt optionally query the data at the block with this hash
* @example getTokenChildren(10, 5);
* @returns tokens whose depth of nesting is <= 5
*/
@@ -1260,15 +1266,14 @@
* @param signer keyring of signer
* @param tokenObj token to be nested
* @param rootTokenObj token to be parent
- * @param label
* @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, label='nest token'): Promise<boolean> {
+ async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {
const rootTokenAddress = {Ethereum: this.helper.util.getNestingTokenAddress(rootTokenObj.collectionId, rootTokenObj.tokenId)};
const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);
if(!result) {
- throw Error(`Unable to nest token for ${label}`);
+ throw Error('Unable to nest token!');
}
return result;
}
@@ -1279,15 +1284,14 @@
* @param tokenObj token to unnest
* @param rootTokenObj parent of a token
* @param toAddressObj address of a new token owner
- * @param label
* @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId, label='unnest token'): Promise<boolean> {
+ async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {
const rootTokenAddress = {Ethereum: this.helper.util.getNestingTokenAddress(rootTokenObj.collectionId, rootTokenObj.tokenId)};
const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);
if(!result) {
- throw Error(`Unable to unnest token for ${label}`);
+ throw Error('Unable to unnest token!');
}
return result;
}
@@ -1296,7 +1300,6 @@
* Mint new collection
* @param signer keyring of signer
* @param collectionOptions Collection options
- * @param label
* @example
* mintCollection(aliceKeyring, {
* name: 'New',
@@ -1305,19 +1308,17 @@
* })
* @returns object of the created collection
*/
- async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, label = 'new collection'): Promise<UniqueNFTCollection> {
- return await super.mintCollection(signer, collectionOptions, 'NFT', `Unable to mint NFT collection for ${label}`) as UniqueNFTCollection;
+ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions): Promise<UniqueNFTCollection> {
+ return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;
}
/**
* Mint new token
* @param signer keyring of signer
* @param data token data
- * @param label
* @returns created token object
*/
- async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }, label?: string): Promise<UniqueNFTToken> {
- if(typeof label === 'undefined') label = `collection #${data.collectionId}`;
+ async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFTToken> {
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
@@ -1325,9 +1326,9 @@
properties: data.properties,
},
}],
- true, `Unable to mint NFT token for ${label}`,
+ true,
);
- const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult, label);
+ const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);
if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');
if (createdTokens.tokens.length < 1) throw Error('No tokens minted');
return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
@@ -1338,7 +1339,6 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param tokens array of tokens with owner and properties
- * @param label
* @example
* mintMultipleTokens(aliceKeyring, 10, [{
* owner: {Substrate: "5DyN4Y92vZCjv38fg..."},
@@ -1349,15 +1349,14 @@
* }]);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[], label?: string): Promise<UniqueNFTToken[]> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFTToken[]> {
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],
- true, `Unable to mint NFT tokens for ${label}`,
+ true,
);
const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
}
/**
@@ -1366,7 +1365,6 @@
* @param collectionId ID of collection
* @param owner tokens owner
* @param tokens array of tokens with owner and properties
- * @param label
* @example
* mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{
* properties: [{
@@ -1379,8 +1377,7 @@
* }]);
* @returns array of newly created tokens
*/
- async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[], label?: string): Promise<UniqueNFTToken[]> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFTToken[]> {
const rawTokens = [];
for (const token of tokens) {
const raw = {NFT: {properties: token.properties}};
@@ -1389,23 +1386,10 @@
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
- true, `Unable to mint NFT tokens for ${label}`,
+ true,
);
const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
- }
-
- /**
- * Destroys a concrete instance of NFT.
- * @param signer keyring of signer
- * @param collectionId ID of collection
- * @param tokenId ID of token
- * @param label
- * @example burnToken(aliceKeyring, 10, 5);
- * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null```
- */
- async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, label?: string): Promise<{ success: boolean; token: number | null; }> {
- return await super.burnToken(signer, collectionId, tokenId, label, 1n);
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
}
/**
@@ -1415,12 +1399,11 @@
* @param collectionId ID of collection
* @param tokenId ID of token
* @param toAddressObj address to approve
- * @param label
* @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, label?: string, amount=1n) {
- return super.approveToken(signer, collectionId, tokenId, toAddressObj, label, amount);
+ async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {
+ return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);
}
}
@@ -1480,7 +1463,7 @@
* @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=100n): Promise<boolean> {
+ async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {
return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);
}
@@ -1495,7 +1478,7 @@
* @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=100n): Promise<boolean> {
+ async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {
return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
}
@@ -1503,7 +1486,6 @@
* Mint new collection
* @param signer keyring of signer
* @param collectionOptions Collection options
- * @param label
* @example
* mintCollection(aliceKeyring, {
* name: 'New',
@@ -1512,20 +1494,18 @@
* })
* @returns object of the created collection
*/
- async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, label = 'new collection'): Promise<UniqueRFTCollection> {
- return await super.mintCollection(signer, collectionOptions, 'RFT', `Unable to mint RFT collection for ${label}`) as UniqueRFTCollection;
+ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions): Promise<UniqueRFTCollection> {
+ return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;
}
/**
* Mint new token
* @param signer keyring of signer
* @param data token data
- * @param label
* @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});
* @returns created token object
*/
- async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }, label?: string): Promise<UniqueRFTToken> {
- if(typeof label === 'undefined') label = `collection #${data.collectionId}`;
+ async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFTToken> {
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
@@ -1534,24 +1514,23 @@
properties: data.properties,
},
}],
- true, `Unable to mint RFT token for ${label}`,
+ true,
);
- const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult, label);
+ const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);
if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');
if (createdTokens.tokens.length < 1) throw Error('No tokens minted');
return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
}
- async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[], label?: string): Promise<UniqueRFTToken[]> {
+ async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFTToken[]> {
throw Error('Not implemented');
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],
- true, `Unable to mint RFT tokens for ${label}`,
+ true, // `Unable to mint RFT tokens for ${label}`,
);
const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
}
/**
@@ -1560,12 +1539,10 @@
* @param collectionId ID of collection
* @param owner tokens owner
* @param tokens array of tokens with properties and pieces
- * @param label
* @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);
* @returns array of newly created RFT tokens
*/
- async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[], label?: string): Promise<UniqueRFTToken[]> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFTToken[]> {
const rawTokens = [];
for (const token of tokens) {
const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};
@@ -1574,10 +1551,10 @@
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
- true, `Unable to mint RFT tokens for ${label}`,
+ true,
);
const collection = this.getCollectionObject(collectionId);
- return this.helper.util.extractTokensFromCreationResult(creationResult, label).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+ return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
}
/**
@@ -1585,13 +1562,12 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param tokenId ID of token
- * @param label
* @param amount number of pieces to be burnt
* @example burnToken(aliceKeyring, 10, 5);
* @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null```
*/
- async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, label?: string, amount=100n): Promise<{ success: boolean; token: number | null; }> {
- return await super.burnToken(signer, collectionId, tokenId, label, amount);
+ async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<{ success: boolean; token: number | null; }> {
+ return await super.burnToken(signer, collectionId, tokenId, amount);
}
/**
@@ -1601,13 +1577,12 @@
* @param collectionId ID of collection
* @param tokenId ID of token
* @param toAddressObj address to approve
- * @param label
* @param amount number of pieces to be approved
* @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);
* @returns true if the token success, otherwise false
*/
- async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, label?: string, amount=100n) {
- return super.approveToken(signer, collectionId, tokenId, toAddressObj, label, amount);
+ async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {
+ return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);
}
/**
@@ -1627,20 +1602,18 @@
* @param collectionId ID of collection
* @param tokenId ID of token
* @param amount new number of pieces
- * @param label
* @example repartitionToken(aliceKeyring, 10, 5, 12345n);
* @returns true if the repartion was success, otherwise false
*/
- async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {
const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);
const repartitionResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.repartition', [collectionId, tokenId, amount],
- true, `Unable to repartition RFT token for ${label}`,
+ true,
);
- if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated', label);
- return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed', label);
+ if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');
+ return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');
}
}
@@ -1661,7 +1634,6 @@
* @param signer keyring of signer
* @param collectionOptions Collection options
* @param decimalPoints number of token decimals
- * @param errorLabel
* @example
* mintCollection(aliceKeyring, {
* name: 'New',
@@ -1670,7 +1642,7 @@
* }, 18)
* @returns newly created fungible collection
*/
- async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, decimalPoints = 0, errorLabel = 'Unable to mint collection'): Promise<UniqueFTCollection> {
+ async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, decimalPoints = 0): Promise<UniqueFTCollection> {
collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');
collectionOptions.mode = {fungible: decimalPoints};
@@ -1680,9 +1652,9 @@
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createCollectionEx', [collectionOptions],
- true, errorLabel,
+ true,
);
- return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult, errorLabel));
+ return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
}
/**
@@ -1691,12 +1663,10 @@
* @param collectionId ID of collection
* @param owner address owner of new tokens
* @param amount amount of tokens to be meanted
- * @param label
* @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async mintTokens(signer: TSigner, collectionId: number, owner: ICrossAccountId | string, amount: bigint, label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async mintTokens(signer: TSigner, collectionId: number, owner: ICrossAccountId | string, amount: bigint): Promise<boolean> {
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {
@@ -1704,9 +1674,9 @@
value: amount,
},
}],
- true, `Unable to mint fungible tokens for ${label}`,
+ true, // `Unable to mint fungible tokens for ${label}`,
);
- return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated', label);
+ return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
}
/**
@@ -1715,11 +1685,9 @@
* @param collectionId ID of collection
* @param owner tokens owner
* @param tokens array of tokens with properties and pieces
- * @param label
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {value: bigint}[], label?: string): Promise<boolean> {
- if(typeof label === 'undefined') label = `collection #${collectionId}`;
+ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {value: bigint}[]): Promise<boolean> {
const rawTokens = [];
for (const token of tokens) {
const raw = {Fungible: {Value: token.value}};
@@ -1728,9 +1696,9 @@
const creationResult = await this.helper.executeExtrinsic(
signer,
'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],
- true, `Unable to mint RFT tokens for ${label}`,
+ true,
);
- return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated', label);
+ return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
}
/**
@@ -1758,12 +1726,12 @@
* Transfer tokens to address
* @param signer keyring of signer
* @param collectionId ID of collection
- * @param toAddressObj address recepient
+ * @param toAddressObj address recipient
* @param amount amount of tokens to be sent
* @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount: bigint) {
+ async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {
return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);
}
@@ -1777,7 +1745,7 @@
* @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) {
+ async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {
return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);
}
@@ -1786,12 +1754,11 @@
* @param signer keyring of signer
* @param collectionId ID of collection
* @param amount amount of tokens to be destroyed
- * @param label
* @example burnTokens(aliceKeyring, 10, 1000n);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async burnTokens(signer: IKeyringPair, collectionId: number, amount=100n, label?: string): Promise<boolean> {
- return (await super.burnToken(signer, collectionId, 0, label, amount)).success;
+ async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {
+ return (await super.burnToken(signer, collectionId, 0, amount)).success;
}
/**
@@ -1800,12 +1767,11 @@
* @param collectionId ID of collection
* @param fromAddressObj address on behalf of which tokens will be burnt
* @param amount amount of tokens to be burnt
- * @param label
* @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=100n, label?: string): Promise<boolean> {
- return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, label, amount);
+ async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {
+ return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, amount);
}
/**
@@ -1824,12 +1790,11 @@
* @param collectionId ID of collection
* @param toAddressObj address to be approved
* @param amount amount of tokens to be approved
- * @param label
* @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
- async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=100n, label?: string) {
- return super.approveToken(signer, collectionId, 0, toAddressObj, label, amount);
+ async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {
+ return super.approveToken(signer, collectionId, 0, toAddressObj, amount);
}
/**
@@ -1881,6 +1846,13 @@
return blockHash;
}
+ // TODO add docs
+ async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {
+ const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);
+ if (!blockHash) return null;
+ return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;
+ }
+
/**
* Get account nonce
* @param address substrate address
@@ -1915,6 +1887,16 @@
}
/**
+ * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved
+ * @param address substrate address
+ * @returns
+ */
+ async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {
+ const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;
+ return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};
+ }
+
+ /**
* Get ethereum address balance
* @param address ethereum address
* @example getEthereum("0x9F0583DbB855d...")
@@ -1927,13 +1909,13 @@
/**
* Transfer tokens to substrate address
* @param signer keyring of signer
- * @param address substrate address of a recepient
+ * @param address substrate address of a recipient
* @param amount amount of tokens to be transfered
* @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);
* @returns ```true``` if extrinsic success, otherwise ```false```
*/
async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {
- const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`);
+ const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);
let transfer = {from: null, to: null, amount: 0n} as any;
result.result.events.forEach(({event: {data, method, section}}) => {
@@ -2000,7 +1982,59 @@
}
}
+class StakingGroup extends HelperGroup {
+ /**
+ * Stake tokens for App Promotion
+ * @param signer keyring of signer
+ * @param amountToStake amount of tokens to stake
+ * @param label extra label for log
+ * @returns
+ */
+ async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {
+ if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;
+ const stakeResult = await this.helper.executeExtrinsic(
+ signer, 'api.tx.appPromotion.stake',
+ [amountToStake], true,
+ );
+ // TODO extract info from stakeResult
+ return true;
+ }
+ /**
+ * Unstake tokens for App Promotion
+ * @param signer keyring of signer
+ * @param amountToUnstake amount of tokens to unstake
+ * @param label extra label for log
+ * @returns block number where balances will be unlocked
+ */
+ async unstake(signer: TSigner, label?: string): Promise<number> {
+ if(typeof label === 'undefined') label = `${signer.address}`;
+ const unstakeResult = await this.helper.executeExtrinsic(
+ signer, 'api.tx.appPromotion.unstake',
+ [], true,
+ );
+ // TODO extract block number fron events
+ return 1;
+ }
+
+ async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {
+ if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();
+ return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();
+ }
+
+ async getTotalStakedPerBlock(address: ICrossAccountId): Promise<bigint[][]> {
+ return (await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);
+ }
+
+ async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {
+ return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();
+ }
+
+ async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<bigint[][]> {
+ return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]);
+ }
+}
+
export class UniqueHelper extends ChainHelperBase {
chain: ChainGroup;
balance: BalanceGroup;
@@ -2009,6 +2043,7 @@
nft: NFTGroup;
rft: RFTGroup;
ft: FTGroup;
+ staking: StakingGroup;
constructor(logger?: ILogger) {
super(logger);
@@ -2019,6 +2054,7 @@
this.nft = new NFTGroup(this);
this.rft = new RFTGroup(this);
this.ft = new FTGroup(this);
+ this.staking = new StakingGroup(this);
}
}
@@ -2056,64 +2092,72 @@
return await this.helper.collection.getEffectiveLimits(this.collectionId);
}
- async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount, label?: string) {
- return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress, label);
+ async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {
+ return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);
}
- async confirmSponsorship(signer: TSigner, label?: string) {
- return await this.helper.collection.confirmSponsorship(signer, this.collectionId, label);
+ async confirmSponsorship(signer: TSigner) {
+ return await this.helper.collection.confirmSponsorship(signer, this.collectionId);
}
- async setLimits(signer: TSigner, limits: ICollectionLimits, label?: string) {
- return await this.helper.collection.setLimits(signer, this.collectionId, limits, label);
+ async removeSponsor(signer: TSigner) {
+ return await this.helper.collection.removeSponsor(signer, this.collectionId);
}
- async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount, label?: string) {
- return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress, label);
+ async setLimits(signer: TSigner, limits: ICollectionLimits) {
+ return await this.helper.collection.setLimits(signer, this.collectionId, limits);
+ }
+
+ async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {
+ return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);
+ }
+
+ async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {
+ return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);
}
- async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) {
- return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj, label);
+ async enableCertainPermissions(signer: TSigner, accessMode: 'AllowList' | 'Normal' | undefined = 'AllowList', mintMode: boolean | undefined = true) {
+ return await this.setPermissions(signer, {access: accessMode, mintMode: mintMode});
}
- async addToAllowList(signer: TSigner, addressObj: ICrossAccountId, label?: string) {
- return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj, label);
+ async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {
+ return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);
}
- async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId, label?: string) {
- return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj, label);
+ async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {
+ return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);
}
- async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) {
- return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj, label);
+ async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {
+ return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);
}
- async setProperties(signer: TSigner, properties: IProperty[], label?: string) {
- return await this.helper.collection.setProperties(signer, this.collectionId, properties, label);
+ async setProperties(signer: TSigner, properties: IProperty[]) {
+ return await this.helper.collection.setProperties(signer, this.collectionId, properties);
}
- async deleteProperties(signer: TSigner, propertyKeys: string[], label?: string) {
- return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys, label);
+ async deleteProperties(signer: TSigner, propertyKeys: string[]) {
+ return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);
}
async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {
return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);
}
- async setPermissions(signer: TSigner, permissions: ICollectionPermissions, label?: string) {
- return await this.helper.collection.setPermissions(signer, this.collectionId, permissions, label);
+ async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {
+ return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);
}
- async enableNesting(signer: TSigner, permissions: INestingPermissions, label?: string) {
- return await this.helper.collection.enableNesting(signer, this.collectionId, permissions, label);
+ async enableNesting(signer: TSigner, permissions: INestingPermissions) {
+ return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);
}
- async disableNesting(signer: TSigner, label?: string) {
- return await this.helper.collection.disableNesting(signer, this.collectionId, label);
+ async disableNesting(signer: TSigner) {
+ return await this.helper.collection.disableNesting(signer, this.collectionId);
}
- async burn(signer: TSigner, label?: string) {
- return await this.helper.collection.burn(signer, this.collectionId, label);
+ async burn(signer: TSigner) {
+ return await this.helper.collection.burn(signer, this.collectionId);
}
}
@@ -2128,7 +2172,7 @@
}
async getToken(tokenId: number, blockHashAt?: string) {
- return await this.helper.nft.getToken(this.collectionId, tokenId, blockHashAt);
+ return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);
}
async getTokenOwner(tokenId: number, blockHashAt?: string) {
@@ -2151,44 +2195,44 @@
return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);
}
- async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, label?: string) {
- return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj, label);
+ async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {
+ return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);
}
async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {
return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);
}
- async mintToken(signer: TSigner, owner: ICrossAccountId, properties?: IProperty[], label?: string) {
- return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties}, label);
+ async mintToken(signer: TSigner, owner: ICrossAccountId, properties?: IProperty[]) {
+ return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});
}
- async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[], label?: string) {
- return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens, label);
+ async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {
+ return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);
}
- async burnToken(signer: TSigner, tokenId: number, label?: string) {
- return await this.helper.nft.burnToken(signer, this.collectionId, tokenId, label);
+ async burnToken(signer: TSigner, tokenId: number) {
+ return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);
}
- async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[], label?: string) {
- return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties, label);
+ async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {
+ return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);
}
- async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[], label?: string) {
- return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys, label);
+ async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {
+ return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);
}
- async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[], label?: string) {
- return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions, label);
+ async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {
+ return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
}
- async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken, label?: string) {
- return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj, label);
+ async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
+ return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
}
- async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId, label?: string) {
- return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj, label);
+ async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+ return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
}
}
@@ -2214,59 +2258,59 @@
return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);
}
- async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=100n) {
+ async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {
return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);
}
- async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=100n) {
+ async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {
return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);
}
- async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=100n, label?: string) {
- return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, label, amount);
+ async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {
+ return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);
}
async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);
}
- async repartitionToken(signer: TSigner, tokenId: number, amount: bigint, label?: string) {
- return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount, label);
+ async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {
+ return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);
}
- async mintToken(signer: TSigner, owner: ICrossAccountId, pieces=100n, properties?: IProperty[], label?: string) {
- return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties}, label);
+ async mintToken(signer: TSigner, owner: ICrossAccountId, pieces=100n, properties?: IProperty[]) {
+ return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});
}
- async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[], label?: string) {
- return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens, label);
+ async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]) {
+ return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);
}
- async burnToken(signer: TSigner, tokenId: number, amount=100n, label?: string) {
- return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, label, amount);
+ async burnToken(signer: TSigner, tokenId: number, amount=1n) {
+ return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);
}
- async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[], label?: string) {
- return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties, label);
+ async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {
+ return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);
}
- async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[], label?: string) {
- return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys, label);
+ async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {
+ return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);
}
- async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[], label?: string) {
- return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions, label);
+ async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {
+ return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
}
}
class UniqueFTCollection extends UniqueCollectionBase {
- async mint(signer: TSigner, owner: ICrossAccountId, amount: bigint, label?: string) {
- return await this.helper.ft.mintTokens(signer, this.collectionId, owner, amount, label);
+ async mint(signer: TSigner, owner: ICrossAccountId, amount: bigint) {
+ return await this.helper.ft.mintTokens(signer, this.collectionId, owner, amount);
}
- async mintWithOneOwner(signer: TSigner, owner: ICrossAccountId, tokens: {value: bigint}[], label?: string) {
- return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, owner, tokens, label);
+ async mintWithOneOwner(signer: TSigner, owner: ICrossAccountId, tokens: {value: bigint}[]) {
+ return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, owner, tokens);
}
async getBalance(addressObj: ICrossAccountId) {
@@ -2277,28 +2321,28 @@
return await this.helper.ft.getTop10Owners(this.collectionId);
}
- async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount: bigint) {
+ async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {
return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);
}
- async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) {
+ async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {
return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);
}
- async burnTokens(signer: TSigner, amount: bigint, label?: string) {
- return await this.helper.ft.burnTokens(signer, this.collectionId, amount, label);
+ async burnTokens(signer: TSigner, amount=1n) {
+ return await this.helper.ft.burnTokens(signer, this.collectionId, amount);
}
- async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount: bigint, label?: string) {
- return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount, label);
+ async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {
+ return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);
}
async getTotalPieces() {
return await this.helper.ft.getTotalPieces(this.collectionId);
}
- async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=100n, label?: string) {
- return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount, label);
+ async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {
+ return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);
}
async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
@@ -2322,12 +2366,12 @@
return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);
}
- async setProperties(signer: TSigner, properties: IProperty[], label?: string) {
- return await this.collection.setTokenProperties(signer, this.tokenId, properties, label);
+ async setProperties(signer: TSigner, properties: IProperty[]) {
+ return await this.collection.setTokenProperties(signer, this.tokenId, properties);
}
- async deleteProperties(signer: TSigner, propertyKeys: string[], label?: string) {
- return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys, label);
+ async deleteProperties(signer: TSigner, propertyKeys: string[]) {
+ return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);
}
}
@@ -2356,12 +2400,12 @@
return await this.collection.getTokenChildren(this.tokenId, blockHashAt);
}
- async nest(signer: TSigner, toTokenObj: IToken, label?: string) {
- return await this.collection.nestToken(signer, this.tokenId, toTokenObj, label);
+ async nest(signer: TSigner, toTokenObj: IToken) {
+ return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
}
- async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId, label?: string) {
- return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj, label);
+ async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+ return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
}
async transfer(signer: TSigner, addressObj: ICrossAccountId) {
@@ -2372,16 +2416,16 @@
return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);
}
- async approve(signer: TSigner, toAddressObj: ICrossAccountId, label?: string) {
- return await this.collection.approveToken(signer, this.tokenId, toAddressObj, label);
+ async approve(signer: TSigner, toAddressObj: ICrossAccountId) {
+ return await this.collection.approveToken(signer, this.tokenId, toAddressObj);
}
async isApproved(toAddressObj: ICrossAccountId) {
return await this.collection.isTokenApproved(this.tokenId, toAddressObj);
}
- async burn(signer: TSigner, label?: string) {
- return await this.collection.burnToken(signer, this.tokenId, label);
+ async burn(signer: TSigner) {
+ return await this.collection.burnToken(signer, this.tokenId);
}
}
@@ -2405,27 +2449,27 @@
return await this.collection.getTokenTotalPieces(this.tokenId);
}
- async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=100n) {
+ async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {
return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);
}
- async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=100n) {
+ async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {
return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);
}
- async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=100n, label?: string) {
- return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount, label);
+ async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {
+ return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);
}
async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {
return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);
}
- async repartition(signer: TSigner, amount: bigint, label?: string) {
- return await this.collection.repartitionToken(signer, this.tokenId, amount, label);
+ async repartition(signer: TSigner, amount: bigint) {
+ return await this.collection.repartitionToken(signer, this.tokenId, amount);
}
- async burn(signer: TSigner, amount=100n, label?: string) {
- return await this.collection.burnToken(signer, this.tokenId, amount, label);
+ async burn(signer: TSigner, amount=1n) {
+ return await this.collection.burnToken(signer, this.tokenId, amount);
}
}