difftreelog
Merge pull request #730 from UniqueNetwork/feature/pov-estimate-api
in: master
Feature/pov estimate api
34 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5362,6 +5362,7 @@
"substrate-wasm-builder",
"up-common",
"up-data-structs",
+ "up-pov-estimate-rpc",
"up-rpc",
"up-sponsorship",
"xcm",
@@ -5806,6 +5807,7 @@
"sp-runtime",
"sp-std",
"up-data-structs",
+ "up-pov-estimate-rpc",
]
[[package]]
@@ -8917,6 +8919,7 @@
"substrate-wasm-builder",
"up-common",
"up-data-structs",
+ "up-pov-estimate-rpc",
"up-rpc",
"up-sponsorship",
"xcm",
@@ -12824,18 +12827,34 @@
dependencies = [
"anyhow",
"app-promotion-rpc",
+ "frame-benchmarking",
"jsonrpsee",
+ "opal-runtime",
"pallet-common",
"pallet-evm",
"parity-scale-codec 3.2.1",
+ "quartz-runtime",
"rmrk-rpc",
+ "sc-client-api",
+ "sc-executor",
+ "sc-rpc-api",
+ "sc-service",
"sp-api",
"sp-blockchain",
"sp-core",
+ "sp-externalities",
+ "sp-keystore",
"sp-rpc",
"sp-runtime",
+ "sp-state-machine",
+ "sp-trie",
+ "trie-db",
+ "unique-runtime",
+ "up-common",
"up-data-structs",
+ "up-pov-estimate-rpc",
"up-rpc",
+ "zstd",
]
[[package]]
@@ -12978,10 +12997,12 @@
"substrate-prometheus-endpoint",
"tokio",
"try-runtime-cli",
+ "uc-rpc",
"unique-rpc",
"unique-runtime",
"up-common",
"up-data-structs",
+ "up-pov-estimate-rpc",
"up-rpc",
]
@@ -13032,6 +13053,7 @@
"uc-rpc",
"up-common",
"up-data-structs",
+ "up-pov-estimate-rpc",
"up-rpc",
]
@@ -13125,6 +13147,7 @@
"substrate-wasm-builder",
"up-common",
"up-data-structs",
+ "up-pov-estimate-rpc",
"up-rpc",
"up-sponsorship",
"xcm",
@@ -13194,6 +13217,19 @@
]
[[package]]
+name = "up-pov-estimate-rpc"
+version = "0.1.0"
+dependencies = [
+ "parity-scale-codec 3.2.1",
+ "scale-info",
+ "serde",
+ "sp-api",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
name = "up-rpc"
version = "0.1.3"
dependencies = [
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,7 @@
'runtime/unique',
'runtime/tests',
]
-default-members = ['node/*', 'runtime/opal']
+default-members = ['node/*', 'client/*', 'runtime/opal']
package.version = "0.9.36"
[profile.release]
client/rpc/Cargo.tomldiffbeforeafterboth--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -7,16 +7,43 @@
[dependencies]
pallet-common = { default-features = false, path = '../../pallets/common' }
up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
+up-common = { default-features = false, path = '../../primitives/common' }
up-rpc = { path = "../../primitives/rpc" }
app-promotion-rpc = { path = "../../primitives/app_promotion_rpc" }
rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
+up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", optional = true }
codec = { package = "parity-scale-codec", version = "3.1.2" }
jsonrpsee = { version = "0.16.2", features = ["server", "macros"] }
anyhow = "1.0.57"
+zstd = { version = "0.11.2", default-features = false }
+trie-db = { version = "0.24.0", default-features = false }
+sc-rpc-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-blockchain = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-keystore = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-rpc = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-trie = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
+
+frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+
+sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+
+unique-runtime = { path = '../../runtime/unique', optional = true }
+quartz-runtime = { path = '../../runtime/quartz', optional = true }
+opal-runtime = { path = '../../runtime/opal' }
+
+[features]
+pov-estimate = [
+ 'up-pov-estimate-rpc',
+ 'unique-runtime?/pov-estimate',
+ 'quartz-runtime?/pov-estimate',
+ 'opal-runtime/pov-estimate',
+]
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -42,6 +42,9 @@
pub use app_promotion_unique_rpc::AppPromotionApiServer;
pub use rmrk_unique_rpc::RmrkApiServer;
+#[cfg(feature = "pov-estimate")]
+pub mod pov_estimate;
+
#[rpc(server)]
#[async_trait]
pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {
@@ -420,17 +423,18 @@
}
}
+#[macro_export]
macro_rules! define_struct_for_server_api {
- ($name:ident) => {
- pub struct $name<C, P> {
- client: Arc<C>,
- _marker: std::marker::PhantomData<P>,
+ ($name:ident { $($arg:ident: $arg_ty:ty),+ $(,)? }) => {
+ pub struct $name<Client, Block: BlockT> {
+ $($arg: $arg_ty),+,
+ _marker: std::marker::PhantomData<Block>,
}
- impl<C, P> $name<C, P> {
- pub fn new(client: Arc<C>) -> Self {
+ impl<Client, Block: BlockT> $name<Client, Block> {
+ pub fn new($($arg: $arg_ty),+) -> Self {
Self {
- client,
+ $($arg),+,
_marker: Default::default(),
}
}
@@ -438,9 +442,23 @@
};
}
-define_struct_for_server_api!(Unique);
-define_struct_for_server_api!(AppPromotion);
-define_struct_for_server_api!(Rmrk);
+define_struct_for_server_api! {
+ Unique {
+ client: Arc<Client>
+ }
+}
+
+define_struct_for_server_api! {
+ AppPromotion {
+ client: Arc<Client>
+ }
+}
+
+define_struct_for_server_api! {
+ Rmrk {
+ client: Arc<Client>
+ }
+}
macro_rules! pass_method {
(
client/rpc/src/pov_estimate.rsdiffbeforeafterboth--- /dev/null
+++ b/client/rpc/src/pov_estimate.rs
@@ -0,0 +1,290 @@
+// 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 std::sync::Arc;
+
+use codec::{Encode, Decode};
+use sp_externalities::Extensions;
+
+use up_pov_estimate_rpc::{PovEstimateApi as PovEstimateRuntimeApi};
+use up_common::types::opaque::RuntimeId;
+
+use sc_service::{NativeExecutionDispatch, config::ExecutionStrategy};
+use sp_state_machine::{StateMachine, TrieBackendBuilder};
+use trie_db::{Trie, TrieDBBuilder};
+
+use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc};
+use anyhow::anyhow;
+
+use sc_client_api::backend::Backend;
+use sp_blockchain::HeaderBackend;
+use sp_core::{
+ Bytes,
+ offchain::{
+ testing::{TestOffchainExt, TestTransactionPoolExt},
+ OffchainDbExt, OffchainWorkerExt, TransactionPoolExt,
+ },
+ testing::TaskExecutor,
+ traits::TaskExecutorExt,
+};
+use sp_keystore::{testing::KeyStore, KeystoreExt};
+use sp_api::{AsTrieBackend, BlockId, BlockT, ProvideRuntimeApi};
+
+use sc_executor::NativeElseWasmExecutor;
+use sc_rpc_api::DenyUnsafe;
+
+use sp_runtime::traits::Header;
+
+use up_pov_estimate_rpc::{PovInfo, TrieKeyValue};
+
+use crate::define_struct_for_server_api;
+
+type HasherOf<Block> = <<Block as BlockT>::Header as Header>::Hashing;
+type StateOf<Block> = <sc_service::TFullBackend<Block> as Backend<Block>>::State;
+
+pub struct ExecutorParams {
+ pub wasm_method: sc_service::config::WasmExecutionMethod,
+ pub default_heap_pages: Option<u64>,
+ pub max_runtime_instances: usize,
+ pub runtime_cache_size: u8,
+}
+
+#[cfg(feature = "unique-runtime")]
+pub struct UniqueRuntimeExecutor;
+
+#[cfg(feature = "quartz-runtime")]
+pub struct QuartzRuntimeExecutor;
+
+pub struct OpalRuntimeExecutor;
+
+#[cfg(feature = "unique-runtime")]
+impl NativeExecutionDispatch for UniqueRuntimeExecutor {
+ type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
+
+ fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
+ unique_runtime::api::dispatch(method, data)
+ }
+
+ fn native_version() -> sc_executor::NativeVersion {
+ unique_runtime::native_version()
+ }
+}
+
+#[cfg(feature = "quartz-runtime")]
+impl NativeExecutionDispatch for QuartzRuntimeExecutor {
+ type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
+
+ fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
+ quartz_runtime::api::dispatch(method, data)
+ }
+
+ fn native_version() -> sc_executor::NativeVersion {
+ quartz_runtime::native_version()
+ }
+}
+
+impl NativeExecutionDispatch for OpalRuntimeExecutor {
+ type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
+
+ fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
+ opal_runtime::api::dispatch(method, data)
+ }
+
+ fn native_version() -> sc_executor::NativeVersion {
+ opal_runtime::native_version()
+ }
+}
+
+#[cfg(feature = "pov-estimate")]
+define_struct_for_server_api! {
+ PovEstimate {
+ client: Arc<Client>,
+ backend: Arc<sc_service::TFullBackend<Block>>,
+ deny_unsafe: DenyUnsafe,
+ exec_params: ExecutorParams,
+ runtime_id: RuntimeId,
+ }
+}
+
+#[rpc(server)]
+#[async_trait]
+pub trait PovEstimateApi<BlockHash> {
+ #[method(name = "povinfo_estimateExtrinsicPoV")]
+ fn estimate_extrinsic_pov(
+ &self,
+ encoded_xts: Vec<Bytes>,
+ at: Option<BlockHash>,
+ ) -> Result<PovInfo>;
+}
+
+#[allow(deprecated)]
+#[cfg(feature = "pov-estimate")]
+impl<C, Block> PovEstimateApiServer<<Block as BlockT>::Hash> for PovEstimate<C, Block>
+where
+ Block: BlockT,
+ C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
+ C::Api: PovEstimateRuntimeApi<Block>,
+{
+ fn estimate_extrinsic_pov(
+ &self,
+ encoded_xts: Vec<Bytes>,
+ at: Option<<Block as BlockT>::Hash>,
+ ) -> Result<PovInfo> {
+ self.deny_unsafe.check_if_safe()?;
+
+ let at = at.unwrap_or_else(|| self.client.info().best_hash);
+ let state = self
+ .backend
+ .state_at(at)
+ .map_err(|_| anyhow!("unable to fetch the state at {at:?}"))?;
+
+ match &self.runtime_id {
+ #[cfg(feature = "unique-runtime")]
+ RuntimeId::Unique => execute_extrinsic_in_sandbox::<Block, UniqueRuntimeExecutor>(
+ state,
+ &self.exec_params,
+ encoded_xts,
+ ),
+
+ #[cfg(feature = "quartz-runtime")]
+ RuntimeId::Quartz => execute_extrinsic_in_sandbox::<Block, QuartzRuntimeExecutor>(
+ state,
+ &self.exec_params,
+ encoded_xts,
+ ),
+
+ RuntimeId::Opal => execute_extrinsic_in_sandbox::<Block, OpalRuntimeExecutor>(
+ state,
+ &self.exec_params,
+ encoded_xts,
+ ),
+
+ runtime_id => Err(anyhow!("unknown runtime id {:?}", runtime_id).into()),
+ }
+ }
+}
+
+fn full_extensions() -> Extensions {
+ let mut extensions = Extensions::default();
+ extensions.register(TaskExecutorExt::new(TaskExecutor::new()));
+ let (offchain, _offchain_state) = TestOffchainExt::new();
+ let (pool, _pool_state) = TestTransactionPoolExt::new();
+ extensions.register(OffchainDbExt::new(offchain.clone()));
+ extensions.register(OffchainWorkerExt::new(offchain));
+ extensions.register(KeystoreExt(std::sync::Arc::new(KeyStore::new())));
+ extensions.register(TransactionPoolExt::new(pool));
+
+ extensions
+}
+
+fn execute_extrinsic_in_sandbox<Block, D>(
+ state: StateOf<Block>,
+ exec_params: &ExecutorParams,
+ encoded_xts: Vec<Bytes>,
+) -> Result<PovInfo>
+where
+ Block: BlockT,
+ D: NativeExecutionDispatch + 'static,
+{
+ let backend = state.as_trie_backend().clone();
+ let mut changes = Default::default();
+ let runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(backend);
+
+ let proving_backend = TrieBackendBuilder::wrap(&backend)
+ .with_recorder(Default::default())
+ .build();
+
+ let runtime_code = runtime_code_backend
+ .runtime_code()
+ .map_err(|_| anyhow!("runtime code backend creation failed"))?;
+
+ let pre_root = *backend.root();
+
+ let executor = NativeElseWasmExecutor::<D>::new(
+ exec_params.wasm_method,
+ exec_params.default_heap_pages,
+ exec_params.max_runtime_instances,
+ exec_params.runtime_cache_size,
+ );
+ let execution = ExecutionStrategy::NativeElseWasm;
+
+ let mut results = Vec::new();
+
+ for encoded_xt in encoded_xts {
+ let encoded_bytes = encoded_xt.encode();
+
+ let xt_result = StateMachine::new(
+ &proving_backend,
+ &mut changes,
+ &executor,
+ "PovEstimateApi_pov_estimate",
+ encoded_bytes.as_slice(),
+ full_extensions(),
+ &runtime_code,
+ sp_core::testing::TaskExecutor::new(),
+ )
+ .execute(execution.into())
+ .map_err(|e| anyhow!("failed to execute the extrinsic {:?}", e))?;
+
+ let xt_result = Decode::decode(&mut &*xt_result)
+ .map_err(|e| anyhow!("failed to decode the extrinsic result {:?}", e))?;
+
+ results.push(xt_result);
+ }
+
+ let root = proving_backend.root().clone();
+
+ let proof = proving_backend
+ .extract_proof()
+ .expect("A recorder was set and thus, a storage proof can be extracted; qed");
+ let proof_size = proof.encoded_size();
+
+ let memory_db = proof.clone().into_memory_db();
+
+ let tree_db =
+ TrieDBBuilder::<sp_trie::LayoutV1<HasherOf<Block>>>::new(&memory_db, &root).build();
+
+ let key_values = tree_db
+ .iter()
+ .map_err(|e| anyhow!("failed to retrieve tree db key values: {:?}", e))?
+ .filter_map(|item| {
+ let item = item.ok()?;
+
+ Some(TrieKeyValue {
+ key: item.0,
+ value: item.1,
+ })
+ })
+ .collect();
+
+ let compact_proof = proof
+ .clone()
+ .into_compact_proof::<HasherOf<Block>>(pre_root)
+ .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?;
+ let compact_proof_size = compact_proof.encoded_size();
+
+ let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0)
+ .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?;
+ let compressed_proof_size = compressed_proof.len();
+
+ Ok(PovInfo {
+ proof_size: proof_size as u64,
+ compact_proof_size: compact_proof_size as u64,
+ compressed_proof_size: compressed_proof_size as u64,
+ results,
+ key_values,
+ })
+}
node/cli/Cargo.tomldiffbeforeafterboth--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -319,8 +319,10 @@
pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
unique-rpc = { default-features = false, path = "../rpc" }
+uc-rpc = { default-features = false, path = "../../client/rpc" }
app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }
rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
+up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", default-features = false }
[features]
default = ["opal-runtime"]
@@ -339,3 +341,10 @@
'try-runtime-cli/try-runtime',
]
sapphire-runtime = ['opal-runtime', 'opal-runtime/become-sapphire']
+pov-estimate = [
+ 'unique-runtime?/pov-estimate',
+ 'quartz-runtime?/pov-estimate',
+ 'opal-runtime/pov-estimate',
+ 'uc-rpc/pov-estimate',
+ 'unique-rpc/pov-estimate',
+]
node/cli/src/chain_spec.rsdiffbeforeafterboth--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -54,17 +54,6 @@
#[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))]
pub type DefaultChainSpec = OpalChainSpec;
-pub enum RuntimeId {
- #[cfg(feature = "unique-runtime")]
- Unique,
-
- #[cfg(feature = "quartz-runtime")]
- Quartz,
-
- Opal,
- Unknown(String),
-}
-
#[cfg(not(feature = "unique-runtime"))]
/// PARA_ID for Opal/Sapphire/Quartz
const PARA_ID: u32 = 2095;
node/cli/src/command.rsdiffbeforeafterboth--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -33,7 +33,7 @@
// limitations under the License.
use crate::{
- chain_spec::{self, RuntimeId, RuntimeIdentification, ServiceId, ServiceIdentification},
+ chain_spec::{self, RuntimeIdentification, ServiceId, ServiceIdentification},
cli::{Cli, RelayChainCli, Subcommand},
service::{new_partial, start_node, start_dev_node},
};
@@ -66,13 +66,13 @@
use sp_runtime::traits::{AccountIdConversion, Block as BlockT};
use std::{net::SocketAddr, time::Duration};
-use up_common::types::opaque::Block;
+use up_common::types::opaque::{Block, RuntimeId};
macro_rules! no_runtime_err {
- ($chain_name:expr) => {
+ ($runtime_id:expr) => {
format!(
- "No runtime valid runtime was found for chain {}",
- $chain_name
+ "No runtime valid runtime was found for chain {:#?}",
+ $runtime_id
)
};
}
@@ -94,7 +94,7 @@
RuntimeId::Quartz => Box::new(chain_spec::QuartzChainSpec::from_json_file(path)?),
RuntimeId::Opal => chain_spec,
- RuntimeId::Unknown(chain) => return Err(no_runtime_err!(chain)),
+ runtime_id => return Err(no_runtime_err!(runtime_id)),
}
}
})
@@ -147,7 +147,7 @@
RuntimeId::Quartz => &quartz_runtime::VERSION,
RuntimeId::Opal => &opal_runtime::VERSION,
- RuntimeId::Unknown(chain) => panic!("{}", no_runtime_err!(chain)),
+ runtime_id => panic!("{}", no_runtime_err!(runtime_id)),
}
}
}
@@ -235,7 +235,7 @@
runner, $components, $cli, $cmd, $config, $( $code )*
),
- RuntimeId::Unknown(chain) => Err(no_runtime_err!(chain).into())
+ runtime_id => Err(no_runtime_err!(runtime_id).into())
}
}}
}
@@ -274,7 +274,7 @@
runner, $components, $cli, $cmd, $config, $( $code )*
),
- RuntimeId::Unknown(chain) => Err(no_runtime_err!(chain).into())
+ runtime_id => Err(no_runtime_err!(runtime_id).into())
}
}}
}
@@ -302,7 +302,7 @@
OpalRuntimeExecutor,
>($config $(, $($args),+)?) $($code)*,
- RuntimeId::Unknown(chain) => Err(no_runtime_err!(chain).into()),
+ runtime_id => Err(no_runtime_err!(runtime_id).into()),
}
};
}
@@ -445,7 +445,7 @@
sp_io::SubstrateHostFunctions,
<OpalRuntimeExecutor as NativeExecutionDispatch>::ExtendHostFunctions,
>>()),
- RuntimeId::Unknown(chain) => return Err(no_runtime_err!(chain).into()),
+ runtime_id => return Err(no_runtime_err!(runtime_id).into()),
},
task_manager,
))
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -66,9 +66,10 @@
use fc_rpc_core::types::FilterPool;
use fc_mapping_sync::{MappingSyncWorker, SyncStrategy};
-use up_common::types::opaque::{
- AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block, BlockNumber,
-};
+use up_common::types::opaque::*;
+
+#[cfg(feature = "pov-estimate")]
+use crate::chain_spec::RuntimeIdentification;
// RMRK
use up_data_structs::{
@@ -412,7 +413,8 @@
RmrkBaseInfo<AccountId>,
RmrkPartType,
RmrkTheme,
- > + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ > + up_pov_estimate_rpc::PovEstimateApi<Block>
+ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>,
@@ -517,9 +519,29 @@
.for_each(|()| futures::future::ready(())),
);
+ #[cfg(feature = "pov-estimate")]
+ let rpc_backend = backend.clone();
+
+ #[cfg(feature = "pov-estimate")]
+ let runtime_id = parachain_config.chain_spec.runtime_id();
+
let rpc_builder = Box::new(move |deny_unsafe, subscription_task_executor| {
let full_deps = unique_rpc::FullDeps {
- backend: rpc_frontier_backend.clone(),
+ #[cfg(feature = "pov-estimate")]
+ runtime_id: runtime_id.clone(),
+
+ #[cfg(feature = "pov-estimate")]
+ exec_params: uc_rpc::pov_estimate::ExecutorParams {
+ wasm_method: parachain_config.wasm_method,
+ default_heap_pages: parachain_config.default_heap_pages,
+ max_runtime_instances: parachain_config.max_runtime_instances,
+ runtime_cache_size: parachain_config.runtime_cache_size,
+ },
+
+ #[cfg(feature = "pov-estimate")]
+ backend: rpc_backend.clone(),
+
+ eth_backend: rpc_frontier_backend.clone(),
deny_unsafe,
client: rpc_client.clone(),
pool: rpc_pool.clone(),
@@ -720,7 +742,8 @@
RmrkBaseInfo<AccountId>,
RmrkPartType,
RmrkTheme,
- > + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ > + up_pov_estimate_rpc::PovEstimateApi<Block>
+ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>
@@ -869,7 +892,8 @@
RmrkBaseInfo<AccountId>,
RmrkPartType,
RmrkTheme,
- > + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ > + up_pov_estimate_rpc::PovEstimateApi<Block>
+ + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ cumulus_primitives_core::CollectCollationInfo<Block>
@@ -1040,9 +1064,29 @@
let rpc_pool = transaction_pool.clone();
let rpc_network = network.clone();
let rpc_frontier_backend = frontier_backend.clone();
+
+ #[cfg(feature = "pov-estimate")]
+ let rpc_backend = backend.clone();
+
+ #[cfg(feature = "pov-estimate")]
+ let runtime_id = config.chain_spec.runtime_id();
+
let rpc_builder = Box::new(move |deny_unsafe, subscription_executor| {
let full_deps = unique_rpc::FullDeps {
- backend: rpc_frontier_backend.clone(),
+ #[cfg(feature = "pov-estimate")]
+ runtime_id: runtime_id.clone(),
+
+ #[cfg(feature = "pov-estimate")]
+ exec_params: uc_rpc::pov_estimate::ExecutorParams {
+ wasm_method: config.wasm_method,
+ default_heap_pages: config.default_heap_pages,
+ max_runtime_instances: config.max_runtime_instances,
+ runtime_cache_size: config.runtime_cache_size,
+ },
+
+ #[cfg(feature = "pov-estimate")]
+ backend: rpc_backend.clone(),
+ eth_backend: rpc_frontier_backend.clone(),
deny_unsafe,
client: rpc_client.clone(),
pool: rpc_pool.clone(),
node/rpc/Cargo.tomldiffbeforeafterboth--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -55,6 +55,7 @@
up-rpc = { path = "../../primitives/rpc" }
app-promotion-rpc = { path = "../../primitives/app_promotion_rpc" }
rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
+up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc" }
up-data-structs = { default-features = false, path = "../../primitives/data-structs" }
[dependencies.serde]
@@ -65,3 +66,4 @@
default = []
std = []
unique-runtime = []
+pov-estimate = ['uc-rpc/pov-estimate']
node/rpc/src/lib.rsdiffbeforeafterboth--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -40,7 +40,7 @@
use sc_service::TransactionPool;
use std::{collections::BTreeMap, sync::Arc};
-use up_common::types::opaque::{Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance};
+use up_common::types::opaque::*;
// RMRK
use up_data_structs::{
@@ -48,6 +48,9 @@
RmrkPartType, RmrkTheme,
};
+#[cfg(feature = "pov-estimate")]
+type FullBackend = sc_service::TFullBackend<Block>;
+
/// Extra dependencies for GRANDPA
pub struct GrandpaDeps<B> {
/// Voting round info.
@@ -82,8 +85,18 @@
pub deny_unsafe: DenyUnsafe,
/// EthFilterApi pool.
pub filter_pool: Option<FilterPool>,
- /// Backend.
- pub backend: Arc<fc_db::Backend<Block>>,
+
+ #[cfg(feature = "pov-estimate")]
+ pub runtime_id: RuntimeId,
+ /// Executor params for PoV estimating
+ #[cfg(feature = "pov-estimate")]
+ pub exec_params: uc_rpc::pov_estimate::ExecutorParams,
+ /// Substrate Backend.
+ #[cfg(feature = "pov-estimate")]
+ pub backend: Arc<FullBackend>,
+
+ /// Ethereum Backend.
+ pub eth_backend: Arc<fc_db::Backend<Block>>,
/// Maximum number of logs in a query.
pub max_past_logs: u32,
/// Maximum fee history cache size.
@@ -162,6 +175,7 @@
RmrkPartType,
RmrkTheme,
>,
+ C::Api: up_pov_estimate_rpc::PovEstimateApi<Block>,
B: sc_client_api::Backend<Block> + Send + Sync + 'static,
B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
P: TransactionPool<Block = Block> + 'static,
@@ -182,6 +196,9 @@
#[cfg(not(feature = "unique-runtime"))]
use uc_rpc::{RmrkApiServer, Rmrk};
+ #[cfg(feature = "pov-estimate")]
+ use uc_rpc::pov_estimate::{PovEstimateApiServer, PovEstimate};
+
// use pallet_contracts_rpc::{Contracts, ContractsApi};
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
@@ -200,7 +217,17 @@
network,
deny_unsafe,
filter_pool,
+
+ #[cfg(feature = "pov-estimate")]
+ runtime_id,
+
+ #[cfg(feature = "pov-estimate")]
+ exec_params,
+
+ #[cfg(feature = "pov-estimate")]
backend,
+
+ eth_backend,
max_past_logs,
} = deps;
@@ -226,7 +253,7 @@
network.clone(),
signers,
overrides.clone(),
- backend.clone(),
+ eth_backend.clone(),
is_authority,
block_data_cache.clone(),
fee_history_cache,
@@ -244,11 +271,23 @@
#[cfg(not(feature = "unique-runtime"))]
io.merge(Rmrk::new(client.clone()).into_rpc())?;
+ #[cfg(feature = "pov-estimate")]
+ io.merge(
+ PovEstimate::new(
+ client.clone(),
+ backend,
+ deny_unsafe,
+ exec_params,
+ runtime_id,
+ )
+ .into_rpc(),
+ )?;
+
if let Some(filter_pool) = filter_pool {
io.merge(
EthFilter::new(
client.clone(),
- backend,
+ eth_backend,
filter_pool,
500_usize, // max stored filters
max_past_logs,
pallets/common/Cargo.tomldiffbeforeafterboth--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -23,6 +23,7 @@
evm-coder = { default-features = false, path = '../../crates/evm-coder' }
ethereum = { version = "0.14.0", default-features = false }
pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
+up-pov-estimate-rpc = { default-features = false, path = "../../primitives/pov-estimate-rpc" }
serde = { version = "1.0.130", default-features = false }
scale-info = { version = "2.0.1", default-features = false, features = [
@@ -39,6 +40,7 @@
"fp-evm-mapping/std",
"up-data-structs/std",
"pallet-evm/std",
+ "up-pov-estimate-rpc/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -115,6 +115,7 @@
RmrkNftChild,
CollectionPermissions,
};
+use up_pov_estimate_rpc::PovInfo;
pub use pallet::*;
use sp_core::H160;
@@ -881,6 +882,8 @@
RmrkPartType,
RmrkBoundedTheme,
RmrkNftChild,
+ // PoV Estimate Info
+ PovInfo,
)>,
),
QueryKind = OptionQuery,
primitives/common/src/types.rsdiffbeforeafterboth--- a/primitives/common/src/types.rs
+++ b/primitives/common/src/types.rs
@@ -29,6 +29,14 @@
pub use super::{BlockNumber, Signature, AccountId, Balance, Index, Hash, AuraId};
+ #[derive(Debug, Clone)]
+ pub enum RuntimeId {
+ Unique,
+ Quartz,
+ Opal,
+ Unknown(sp_std::vec::Vec<u8>),
+ }
+
/// Opaque block header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
primitives/pov-estimate-rpc/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/primitives/pov-estimate-rpc/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "up-pov-estimate-rpc"
+version = "0.1.0"
+license = "GPLv3"
+edition = "2021"
+
+[dependencies]
+codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = [
+ "derive",
+] }
+serde = { version = "1.0.130", features = ["derive"], default-features = false, optional = true }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
+sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" }
+
+[features]
+default = ["std"]
+std = [
+ "codec/std",
+ "serde/std",
+ "scale-info/std",
+ "sp-core/std",
+ "sp-std/std",
+ "sp-api/std",
+ "sp-runtime/std",
+]
primitives/pov-estimate-rpc/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/primitives/pov-estimate-rpc/src/lib.rs
@@ -0,0 +1,49 @@
+// 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 scale_info::TypeInfo;
+use sp_std::vec::Vec;
+
+#[cfg(feature = "std")]
+use serde::Serialize;
+
+use sp_runtime::ApplyExtrinsicResult;
+use sp_core::Bytes;
+
+#[cfg_attr(feature = "std", derive(Serialize))]
+#[derive(Debug, TypeInfo)]
+pub struct PovInfo {
+ pub proof_size: u64,
+ pub compact_proof_size: u64,
+ pub compressed_proof_size: u64,
+ pub results: Vec<ApplyExtrinsicResult>,
+ pub key_values: Vec<TrieKeyValue>,
+}
+
+#[cfg_attr(feature = "std", derive(Serialize))]
+#[derive(Debug, TypeInfo)]
+pub struct TrieKeyValue {
+ pub key: Vec<u8>,
+ pub value: Vec<u8>,
+}
+
+sp_api::decl_runtime_apis! {
+ pub trait PovEstimateApi {
+ fn pov_estimate(uxt: Bytes) -> ApplyExtrinsicResult;
+ }
+}
runtime/common/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -35,7 +35,7 @@
) => {
use sp_std::prelude::*;
use sp_api::impl_runtime_apis;
- use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
+ use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160, Bytes};
use sp_runtime::{
Permill,
traits::Block as BlockT,
@@ -778,6 +778,29 @@
}
}
+ impl up_pov_estimate_rpc::PovEstimateApi<Block> for Runtime {
+ #[allow(unused_variables)]
+ fn pov_estimate(uxt: Bytes) -> ApplyExtrinsicResult {
+ #[cfg(feature = "pov-estimate")]
+ {
+ use codec::Decode;
+
+ let uxt_decode = <<Block as BlockT>::Extrinsic as Decode>::decode(&mut &*uxt)
+ .map_err(|_| DispatchError::Other("failed to decode the extrinsic"));
+
+ let uxt = match uxt_decode {
+ Ok(uxt) => uxt,
+ Err(err) => return Ok(err.into()),
+ };
+
+ Executive::apply_extrinsic(uxt)
+ }
+
+ #[cfg(not(feature = "pov-estimate"))]
+ return Ok(unsupported!());
+ }
+ }
+
#[cfg(feature = "try-runtime")]
impl frame_try_runtime::TryRuntime<Block> for Runtime {
fn on_runtime_upgrade(checks: bool) -> (frame_support::pallet_prelude::Weight, frame_support::pallet_prelude::Weight) {
runtime/opal/Cargo.tomldiffbeforeafterboth--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -127,6 +127,7 @@
'pallet-base-fee/std',
'fp-rpc/std',
'up-rpc/std',
+ 'up-pov-estimate-rpc/std',
'app-promotion-rpc/std',
'fp-evm-mapping/std',
'fp-self-contained/std',
@@ -184,6 +185,7 @@
'pallet-test-utils',
]
become-sapphire = []
+pov-estimate = []
refungible = []
scheduler = []
@@ -468,6 +470,7 @@
derivative = "2.2.0"
pallet-unique = { path = '../../pallets/unique', default-features = false }
up-rpc = { path = "../../primitives/rpc", default-features = false }
+up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-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 = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
runtime/quartz/Cargo.tomldiffbeforeafterboth--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -122,6 +122,7 @@
'pallet-base-fee/std',
'fp-rpc/std',
'up-rpc/std',
+ 'up-pov-estimate-rpc/std',
'app-promotion-rpc/std',
'fp-evm-mapping/std',
'fp-self-contained/std',
@@ -169,6 +170,7 @@
]
limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
quartz-runtime = ['refungible', 'app-promotion', 'foreign-assets']
+pov-estimate = []
refungible = []
scheduler = []
@@ -461,6 +463,7 @@
derivative = "2.2.0"
pallet-unique = { path = '../../pallets/unique', default-features = false }
up-rpc = { path = "../../primitives/rpc", default-features = false }
+up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", default-features = false }
app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }
fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
runtime/unique/Cargo.tomldiffbeforeafterboth--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -123,6 +123,7 @@
'pallet-base-fee/std',
'fp-rpc/std',
'up-rpc/std',
+ 'up-pov-estimate-rpc/std',
'app-promotion-rpc/std',
'fp-evm-mapping/std',
'fp-self-contained/std',
@@ -170,6 +171,7 @@
]
limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
unique-runtime = ['foreign-assets']
+pov-estimate = []
stubgen = ["evm-coder/stubgen"]
refungible = []
@@ -454,6 +456,7 @@
derivative = "2.2.0"
pallet-unique = { path = '../../pallets/unique', default-features = false }
up-rpc = { path = "../../primitives/rpc", default-features = false }
+up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-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 }
tests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -5,7 +5,7 @@
// this is required to allow for ambient/previous definitions
import '@polkadot/rpc-core/types/jsonrpc';
-import type { PalletEvmAccountBasicCrossAccountIdRepr, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsPartPartType, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData } from './default';
+import type { PalletEvmAccountBasicCrossAccountIdRepr, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsPartPartType, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo } from './default';
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';
@@ -436,6 +436,12 @@
**/
queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfoV1>>;
};
+ povinfo: {
+ /**
+ * Estimate PoV size of encoded signed extrinsics
+ **/
+ estimateExtrinsicPoV: AugmentedRpc<(encodedXt: Vec<Bytes> | (Bytes | string | Uint8Array)[], at?: Hash | string | Uint8Array) => Observable<UpPovEstimateRpcPovInfo>>;
+ };
rmrk: {
/**
* Get tokens owned by an account in a collection
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, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletXcmCall, PalletXcmError, PalletXcmEvent, 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, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, 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, UpDataStructsRpcCollectionFlags, 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, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletXcmCall, PalletXcmError, PalletXcmEvent, 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, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, 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, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue, 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, XcmVersionedMultiAsset, 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';
@@ -1186,6 +1186,9 @@
SpRuntimeMultiSignature: SpRuntimeMultiSignature;
SpRuntimeTokenError: SpRuntimeTokenError;
SpRuntimeTransactionalError: SpRuntimeTransactionalError;
+ SpRuntimeTransactionValidityInvalidTransaction: SpRuntimeTransactionValidityInvalidTransaction;
+ SpRuntimeTransactionValidityTransactionValidityError: SpRuntimeTransactionValidityTransactionValidityError;
+ SpRuntimeTransactionValidityUnknownTransaction: SpRuntimeTransactionValidityUnknownTransaction;
SpTrieStorageProof: SpTrieStorageProof;
SpVersionRuntimeVersion: SpVersionRuntimeVersion;
SpWeightsRuntimeDbWeight: SpWeightsRuntimeDbWeight;
@@ -1325,6 +1328,8 @@
UpDataStructsTokenData: UpDataStructsTokenData;
UpgradeGoAhead: UpgradeGoAhead;
UpgradeRestriction: UpgradeRestriction;
+ UpPovEstimateRpcPovInfo: UpPovEstimateRpcPovInfo;
+ UpPovEstimateRpcTrieKeyValue: UpPovEstimateRpcTrieKeyValue;
UpwardMessage: UpwardMessage;
usize: usize;
USize: USize;
tests/src/interfaces/default/types.tsdiffbeforeafterboth--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -2444,7 +2444,7 @@
}
/** @name PhantomTypeUpDataStructs */
-export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild]>> {}
+export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild, UpPovEstimateRpcPovInfo]>> {}
/** @name PolkadotCorePrimitivesInboundDownwardMessage */
export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
@@ -2748,6 +2748,41 @@
readonly type: 'LimitReached' | 'NoLayer';
}
+/** @name SpRuntimeTransactionValidityInvalidTransaction */
+export interface SpRuntimeTransactionValidityInvalidTransaction extends Enum {
+ readonly isCall: boolean;
+ readonly isPayment: boolean;
+ readonly isFuture: boolean;
+ readonly isStale: boolean;
+ readonly isBadProof: boolean;
+ readonly isAncientBirthBlock: boolean;
+ readonly isExhaustsResources: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly isBadMandatory: boolean;
+ readonly isMandatoryValidation: boolean;
+ readonly isBadSigner: boolean;
+ readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner';
+}
+
+/** @name SpRuntimeTransactionValidityTransactionValidityError */
+export interface SpRuntimeTransactionValidityTransactionValidityError extends Enum {
+ readonly isInvalid: boolean;
+ readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction;
+ readonly isUnknown: boolean;
+ readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction;
+ readonly type: 'Invalid' | 'Unknown';
+}
+
+/** @name SpRuntimeTransactionValidityUnknownTransaction */
+export interface SpRuntimeTransactionValidityUnknownTransaction extends Enum {
+ readonly isCannotLookup: boolean;
+ readonly isNoUnsignedValidator: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom';
+}
+
/** @name SpTrieStorageProof */
export interface SpTrieStorageProof extends Struct {
readonly trieNodes: BTreeSet<Bytes>;
@@ -3018,6 +3053,21 @@
readonly pieces: u128;
}
+/** @name UpPovEstimateRpcPovInfo */
+export interface UpPovEstimateRpcPovInfo extends Struct {
+ readonly proofSize: u64;
+ readonly compactProofSize: u64;
+ readonly compressedProofSize: u64;
+ readonly results: Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>;
+ readonly keyValues: Vec<UpPovEstimateRpcTrieKeyValue>;
+}
+
+/** @name UpPovEstimateRpcTrieKeyValue */
+export interface UpPovEstimateRpcTrieKeyValue extends Struct {
+ readonly key: Bytes;
+ readonly value: Bytes;
+}
+
/** @name XcmDoubleEncoded */
export interface XcmDoubleEncoded extends Struct {
readonly encoded: Bytes;
tests/src/interfaces/definitions.tsdiffbeforeafterboth--- a/tests/src/interfaces/definitions.ts
+++ b/tests/src/interfaces/definitions.ts
@@ -17,4 +17,5 @@
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
+export {default as povinfo} from './povinfo/definitions';
+export {default as default} from './default/definitions';
tests/src/interfaces/lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -3106,7 +3106,7 @@
/**
* Lookup399: PhantomType::up_data_structs<T>
**/
- PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]',
+ PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild,UpPovEstimateRpcPovInfo);0]',
/**
* Lookup401: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
@@ -3198,79 +3198,133 @@
nftId: 'u32'
},
/**
- * Lookup414: pallet_common::pallet::Error<T>
+ * Lookup413: up_pov_estimate_rpc::PovInfo
+ **/
+ UpPovEstimateRpcPovInfo: {
+ proofSize: 'u64',
+ compactProofSize: 'u64',
+ compressedProofSize: 'u64',
+ results: 'Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>',
+ keyValues: 'Vec<UpPovEstimateRpcTrieKeyValue>'
+ },
+ /**
+ * Lookup416: sp_runtime::transaction_validity::TransactionValidityError
+ **/
+ SpRuntimeTransactionValidityTransactionValidityError: {
+ _enum: {
+ Invalid: 'SpRuntimeTransactionValidityInvalidTransaction',
+ Unknown: 'SpRuntimeTransactionValidityUnknownTransaction'
+ }
+ },
+ /**
+ * Lookup417: sp_runtime::transaction_validity::InvalidTransaction
+ **/
+ SpRuntimeTransactionValidityInvalidTransaction: {
+ _enum: {
+ Call: 'Null',
+ Payment: 'Null',
+ Future: 'Null',
+ Stale: 'Null',
+ BadProof: 'Null',
+ AncientBirthBlock: 'Null',
+ ExhaustsResources: 'Null',
+ Custom: 'u8',
+ BadMandatory: 'Null',
+ MandatoryValidation: 'Null',
+ BadSigner: 'Null'
+ }
+ },
+ /**
+ * Lookup418: sp_runtime::transaction_validity::UnknownTransaction
+ **/
+ SpRuntimeTransactionValidityUnknownTransaction: {
+ _enum: {
+ CannotLookup: 'Null',
+ NoUnsignedValidator: 'Null',
+ Custom: 'u8'
+ }
+ },
+ /**
+ * Lookup420: up_pov_estimate_rpc::TrieKeyValue
+ **/
+ UpPovEstimateRpcTrieKeyValue: {
+ key: 'Bytes',
+ value: 'Bytes'
+ },
+ /**
+ * Lookup422: 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', 'ConfirmSponsorshipFail', 'UserIsNotCollectionAdmin']
},
/**
- * Lookup416: pallet_fungible::pallet::Error<T>
+ * Lookup424: pallet_fungible::pallet::Error<T>
**/
PalletFungibleError: {
_enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingAllowanceForAllNotAllowed', 'FungibleTokensAreAlwaysValid']
},
/**
- * Lookup420: pallet_refungible::pallet::Error<T>
+ * Lookup428: pallet_refungible::pallet::Error<T>
**/
PalletRefungibleError: {
_enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
},
/**
- * Lookup421: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup429: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
PalletNonfungibleItemData: {
owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
},
/**
- * Lookup423: up_data_structs::PropertyScope
+ * Lookup431: up_data_structs::PropertyScope
**/
UpDataStructsPropertyScope: {
_enum: ['None', 'Rmrk']
},
/**
- * Lookup426: pallet_nonfungible::pallet::Error<T>
+ * Lookup434: pallet_nonfungible::pallet::Error<T>
**/
PalletNonfungibleError: {
_enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
},
/**
- * Lookup427: pallet_structure::pallet::Error<T>
+ * Lookup435: pallet_structure::pallet::Error<T>
**/
PalletStructureError: {
_enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound']
},
/**
- * Lookup428: pallet_rmrk_core::pallet::Error<T>
+ * Lookup436: 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']
},
/**
- * Lookup430: pallet_rmrk_equip::pallet::Error<T>
+ * Lookup438: pallet_rmrk_equip::pallet::Error<T>
**/
PalletRmrkEquipError: {
_enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart']
},
/**
- * Lookup436: pallet_app_promotion::pallet::Error<T>
+ * Lookup444: pallet_app_promotion::pallet::Error<T>
**/
PalletAppPromotionError: {
_enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'IncorrectLockedBalanceOperation']
},
/**
- * Lookup437: pallet_foreign_assets::module::Error<T>
+ * Lookup445: pallet_foreign_assets::module::Error<T>
**/
PalletForeignAssetsModuleError: {
_enum: ['BadLocation', 'MultiLocationExisted', 'AssetIdNotExists', 'AssetIdExisted']
},
/**
- * Lookup439: pallet_evm::pallet::Error<T>
+ * Lookup447: pallet_evm::pallet::Error<T>
**/
PalletEvmError: {
_enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce', 'GasLimitTooLow', 'GasLimitTooHigh', 'Undefined', 'Reentrancy', 'TransactionMustComeFromEOA']
},
/**
- * Lookup442: fp_rpc::TransactionStatus
+ * Lookup450: fp_rpc::TransactionStatus
**/
FpRpcTransactionStatus: {
transactionHash: 'H256',
@@ -3282,11 +3336,11 @@
logsBloom: 'EthbloomBloom'
},
/**
- * Lookup444: ethbloom::Bloom
+ * Lookup452: ethbloom::Bloom
**/
EthbloomBloom: '[u8;256]',
/**
- * Lookup446: ethereum::receipt::ReceiptV3
+ * Lookup454: ethereum::receipt::ReceiptV3
**/
EthereumReceiptReceiptV3: {
_enum: {
@@ -3296,7 +3350,7 @@
}
},
/**
- * Lookup447: ethereum::receipt::EIP658ReceiptData
+ * Lookup455: ethereum::receipt::EIP658ReceiptData
**/
EthereumReceiptEip658ReceiptData: {
statusCode: 'u8',
@@ -3305,7 +3359,7 @@
logs: 'Vec<EthereumLog>'
},
/**
- * Lookup448: ethereum::block::Block<ethereum::transaction::TransactionV2>
+ * Lookup456: ethereum::block::Block<ethereum::transaction::TransactionV2>
**/
EthereumBlock: {
header: 'EthereumHeader',
@@ -3313,7 +3367,7 @@
ommers: 'Vec<EthereumHeader>'
},
/**
- * Lookup449: ethereum::header::Header
+ * Lookup457: ethereum::header::Header
**/
EthereumHeader: {
parentHash: 'H256',
@@ -3333,23 +3387,23 @@
nonce: 'EthereumTypesHashH64'
},
/**
- * Lookup450: ethereum_types::hash::H64
+ * Lookup458: ethereum_types::hash::H64
**/
EthereumTypesHashH64: '[u8;8]',
/**
- * Lookup455: pallet_ethereum::pallet::Error<T>
+ * Lookup463: pallet_ethereum::pallet::Error<T>
**/
PalletEthereumError: {
_enum: ['InvalidSignature', 'PreLogExists']
},
/**
- * Lookup456: pallet_evm_coder_substrate::pallet::Error<T>
+ * Lookup464: pallet_evm_coder_substrate::pallet::Error<T>
**/
PalletEvmCoderSubstrateError: {
_enum: ['OutOfGas', 'OutOfFund']
},
/**
- * Lookup457: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup465: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: {
_enum: {
@@ -3359,35 +3413,35 @@
}
},
/**
- * Lookup458: pallet_evm_contract_helpers::SponsoringModeT
+ * Lookup466: pallet_evm_contract_helpers::SponsoringModeT
**/
PalletEvmContractHelpersSponsoringModeT: {
_enum: ['Disabled', 'Allowlisted', 'Generous']
},
/**
- * Lookup464: pallet_evm_contract_helpers::pallet::Error<T>
+ * Lookup472: pallet_evm_contract_helpers::pallet::Error<T>
**/
PalletEvmContractHelpersError: {
_enum: ['NoPermission', 'NoPendingSponsor', 'TooManyMethodsHaveSponsoredLimit']
},
/**
- * Lookup465: pallet_evm_migration::pallet::Error<T>
+ * Lookup473: pallet_evm_migration::pallet::Error<T>
**/
PalletEvmMigrationError: {
_enum: ['AccountNotEmpty', 'AccountIsNotMigrating', 'BadEvent']
},
/**
- * Lookup466: pallet_maintenance::pallet::Error<T>
+ * Lookup474: pallet_maintenance::pallet::Error<T>
**/
PalletMaintenanceError: 'Null',
/**
- * Lookup467: pallet_test_utils::pallet::Error<T>
+ * Lookup475: pallet_test_utils::pallet::Error<T>
**/
PalletTestUtilsError: {
_enum: ['TestPalletDisabled', 'TriggerRollback']
},
/**
- * Lookup469: sp_runtime::MultiSignature
+ * Lookup477: sp_runtime::MultiSignature
**/
SpRuntimeMultiSignature: {
_enum: {
@@ -3397,51 +3451,51 @@
}
},
/**
- * Lookup470: sp_core::ed25519::Signature
+ * Lookup478: sp_core::ed25519::Signature
**/
SpCoreEd25519Signature: '[u8;64]',
/**
- * Lookup472: sp_core::sr25519::Signature
+ * Lookup480: sp_core::sr25519::Signature
**/
SpCoreSr25519Signature: '[u8;64]',
/**
- * Lookup473: sp_core::ecdsa::Signature
+ * Lookup481: sp_core::ecdsa::Signature
**/
SpCoreEcdsaSignature: '[u8;65]',
/**
- * Lookup476: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+ * Lookup484: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
**/
FrameSystemExtensionsCheckSpecVersion: 'Null',
/**
- * Lookup477: frame_system::extensions::check_tx_version::CheckTxVersion<T>
+ * Lookup485: frame_system::extensions::check_tx_version::CheckTxVersion<T>
**/
FrameSystemExtensionsCheckTxVersion: 'Null',
/**
- * Lookup478: frame_system::extensions::check_genesis::CheckGenesis<T>
+ * Lookup486: frame_system::extensions::check_genesis::CheckGenesis<T>
**/
FrameSystemExtensionsCheckGenesis: 'Null',
/**
- * Lookup481: frame_system::extensions::check_nonce::CheckNonce<T>
+ * Lookup489: frame_system::extensions::check_nonce::CheckNonce<T>
**/
FrameSystemExtensionsCheckNonce: 'Compact<u32>',
/**
- * Lookup482: frame_system::extensions::check_weight::CheckWeight<T>
+ * Lookup490: frame_system::extensions::check_weight::CheckWeight<T>
**/
FrameSystemExtensionsCheckWeight: 'Null',
/**
- * Lookup483: opal_runtime::runtime_common::maintenance::CheckMaintenance
+ * Lookup491: opal_runtime::runtime_common::maintenance::CheckMaintenance
**/
OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: 'Null',
/**
- * Lookup484: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+ * Lookup492: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
**/
PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
/**
- * Lookup485: opal_runtime::Runtime
+ * Lookup493: opal_runtime::Runtime
**/
OpalRuntimeRuntime: 'Null',
/**
- * Lookup486: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+ * Lookup494: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
**/
PalletEthereumFakeTransactionFinalizer: 'Null'
};
tests/src/interfaces/povinfo/definitions.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/interfaces/povinfo/definitions.ts
@@ -0,0 +1,40 @@
+// 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 atParam = {name: 'at', type: 'Hash', isOptional: true};
+
+const fun = (description: string, params: RpcParam[], type: string) => ({
+ description,
+ params: [...params, atParam],
+ type,
+});
+
+export default {
+ types: {},
+ rpc: {
+ estimateExtrinsicPoV: fun(
+ 'Estimate PoV size of encoded signed extrinsics',
+ [{name: 'encodedXt', type: 'Vec<Bytes>'}],
+ 'UpPovEstimateRpcPovInfo',
+ ),
+ },
+};
tests/src/interfaces/povinfo/index.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/interfaces/povinfo/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/povinfo/types.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/interfaces/povinfo/types.ts
@@ -0,0 +1,4 @@
+// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
+/* eslint-disable */
+
+export type PHANTOM_POVINFO = 'povinfo';
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, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletXcmCall, PalletXcmError, PalletXcmEvent, 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, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, 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, UpDataStructsRpcCollectionFlags, 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, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletXcmCall, PalletXcmError, PalletXcmEvent, 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, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, 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, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue, 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, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
declare module '@polkadot/types/types/registry' {
interface InterfaceTypes {
@@ -198,6 +198,9 @@
SpRuntimeModuleError: SpRuntimeModuleError;
SpRuntimeMultiSignature: SpRuntimeMultiSignature;
SpRuntimeTokenError: SpRuntimeTokenError;
+ SpRuntimeTransactionValidityInvalidTransaction: SpRuntimeTransactionValidityInvalidTransaction;
+ SpRuntimeTransactionValidityTransactionValidityError: SpRuntimeTransactionValidityTransactionValidityError;
+ SpRuntimeTransactionValidityUnknownTransaction: SpRuntimeTransactionValidityUnknownTransaction;
SpRuntimeTransactionalError: SpRuntimeTransactionalError;
SpTrieStorageProof: SpTrieStorageProof;
SpVersionRuntimeVersion: SpVersionRuntimeVersion;
@@ -234,6 +237,8 @@
UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: UpDataStructsSponsorshipStateBasicCrossAccountIdRepr;
UpDataStructsTokenChild: UpDataStructsTokenChild;
UpDataStructsTokenData: UpDataStructsTokenData;
+ UpPovEstimateRpcPovInfo: UpPovEstimateRpcPovInfo;
+ UpPovEstimateRpcTrieKeyValue: UpPovEstimateRpcTrieKeyValue;
XcmDoubleEncoded: XcmDoubleEncoded;
XcmV0Junction: XcmV0Junction;
XcmV0JunctionBodyId: XcmV0JunctionBodyId;
tests/src/interfaces/types-lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -3380,7 +3380,7 @@
}
/** @name PhantomTypeUpDataStructs (399) */
- interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild]>> {}
+ interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild, UpPovEstimateRpcPovInfo]>> {}
/** @name UpDataStructsTokenData (401) */
interface UpDataStructsTokenData extends Struct {
@@ -3462,7 +3462,57 @@
readonly nftId: u32;
}
- /** @name PalletCommonError (414) */
+ /** @name UpPovEstimateRpcPovInfo (413) */
+ interface UpPovEstimateRpcPovInfo extends Struct {
+ readonly proofSize: u64;
+ readonly compactProofSize: u64;
+ readonly compressedProofSize: u64;
+ readonly results: Vec<Result<Result<Null, SpRuntimeDispatchError>, SpRuntimeTransactionValidityTransactionValidityError>>;
+ readonly keyValues: Vec<UpPovEstimateRpcTrieKeyValue>;
+ }
+
+ /** @name SpRuntimeTransactionValidityTransactionValidityError (416) */
+ interface SpRuntimeTransactionValidityTransactionValidityError extends Enum {
+ readonly isInvalid: boolean;
+ readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction;
+ readonly isUnknown: boolean;
+ readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction;
+ readonly type: 'Invalid' | 'Unknown';
+ }
+
+ /** @name SpRuntimeTransactionValidityInvalidTransaction (417) */
+ interface SpRuntimeTransactionValidityInvalidTransaction extends Enum {
+ readonly isCall: boolean;
+ readonly isPayment: boolean;
+ readonly isFuture: boolean;
+ readonly isStale: boolean;
+ readonly isBadProof: boolean;
+ readonly isAncientBirthBlock: boolean;
+ readonly isExhaustsResources: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly isBadMandatory: boolean;
+ readonly isMandatoryValidation: boolean;
+ readonly isBadSigner: boolean;
+ readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner';
+ }
+
+ /** @name SpRuntimeTransactionValidityUnknownTransaction (418) */
+ interface SpRuntimeTransactionValidityUnknownTransaction extends Enum {
+ readonly isCannotLookup: boolean;
+ readonly isNoUnsignedValidator: boolean;
+ readonly isCustom: boolean;
+ readonly asCustom: u8;
+ readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom';
+ }
+
+ /** @name UpPovEstimateRpcTrieKeyValue (420) */
+ interface UpPovEstimateRpcTrieKeyValue extends Struct {
+ readonly key: Bytes;
+ readonly value: Bytes;
+ }
+
+ /** @name PalletCommonError (422) */
interface PalletCommonError extends Enum {
readonly isCollectionNotFound: boolean;
readonly isMustBeTokenOwner: boolean;
@@ -3503,7 +3553,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' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin';
}
- /** @name PalletFungibleError (416) */
+ /** @name PalletFungibleError (424) */
interface PalletFungibleError extends Enum {
readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isFungibleItemsHaveNoId: boolean;
@@ -3515,7 +3565,7 @@
readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid';
}
- /** @name PalletRefungibleError (420) */
+ /** @name PalletRefungibleError (428) */
interface PalletRefungibleError extends Enum {
readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isWrongRefungiblePieces: boolean;
@@ -3525,19 +3575,19 @@
readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
}
- /** @name PalletNonfungibleItemData (421) */
+ /** @name PalletNonfungibleItemData (429) */
interface PalletNonfungibleItemData extends Struct {
readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
}
- /** @name UpDataStructsPropertyScope (423) */
+ /** @name UpDataStructsPropertyScope (431) */
interface UpDataStructsPropertyScope extends Enum {
readonly isNone: boolean;
readonly isRmrk: boolean;
readonly type: 'None' | 'Rmrk';
}
- /** @name PalletNonfungibleError (426) */
+ /** @name PalletNonfungibleError (434) */
interface PalletNonfungibleError extends Enum {
readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isNonfungibleItemsHaveNoAmount: boolean;
@@ -3545,7 +3595,7 @@
readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
}
- /** @name PalletStructureError (427) */
+ /** @name PalletStructureError (435) */
interface PalletStructureError extends Enum {
readonly isOuroborosDetected: boolean;
readonly isDepthLimit: boolean;
@@ -3554,7 +3604,7 @@
readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound';
}
- /** @name PalletRmrkCoreError (428) */
+ /** @name PalletRmrkCoreError (436) */
interface PalletRmrkCoreError extends Enum {
readonly isCorruptedCollectionType: boolean;
readonly isRmrkPropertyKeyIsTooLong: boolean;
@@ -3578,7 +3628,7 @@
readonly type: 'CorruptedCollectionType' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'RmrkPropertyIsNotFound' | 'UnableToDecodeRmrkData' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'NonTransferable' | 'CollectionFullOrLocked' | 'ResourceDoesntExist' | 'CannotSendToDescendentOrSelf' | 'CannotAcceptNonOwnedNft' | 'CannotRejectNonOwnedNft' | 'CannotRejectNonPendingNft' | 'ResourceNotPending' | 'NoAvailableResourceId';
}
- /** @name PalletRmrkEquipError (430) */
+ /** @name PalletRmrkEquipError (438) */
interface PalletRmrkEquipError extends Enum {
readonly isPermissionError: boolean;
readonly isNoAvailableBaseId: boolean;
@@ -3590,7 +3640,7 @@
readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst' | 'PartDoesntExist' | 'NoEquippableOnFixedPart';
}
- /** @name PalletAppPromotionError (436) */
+ /** @name PalletAppPromotionError (444) */
interface PalletAppPromotionError extends Enum {
readonly isAdminNotSet: boolean;
readonly isNoPermission: boolean;
@@ -3601,7 +3651,7 @@
readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'IncorrectLockedBalanceOperation';
}
- /** @name PalletForeignAssetsModuleError (437) */
+ /** @name PalletForeignAssetsModuleError (445) */
interface PalletForeignAssetsModuleError extends Enum {
readonly isBadLocation: boolean;
readonly isMultiLocationExisted: boolean;
@@ -3610,7 +3660,7 @@
readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
}
- /** @name PalletEvmError (439) */
+ /** @name PalletEvmError (447) */
interface PalletEvmError extends Enum {
readonly isBalanceLow: boolean;
readonly isFeeOverflow: boolean;
@@ -3626,7 +3676,7 @@
readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA';
}
- /** @name FpRpcTransactionStatus (442) */
+ /** @name FpRpcTransactionStatus (450) */
interface FpRpcTransactionStatus extends Struct {
readonly transactionHash: H256;
readonly transactionIndex: u32;
@@ -3637,10 +3687,10 @@
readonly logsBloom: EthbloomBloom;
}
- /** @name EthbloomBloom (444) */
+ /** @name EthbloomBloom (452) */
interface EthbloomBloom extends U8aFixed {}
- /** @name EthereumReceiptReceiptV3 (446) */
+ /** @name EthereumReceiptReceiptV3 (454) */
interface EthereumReceiptReceiptV3 extends Enum {
readonly isLegacy: boolean;
readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -3651,7 +3701,7 @@
readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
}
- /** @name EthereumReceiptEip658ReceiptData (447) */
+ /** @name EthereumReceiptEip658ReceiptData (455) */
interface EthereumReceiptEip658ReceiptData extends Struct {
readonly statusCode: u8;
readonly usedGas: U256;
@@ -3659,14 +3709,14 @@
readonly logs: Vec<EthereumLog>;
}
- /** @name EthereumBlock (448) */
+ /** @name EthereumBlock (456) */
interface EthereumBlock extends Struct {
readonly header: EthereumHeader;
readonly transactions: Vec<EthereumTransactionTransactionV2>;
readonly ommers: Vec<EthereumHeader>;
}
- /** @name EthereumHeader (449) */
+ /** @name EthereumHeader (457) */
interface EthereumHeader extends Struct {
readonly parentHash: H256;
readonly ommersHash: H256;
@@ -3685,24 +3735,24 @@
readonly nonce: EthereumTypesHashH64;
}
- /** @name EthereumTypesHashH64 (450) */
+ /** @name EthereumTypesHashH64 (458) */
interface EthereumTypesHashH64 extends U8aFixed {}
- /** @name PalletEthereumError (455) */
+ /** @name PalletEthereumError (463) */
interface PalletEthereumError extends Enum {
readonly isInvalidSignature: boolean;
readonly isPreLogExists: boolean;
readonly type: 'InvalidSignature' | 'PreLogExists';
}
- /** @name PalletEvmCoderSubstrateError (456) */
+ /** @name PalletEvmCoderSubstrateError (464) */
interface PalletEvmCoderSubstrateError extends Enum {
readonly isOutOfGas: boolean;
readonly isOutOfFund: boolean;
readonly type: 'OutOfGas' | 'OutOfFund';
}
- /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (457) */
+ /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (465) */
interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
readonly isDisabled: boolean;
readonly isUnconfirmed: boolean;
@@ -3712,7 +3762,7 @@
readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
}
- /** @name PalletEvmContractHelpersSponsoringModeT (458) */
+ /** @name PalletEvmContractHelpersSponsoringModeT (466) */
interface PalletEvmContractHelpersSponsoringModeT extends Enum {
readonly isDisabled: boolean;
readonly isAllowlisted: boolean;
@@ -3720,7 +3770,7 @@
readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
}
- /** @name PalletEvmContractHelpersError (464) */
+ /** @name PalletEvmContractHelpersError (472) */
interface PalletEvmContractHelpersError extends Enum {
readonly isNoPermission: boolean;
readonly isNoPendingSponsor: boolean;
@@ -3728,7 +3778,7 @@
readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
}
- /** @name PalletEvmMigrationError (465) */
+ /** @name PalletEvmMigrationError (473) */
interface PalletEvmMigrationError extends Enum {
readonly isAccountNotEmpty: boolean;
readonly isAccountIsNotMigrating: boolean;
@@ -3736,17 +3786,17 @@
readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
}
- /** @name PalletMaintenanceError (466) */
+ /** @name PalletMaintenanceError (474) */
type PalletMaintenanceError = Null;
- /** @name PalletTestUtilsError (467) */
+ /** @name PalletTestUtilsError (475) */
interface PalletTestUtilsError extends Enum {
readonly isTestPalletDisabled: boolean;
readonly isTriggerRollback: boolean;
readonly type: 'TestPalletDisabled' | 'TriggerRollback';
}
- /** @name SpRuntimeMultiSignature (469) */
+ /** @name SpRuntimeMultiSignature (477) */
interface SpRuntimeMultiSignature extends Enum {
readonly isEd25519: boolean;
readonly asEd25519: SpCoreEd25519Signature;
@@ -3757,40 +3807,40 @@
readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
}
- /** @name SpCoreEd25519Signature (470) */
+ /** @name SpCoreEd25519Signature (478) */
interface SpCoreEd25519Signature extends U8aFixed {}
- /** @name SpCoreSr25519Signature (472) */
+ /** @name SpCoreSr25519Signature (480) */
interface SpCoreSr25519Signature extends U8aFixed {}
- /** @name SpCoreEcdsaSignature (473) */
+ /** @name SpCoreEcdsaSignature (481) */
interface SpCoreEcdsaSignature extends U8aFixed {}
- /** @name FrameSystemExtensionsCheckSpecVersion (476) */
+ /** @name FrameSystemExtensionsCheckSpecVersion (484) */
type FrameSystemExtensionsCheckSpecVersion = Null;
- /** @name FrameSystemExtensionsCheckTxVersion (477) */
+ /** @name FrameSystemExtensionsCheckTxVersion (485) */
type FrameSystemExtensionsCheckTxVersion = Null;
- /** @name FrameSystemExtensionsCheckGenesis (478) */
+ /** @name FrameSystemExtensionsCheckGenesis (486) */
type FrameSystemExtensionsCheckGenesis = Null;
- /** @name FrameSystemExtensionsCheckNonce (481) */
+ /** @name FrameSystemExtensionsCheckNonce (489) */
interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
- /** @name FrameSystemExtensionsCheckWeight (482) */
+ /** @name FrameSystemExtensionsCheckWeight (490) */
type FrameSystemExtensionsCheckWeight = Null;
- /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (483) */
+ /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (491) */
type OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance = Null;
- /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (484) */
+ /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (492) */
interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
- /** @name OpalRuntimeRuntime (485) */
+ /** @name OpalRuntimeRuntime (493) */
type OpalRuntimeRuntime = Null;
- /** @name PalletEthereumFakeTransactionFinalizer (486) */
+ /** @name PalletEthereumFakeTransactionFinalizer (494) */
type PalletEthereumFakeTransactionFinalizer = Null;
} // declare module
tests/src/interfaces/types.tsdiffbeforeafterboth--- a/tests/src/interfaces/types.ts
+++ b/tests/src/interfaces/types.ts
@@ -4,4 +4,5 @@
export * from './unique/types';
export * from './appPromotion/types';
export * from './rmrk/types';
+export * from './povinfo/types';
export * from './default/types';
tests/src/util/playgrounds/types.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/types.ts
+++ b/tests/src/util/playgrounds/types.ts
@@ -171,6 +171,14 @@
amount: bigint,
}
+export interface IPovInfo {
+ proofSize: number,
+ compactProofSize: number,
+ compressedProofSize: number,
+ results: any[],
+ kv: any,
+}
+
export interface ISchedulerOptions {
scheduledId?: string,
priority?: number,
tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -8,10 +8,11 @@
import * as defs from '../../interfaces/definitions';
import {IKeyringPair} from '@polkadot/types/types';
import {EventRecord} from '@polkadot/types/interfaces';
-import {ICrossAccountId, TSigner} from './types';
+import {ICrossAccountId, IPovInfo, TSigner} from './types';
import {FrameSystemEventRecord} from '@polkadot/types/lookup';
import {VoidFn} from '@polkadot/api/types';
import {Pallets} from '..';
+import {spawnSync} from 'child_process';
export class SilentLogger {
log(_msg: any, _level: any): void { }
@@ -98,6 +99,7 @@
rpc: {
unique: defs.unique.rpc,
appPromotion: defs.appPromotion.rpc,
+ povinfo: defs.povinfo.rpc,
rmrk: defs.rmrk.rpc,
eth: {
feeHistory: {
@@ -115,6 +117,7 @@
});
await this.api.isReadyOrError;
this.network = await UniqueHelper.detectNetwork(this.api);
+ this.wsEndpoint = wsEndpoint;
}
}
@@ -322,6 +325,38 @@
return balance;
}
+ async calculatePoVInfo(txs: any[]): Promise<IPovInfo> {
+ const rawPovInfo = await this.helper.callRpc('api.rpc.povinfo.estimateExtrinsicPoV', [txs]);
+
+ const kvJson: {[key: string]: string} = {};
+
+ for (const kv of rawPovInfo.keyValues) {
+ kvJson[kv.key.toHex()] = kv.value.toHex();
+ }
+
+ const kvStr = JSON.stringify(kvJson);
+
+ const chainql = spawnSync(
+ 'chainql',
+ [
+ `--tla-code=data=${kvStr}`,
+ '-e', `function(data) cql.dump(cql.chain("${this.helper.getEndpoint()}").latest._meta, data, {omit_empty:true})`,
+ ],
+ );
+
+ if (!chainql.stdout) {
+ throw Error('unable to get an output from the `chainql`');
+ }
+
+ return {
+ proofSize: rawPovInfo.proofSize.toNumber(),
+ compactProofSize: rawPovInfo.compactProofSize.toNumber(),
+ compressedProofSize: rawPovInfo.compressedProofSize.toNumber(),
+ results: rawPovInfo.results,
+ kv: JSON.parse(chainql.stdout.toString()),
+ };
+ }
+
calculatePalletAddress(palletId: any) {
const address = stringToU8a(('modl' + palletId).padEnd(32, '\0'));
return encodeAddress(address, this.helper.chain.getChainProperties().ss58Format);
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';12import {hexToU8a} from '@polkadot/util/hex';13import {u8aConcat} from '@polkadot/util/u8a';14import {15 IApiListeners,16 IBlock,17 IEvent,18 IChainProperties,19 ICollectionCreationOptions,20 ICollectionLimits,21 ICollectionPermissions,22 ICrossAccountId,23 ICrossAccountIdLower,24 ILogger,25 INestingPermissions,26 IProperty,27 IStakingInfo,28 ISchedulerOptions,29 ISubstrateBalance,30 IToken,31 ITokenPropertyPermission,32 ITransactionResult,33 IUniqueHelperLog,34 TApiAllowedListeners,35 TEthereumAccount,36 TSigner,37 TSubstrateAccount,38 TNetworks,39 IForeignAssetMetadata,40 AcalaAssetMetadata,41 MoonbeamAssetInfo,42 DemocracyStandardAccountVote,43 IEthCrossAccountId,44} from './types';45import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';46import type {Vec} from '@polkadot/types-codec';47import {FrameSystemEventRecord} from '@polkadot/types/lookup';4849export class CrossAccountId implements ICrossAccountId {50 Substrate?: TSubstrateAccount;51 Ethereum?: TEthereumAccount;5253 constructor(account: ICrossAccountId) {54 if (account.Substrate) this.Substrate = account.Substrate;55 if (account.Ethereum) this.Ethereum = account.Ethereum;56 }5758 static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {59 switch (domain) {60 case 'Substrate': return new CrossAccountId({Substrate: account.address});61 case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();62 }63 }6465 static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {66 return new CrossAccountId({Substrate: address.substrate, Ethereum: address.ethereum});67 }6869 static normalizeSubstrateAddress(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {70 return encodeAddress(decodeAddress(address), ss58Format);71 }7273 static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId {74 return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)});75 }7677 withNormalizedSubstrate(ss58Format = 42): CrossAccountId {78 if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format);79 return this;80 }8182 static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {83 return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));84 }8586 toEthereum(): CrossAccountId {87 if (this.Substrate) return new CrossAccountId({Ethereum: CrossAccountId.translateSubToEth(this.Substrate)});88 return this;89 }9091 static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {92 return evmToAddress(address, ss58Format);93 }9495 toSubstrate(ss58Format?: number): CrossAccountId {96 if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)});97 return this;98 }99100 toLowerCase(): CrossAccountId {101 if (this.Substrate) this.Substrate = this.Substrate.toLowerCase();102 if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase();103 return this;104 }105}106107const nesting = {108 toChecksumAddress(address: string): string {109 if (typeof address === 'undefined') return '';110111 if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);112113 address = address.toLowerCase().replace(/^0x/i,'');114 const addressHash = keccakAsHex(address).replace(/^0x/i,'');115 const checksumAddress = ['0x'];116117 for (let i = 0; i < address.length; i++) {118 // If ith character is 8 to f then make it uppercase119 if (parseInt(addressHash[i], 16) > 7) {120 checksumAddress.push(address[i].toUpperCase());121 } else {122 checksumAddress.push(address[i]);123 }124 }125 return checksumAddress.join('');126 },127 tokenIdToAddress(collectionId: number, tokenId: number) {128 return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8,'0')}${tokenId.toString(16).padStart(8,'0')}`);129 },130};131132class UniqueUtil {133 static transactionStatus = {134 NOT_READY: 'NotReady',135 FAIL: 'Fail',136 SUCCESS: 'Success',137 };138139 static chainLogType = {140 EXTRINSIC: 'extrinsic',141 RPC: 'rpc',142 };143144 static getTokenAccount(token: IToken): CrossAccountId {145 return new CrossAccountId({Ethereum: this.getTokenAddress(token)});146 }147148 static getTokenAddress(token: IToken): string {149 return nesting.tokenIdToAddress(token.collectionId, token.tokenId);150 }151152 static getDefaultLogger(): ILogger {153 return {154 log(msg: any, level = 'INFO') {155 console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));156 },157 level: {158 ERROR: 'ERROR',159 WARNING: 'WARNING',160 INFO: 'INFO',161 },162 };163 }164165 static vec2str(arr: string[] | number[]) {166 return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');167 }168169 static str2vec(string: string) {170 if (typeof string !== 'string') return string;171 return Array.from(string).map(x => x.charCodeAt(0));172 }173174 static fromSeed(seed: string, ss58Format = 42) {175 const keyring = new Keyring({type: 'sr25519', ss58Format});176 return keyring.addFromUri(seed);177 }178179 static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {180 if (creationResult.status !== this.transactionStatus.SUCCESS) {181 throw Error('Unable to create collection!');182 }183184 let collectionId = null;185 creationResult.result.events.forEach(({event: {data, method, section}}) => {186 if ((section === 'common') && (method === 'CollectionCreated')) {187 collectionId = parseInt(data[0].toString(), 10);188 }189 });190191 if (collectionId === null) {192 throw Error('No CollectionCreated event was found!');193 }194195 return collectionId;196 }197198 static extractTokensFromCreationResult(creationResult: ITransactionResult): {199 success: boolean,200 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],201 } {202 if (creationResult.status !== this.transactionStatus.SUCCESS) {203 throw Error('Unable to create tokens!');204 }205 let success = false;206 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];207 creationResult.result.events.forEach(({event: {data, method, section}}) => {208 if (method === 'ExtrinsicSuccess') {209 success = true;210 } else if ((section === 'common') && (method === 'ItemCreated')) {211 tokens.push({212 collectionId: parseInt(data[0].toString(), 10),213 tokenId: parseInt(data[1].toString(), 10),214 owner: data[2].toHuman(),215 amount: data[3].toBigInt(),216 });217 }218 });219 return {success, tokens};220 }221222 static extractTokensFromBurnResult(burnResult: ITransactionResult): {223 success: boolean,224 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],225 } {226 if (burnResult.status !== this.transactionStatus.SUCCESS) {227 throw Error('Unable to burn tokens!');228 }229 let success = false;230 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];231 burnResult.result.events.forEach(({event: {data, method, section}}) => {232 if (method === 'ExtrinsicSuccess') {233 success = true;234 } else if ((section === 'common') && (method === 'ItemDestroyed')) {235 tokens.push({236 collectionId: parseInt(data[0].toString(), 10),237 tokenId: parseInt(data[1].toString(), 10),238 owner: data[2].toHuman(),239 amount: data[3].toBigInt(),240 });241 }242 });243 return {success, tokens};244 }245246 static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {247 let eventId = null;248 events.forEach(({event: {data, method, section}}) => {249 if ((section === expectedSection) && (method === expectedMethod)) {250 eventId = parseInt(data[0].toString(), 10);251 }252 });253254 if (eventId === null) {255 throw Error(`No ${expectedMethod} event was found!`);256 }257 return eventId === collectionId;258 }259260 static isTokenTransferSuccess(events: {event: IEvent}[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {261 const normalizeAddress = (address: string | ICrossAccountId) => {262 if(typeof address === 'string') return address;263 const obj = {} as any;264 Object.keys(address).forEach(k => {265 obj[k.toLocaleLowerCase()] = address[k as 'Substrate' | 'Ethereum'];266 });267 if(obj.substrate) return CrossAccountId.withNormalizedSubstrate(obj.substrate);268 if(obj.ethereum) return CrossAccountId.fromLowerCaseKeys(obj).toLowerCase();269 return address;270 };271 let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;272 events.forEach(({event: {data, method, section}}) => {273 if ((section === 'common') && (method === 'Transfer')) {274 const hData = (data as any).toJSON();275 transfer = {276 collectionId: hData[0],277 tokenId: hData[1],278 from: normalizeAddress(hData[2]),279 to: normalizeAddress(hData[3]),280 amount: BigInt(hData[4]),281 };282 }283 });284 let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;285 isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);286 isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);287 isSuccess = isSuccess && amount === transfer.amount;288 return isSuccess;289 }290291 static bigIntToDecimals(number: bigint, decimals = 18) {292 const numberStr = number.toString();293 const dotPos = numberStr.length - decimals;294295 if (dotPos <= 0) {296 return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;297 } else {298 const intPart = numberStr.substring(0, dotPos);299 const fractPart = numberStr.substring(dotPos);300 return intPart + '.' + fractPart;301 }302 }303}304305class UniqueEventHelper {306 private static extractIndex(index: any): [number, number] | string {307 if(index.toRawType() === '[u8;2]') return [index[0], index[1]];308 return index.toJSON();309 }310311 private static extractSub(data: any, subTypes: any): {[key: string]: any} {312 let obj: any = {};313 let index = 0;314315 if (data.entries) {316 for(const [key, value] of data.entries()) {317 obj[key] = this.extractData(value, subTypes[index]);318 index++;319 }320 } else obj = data.toJSON();321322 return obj;323 }324325 private static toHuman(data: any) {326 return data && data.toHuman ? data.toHuman() : `${data}`;327 }328329 private static extractData(data: any, type: any): any {330 if(!type) return this.toHuman(data);331 if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();332 if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();333 if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);334 return this.toHuman(data);335 }336337 public static extractEvents(events: {event: any, phase: any}[]): IEvent[] {338 const parsedEvents: IEvent[] = [];339340 events.forEach((record) => {341 const {event, phase} = record;342 const types = event.typeDef;343344 const eventData: IEvent = {345 section: event.section.toString(),346 method: event.method.toString(),347 index: this.extractIndex(event.index),348 data: [],349 phase: phase.toJSON(),350 };351352 event.data.forEach((val: any, index: number) => {353 eventData.data.push(this.extractData(val, types[index]));354 });355356 parsedEvents.push(eventData);357 });358359 return parsedEvents;360 }361}362363export class ChainHelperBase {364 helperBase: any;365366 transactionStatus = UniqueUtil.transactionStatus;367 chainLogType = UniqueUtil.chainLogType;368 util: typeof UniqueUtil;369 eventHelper: typeof UniqueEventHelper;370 logger: ILogger;371 api: ApiPromise | null;372 forcedNetwork: TNetworks | null;373 network: TNetworks | null;374 chainLog: IUniqueHelperLog[];375 children: ChainHelperBase[];376 address: AddressGroup;377 chain: ChainGroup;378379 constructor(logger?: ILogger, helperBase?: any) {380 this.helperBase = helperBase;381382 this.util = UniqueUtil;383 this.eventHelper = UniqueEventHelper;384 if (typeof logger == 'undefined') logger = this.util.getDefaultLogger();385 this.logger = logger;386 this.api = null;387 this.forcedNetwork = null;388 this.network = null;389 this.chainLog = [];390 this.children = [];391 this.address = new AddressGroup(this);392 this.chain = new ChainGroup(this);393 }394395 clone(helperCls: ChainHelperBaseConstructor, options: {[key: string]: any} = {}) {396 Object.setPrototypeOf(helperCls.prototype, this);397 const newHelper = new helperCls(this.logger, options);398399 newHelper.api = this.api;400 newHelper.network = this.network;401 newHelper.forceNetwork = this.forceNetwork;402403 this.children.push(newHelper);404405 return newHelper;406 }407408 getApi(): ApiPromise {409 if(this.api === null) throw Error('API not initialized');410 return this.api;411 }412413 async subscribeEvents(expectedEvents: {section: string, names: string[]}[]) {414 const collectedEvents: IEvent[] = [];415 const unsubscribe = await this.getApi().query.system.events((events: Vec<FrameSystemEventRecord>) => {416 const ievents = this.eventHelper.extractEvents(events);417 ievents.forEach((event) => {418 expectedEvents.forEach((e => {419 if (event.section === e.section && e.names.includes(event.method)) {420 collectedEvents.push(event);421 }422 }));423 });424 });425 return {unsubscribe: unsubscribe as any, collectedEvents};426 }427428 clearChainLog(): void {429 this.chainLog = [];430 }431432 forceNetwork(value: TNetworks): void {433 this.forcedNetwork = value;434 }435436 async connect(wsEndpoint: string, listeners?: IApiListeners) {437 if (this.api !== null) throw Error('Already connected');438 const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);439 this.api = api;440 this.network = network;441 }442443 async disconnect() {444 for (const child of this.children) {445 child.clearApi();446 }447448 if (this.api === null) return;449 await this.api.disconnect();450 this.clearApi();451 }452453 clearApi() {454 this.api = null;455 this.network = null;456 }457458 static async detectNetwork(api: ApiPromise): Promise<TNetworks> {459 const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;460 const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];461462 if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;463464 if(['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;465 return 'opal';466 }467468 static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {469 const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});470 await api.isReady;471472 const network = await this.detectNetwork(api);473474 await api.disconnect();475476 return network;477 }478479 static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{480 api: ApiPromise;481 network: TNetworks;482 }> {483 if(typeof network === 'undefined' || network === null) network = 'opal';484 const supportedRPC = {485 opal: {486 unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,487 },488 quartz: {489 unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,490 },491 unique: {492 unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,493 },494 rococo: {},495 westend: {},496 moonbeam: {},497 moonriver: {},498 acala: {},499 karura: {},500 westmint: {},501 };502 if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);503 const rpc = supportedRPC[network];504505 // TODO: investigate how to replace rpc in runtime506 // api._rpcCore.addUserInterfaces(rpc);507508 const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});509510 await api.isReadyOrError;511512 if (typeof listeners === 'undefined') listeners = {};513 for (const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {514 if (!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;515 api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);516 }517518 return {api, network};519 }520521 getTransactionStatus(data: {events: {event: IEvent}[], status: any}) {522 const {events, status} = data;523 if (status.isReady) {524 return this.transactionStatus.NOT_READY;525 }526 if (status.isBroadcast) {527 return this.transactionStatus.NOT_READY;528 }529 if (status.isInBlock || status.isFinalized) {530 const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');531 if (errors.length > 0) {532 return this.transactionStatus.FAIL;533 }534 if (events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {535 return this.transactionStatus.SUCCESS;536 }537 }538539 return this.transactionStatus.FAIL;540 }541542 signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {543 const sign = (callback: any) => {544 if(options !== null) return transaction.signAndSend(sender, options, callback);545 return transaction.signAndSend(sender, callback);546 };547 // eslint-disable-next-line no-async-promise-executor548 return new Promise(async (resolve, reject) => {549 try {550 const unsub = await sign((result: any) => {551 const status = this.getTransactionStatus(result);552553 if (status === this.transactionStatus.SUCCESS) {554 this.logger.log(`${label} successful`);555 unsub();556 resolve({result, status});557 } else if (status === this.transactionStatus.FAIL) {558 let moduleError = null;559560 if (result.hasOwnProperty('dispatchError')) {561 const dispatchError = result['dispatchError'];562563 if (dispatchError) {564 if (dispatchError.isModule) {565 const modErr = dispatchError.asModule;566 const errorMeta = dispatchError.registry.findMetaError(modErr);567568 moduleError = `${errorMeta.section}.${errorMeta.name}`;569 } else {570 moduleError = dispatchError.toHuman();571 }572 } else {573 this.logger.log(result, this.logger.level.ERROR);574 }575 }576577 this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);578 unsub();579 reject({status, moduleError, result});580 }581 });582 } catch (e) {583 this.logger.log(e, this.logger.level.ERROR);584 reject(e);585 }586 });587 }588589 async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {590 const api = this.getApi();591 const signingInfo = await api.derive.tx.signingInfo(signer.address);592593 // We need to sign the tx because594 // unsigned transactions does not have an inclusion fee595 tx.sign(signer, {596 blockHash: api.genesisHash,597 genesisHash: api.genesisHash,598 runtimeVersion: api.runtimeVersion,599 nonce: signingInfo.nonce,600 });601602 if (len === null) {603 return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;604 } else {605 return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;606 }607 }608609 constructApiCall(apiCall: string, params: any[]) {610 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);611 let call = this.getApi() as any;612 for(const part of apiCall.slice(4).split('.')) {613 call = call[part];614 }615 return call(...params);616 }617618 async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {619 if(this.api === null) throw Error('API not initialized');620 if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);621622 const startTime = (new Date()).getTime();623 let result: ITransactionResult;624 let events: IEvent[] = [];625 try {626 result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;627 events = this.eventHelper.extractEvents(result.result.events);628 }629 catch(e) {630 if(!(e as object).hasOwnProperty('status')) throw e;631 result = e as ITransactionResult;632 }633634 const endTime = (new Date()).getTime();635636 const log = {637 executedAt: endTime,638 executionTime: endTime - startTime,639 type: this.chainLogType.EXTRINSIC,640 status: result.status,641 call: extrinsic,642 signer: this.getSignerAddress(sender),643 params,644 } as IUniqueHelperLog;645646 if(result.status !== this.transactionStatus.SUCCESS) {647 if (result.moduleError) log.moduleError = result.moduleError;648 else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;649 }650 if(events.length > 0) log.events = events;651652 this.chainLog.push(log);653654 if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {655 if (result.moduleError) throw Error(`${result.moduleError}`);656 else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));657 }658 return result;659 }660661 async callRpc(rpc: string, params?: any[]) {662 if(typeof params === 'undefined') params = [];663 if(this.api === null) throw Error('API not initialized');664 if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);665666 const startTime = (new Date()).getTime();667 let result;668 let error = null;669 const log = {670 type: this.chainLogType.RPC,671 call: rpc,672 params,673 } as IUniqueHelperLog;674675 try {676 result = await this.constructApiCall(rpc, params);677 }678 catch(e) {679 error = e;680 }681682 const endTime = (new Date()).getTime();683684 log.executedAt = endTime;685 log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';686 log.executionTime = endTime - startTime;687688 this.chainLog.push(log);689690 if(error !== null) throw error;691692 return result;693 }694695 getSignerAddress(signer: IKeyringPair | string): string {696 if(typeof signer === 'string') return signer;697 return signer.address;698 }699700 fetchAllPalletNames(): string[] {701 if(this.api === null) throw Error('API not initialized');702 return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());703 }704705 fetchMissingPalletNames(requiredPallets: string[]): string[] {706 const palletNames = this.fetchAllPalletNames();707 return requiredPallets.filter(p => !palletNames.includes(p));708 }709}710711712class HelperGroup<T extends ChainHelperBase> {713 helper: T;714715 constructor(uniqueHelper: T) {716 this.helper = uniqueHelper;717 }718}719720721class CollectionGroup extends HelperGroup<UniqueHelper> {722 /**723 * Get number of blocks when sponsored transaction is available.724 *725 * @param collectionId ID of collection726 * @param tokenId ID of token727 * @param addressObj address for which the sponsorship is checked728 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});729 * @returns number of blocks or null if sponsorship hasn't been set730 */731 async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {732 return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();733 }734735 /**736 * Get the number of created collections.737 *738 * @returns number of created collections739 */740 async getTotalCount(): Promise<number> {741 return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();742 }743744 /**745 * Get information about the collection with additional data,746 * including the number of tokens it contains, its administrators,747 * the normalized address of the collection's owner, and decoded name and description.748 *749 * @param collectionId ID of collection750 * @example await getData(2)751 * @returns collection information object752 */753 async getData(collectionId: number): Promise<{754 id: number;755 name: string;756 description: string;757 tokensCount: number;758 admins: CrossAccountId[];759 normalizedOwner: TSubstrateAccount;760 raw: any761 } | null> {762 const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);763 const humanCollection = collection.toHuman(), collectionData = {764 id: collectionId, name: null, description: null, tokensCount: 0, admins: [],765 raw: humanCollection,766 } as any, jsonCollection = collection.toJSON();767 if (humanCollection === null) return null;768 collectionData.raw.limits = jsonCollection.limits;769 collectionData.raw.permissions = jsonCollection.permissions;770 collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);771 for (const key of ['name', 'description']) {772 collectionData[key] = this.helper.util.vec2str(humanCollection[key]);773 }774775 collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))776 ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)777 : 0;778 collectionData.admins = await this.getAdmins(collectionId);779780 return collectionData;781 }782783 /**784 * Get the addresses of the collection's administrators, optionally normalized.785 *786 * @param collectionId ID of collection787 * @param normalize whether to normalize the addresses to the default ss58 format788 * @example await getAdmins(1)789 * @returns array of administrators790 */791 async getAdmins(collectionId: number, normalize = false): Promise<CrossAccountId[]> {792 const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();793794 return normalize795 ? admins.map((address: CrossAccountId) => address.withNormalizedSubstrate())796 : admins;797 }798799 /**800 * Get the addresses added to the collection allow-list, optionally normalized.801 * @param collectionId ID of collection802 * @param normalize whether to normalize the addresses to the default ss58 format803 * @example await getAllowList(1)804 * @returns array of allow-listed addresses805 */806 async getAllowList(collectionId: number, normalize = false): Promise<CrossAccountId[]> {807 const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();808 return normalize809 ? allowListed.map((address: CrossAccountId) => address.withNormalizedSubstrate())810 : allowListed;811 }812813 /**814 * Get the effective limits of the collection instead of null for default values815 *816 * @param collectionId ID of collection817 * @example await getEffectiveLimits(2)818 * @returns object of collection limits819 */820 async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {821 return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();822 }823824 /**825 * Burns the collection if the signer has sufficient permissions and collection is empty.826 *827 * @param signer keyring of signer828 * @param collectionId ID of collection829 * @example await helper.collection.burn(aliceKeyring, 3);830 * @returns ```true``` if extrinsic success, otherwise ```false```831 */832 async burn(signer: TSigner, collectionId: number): Promise<boolean> {833 const result = await this.helper.executeExtrinsic(834 signer,835 'api.tx.unique.destroyCollection', [collectionId],836 true,837 );838839 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');840 }841842 /**843 * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.844 *845 * @param signer keyring of signer846 * @param collectionId ID of collection847 * @param sponsorAddress Sponsor substrate address848 * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")849 * @returns ```true``` if extrinsic success, otherwise ```false```850 */851 async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {852 const result = await this.helper.executeExtrinsic(853 signer,854 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],855 true,856 );857858 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');859 }860861 /**862 * Confirms consent to sponsor the collection on behalf of the signer.863 *864 * @param signer keyring of signer865 * @param collectionId ID of collection866 * @example confirmSponsorship(aliceKeyring, 10)867 * @returns ```true``` if extrinsic success, otherwise ```false```868 */869 async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {870 const result = await this.helper.executeExtrinsic(871 signer,872 'api.tx.unique.confirmSponsorship', [collectionId],873 true,874 );875876 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');877 }878879 /**880 * Removes the sponsor of a collection, regardless if it consented or not.881 *882 * @param signer keyring of signer883 * @param collectionId ID of collection884 * @example removeSponsor(aliceKeyring, 10)885 * @returns ```true``` if extrinsic success, otherwise ```false```886 */887 async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {888 const result = await this.helper.executeExtrinsic(889 signer,890 'api.tx.unique.removeCollectionSponsor', [collectionId],891 true,892 );893894 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');895 }896897 /**898 * Sets the limits of the collection. At least one limit must be specified for a correct call.899 *900 * @param signer keyring of signer901 * @param collectionId ID of collection902 * @param limits collection limits object903 * @example904 * await setLimits(905 * aliceKeyring,906 * 10,907 * {908 * sponsorTransferTimeout: 0,909 * ownerCanDestroy: false910 * }911 * )912 * @returns ```true``` if extrinsic success, otherwise ```false```913 */914 async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {915 const result = await this.helper.executeExtrinsic(916 signer,917 'api.tx.unique.setCollectionLimits', [collectionId, limits],918 true,919 );920921 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');922 }923924 /**925 * Changes the owner of the collection to the new Substrate address.926 *927 * @param signer keyring of signer928 * @param collectionId ID of collection929 * @param ownerAddress substrate address of new owner930 * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")931 * @returns ```true``` if extrinsic success, otherwise ```false```932 */933 async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {934 const result = await this.helper.executeExtrinsic(935 signer,936 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],937 true,938 );939940 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');941 }942943 /**944 * Adds a collection administrator.945 *946 * @param signer keyring of signer947 * @param collectionId ID of collection948 * @param adminAddressObj Administrator address (substrate or ethereum)949 * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})950 * @returns ```true``` if extrinsic success, otherwise ```false```951 */952 async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {953 const result = await this.helper.executeExtrinsic(954 signer,955 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],956 true,957 );958959 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');960 }961962 /**963 * Removes a collection administrator.964 *965 * @param signer keyring of signer966 * @param collectionId ID of collection967 * @param adminAddressObj Administrator address (substrate or ethereum)968 * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})969 * @returns ```true``` if extrinsic success, otherwise ```false```970 */971 async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {972 const result = await this.helper.executeExtrinsic(973 signer,974 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],975 true,976 );977978 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');979 }980981 /**982 * Check if user is in allow list.983 *984 * @param collectionId ID of collection985 * @param user Account to check986 * @example await getAdmins(1)987 * @returns is user in allow list988 */989 async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {990 return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();991 }992993 /**994 * Adds an address to allow list995 * @param signer keyring of signer996 * @param collectionId ID of collection997 * @param addressObj address to add to the allow list998 * @returns ```true``` if extrinsic success, otherwise ```false```999 */1000 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1001 const result = await this.helper.executeExtrinsic(1002 signer,1003 'api.tx.unique.addToAllowList', [collectionId, addressObj],1004 true,1005 );10061007 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');1008 }10091010 /**1011 * Removes an address from allow list1012 *1013 * @param signer keyring of signer1014 * @param collectionId ID of collection1015 * @param addressObj address to remove from the allow list1016 * @returns ```true``` if extrinsic success, otherwise ```false```1017 */1018 async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1019 const result = await this.helper.executeExtrinsic(1020 signer,1021 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1022 true,1023 );10241025 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');1026 }10271028 /**1029 * Sets onchain permissions for selected collection.1030 *1031 * @param signer keyring of signer1032 * @param collectionId ID of collection1033 * @param permissions collection permissions object1034 * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1035 * @returns ```true``` if extrinsic success, otherwise ```false```1036 */1037 async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1038 const result = await this.helper.executeExtrinsic(1039 signer,1040 'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1041 true,1042 );10431044 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');1045 }10461047 /**1048 * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1049 *1050 * @param signer keyring of signer1051 * @param collectionId ID of collection1052 * @param permissions nesting permissions object1053 * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1054 * @returns ```true``` if extrinsic success, otherwise ```false```1055 */1056 async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1057 return await this.setPermissions(signer, collectionId, {nesting: permissions});1058 }10591060 /**1061 * Disables nesting for selected collection.1062 *1063 * @param signer keyring of signer1064 * @param collectionId ID of collection1065 * @example disableNesting(aliceKeyring, 10);1066 * @returns ```true``` if extrinsic success, otherwise ```false```1067 */1068 async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1069 return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1070 }10711072 /**1073 * Sets onchain properties to the collection.1074 *1075 * @param signer keyring of signer1076 * @param collectionId ID of collection1077 * @param properties array of property objects1078 * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1079 * @returns ```true``` if extrinsic success, otherwise ```false```1080 */1081 async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1082 const result = await this.helper.executeExtrinsic(1083 signer,1084 'api.tx.unique.setCollectionProperties', [collectionId, properties],1085 true,1086 );10871088 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1089 }10901091 /**1092 * Get collection properties.1093 *1094 * @param collectionId ID of collection1095 * @param propertyKeys optionally filter the returned properties to only these keys1096 * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1097 * @returns array of key-value pairs1098 */1099 async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1100 return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1101 }11021103 async getPropertiesConsumedSpace(collectionId: number): Promise<number> {1104 const api = this.helper.getApi();1105 const props = (await api.query.common.collectionProperties(collectionId)).toJSON();11061107 return (props! as any).consumedSpace;1108 }11091110 async getCollectionOptions(collectionId: number) {1111 return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1112 }11131114 /**1115 * Deletes onchain properties from the collection.1116 *1117 * @param signer keyring of signer1118 * @param collectionId ID of collection1119 * @param propertyKeys array of property keys to delete1120 * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1121 * @returns ```true``` if extrinsic success, otherwise ```false```1122 */1123 async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1124 const result = await this.helper.executeExtrinsic(1125 signer,1126 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1127 true,1128 );11291130 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1131 }11321133 /**1134 * Changes the owner of the token.1135 *1136 * @param signer keyring of signer1137 * @param collectionId ID of collection1138 * @param tokenId ID of token1139 * @param addressObj address of a new owner1140 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1141 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1142 * @returns true if the token success, otherwise false1143 */1144 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1145 const result = await this.helper.executeExtrinsic(1146 signer,1147 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1148 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1149 );11501151 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1152 }11531154 /**1155 *1156 * Change ownership of a token(s) on behalf of the owner.1157 *1158 * @param signer keyring of signer1159 * @param collectionId ID of collection1160 * @param tokenId ID of token1161 * @param fromAddressObj address on behalf of which the token will be sent1162 * @param toAddressObj new token owner1163 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1164 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1165 * @returns true if the token success, otherwise false1166 */1167 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1168 const result = await this.helper.executeExtrinsic(1169 signer,1170 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1171 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1172 );1173 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1174 }11751176 /**1177 *1178 * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1179 *1180 * @param signer keyring of signer1181 * @param collectionId ID of collection1182 * @param tokenId ID of token1183 * @param amount amount of tokens to be burned. For NFT must be set to 1n1184 * @example burnToken(aliceKeyring, 10, 5);1185 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1186 */1187 async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1188 const burnResult = await this.helper.executeExtrinsic(1189 signer,1190 'api.tx.unique.burnItem', [collectionId, tokenId, amount],1191 true, // `Unable to burn token for ${label}`,1192 );1193 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1194 if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1195 return burnedTokens.success;1196 }11971198 /**1199 * Destroys a concrete instance of NFT on behalf of the owner1200 *1201 * @param signer keyring of signer1202 * @param collectionId ID of collection1203 * @param tokenId ID of token1204 * @param fromAddressObj address on behalf of which the token will be burnt1205 * @param amount amount of tokens to be burned. For NFT must be set to 1n1206 * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1207 * @returns ```true``` if extrinsic success, otherwise ```false```1208 */1209 async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1210 const burnResult = await this.helper.executeExtrinsic(1211 signer,1212 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1213 true, // `Unable to burn token from for ${label}`,1214 );1215 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1216 return burnedTokens.success && burnedTokens.tokens.length > 0;1217 }12181219 /**1220 * Set, change, or remove approved address to transfer the ownership of the NFT.1221 *1222 * @param signer keyring of signer1223 * @param collectionId ID of collection1224 * @param tokenId ID of token1225 * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1226 * @param amount amount of token to be approved. For NFT must be set to 1n1227 * @returns ```true``` if extrinsic success, otherwise ```false```1228 */1229 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1230 const approveResult = await this.helper.executeExtrinsic(1231 signer,1232 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1233 true, // `Unable to approve token for ${label}`,1234 );12351236 return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1237 }12381239 /**1240 * Get the amount of token pieces approved to transfer or burn. Normally 0.1241 *1242 * @param collectionId ID of collection1243 * @param tokenId ID of token1244 * @param toAccountObj address which is approved to use token pieces1245 * @param fromAccountObj address which may have allowed the use of its owned tokens1246 * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1247 * @returns number of approved to transfer pieces1248 */1249 async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1250 return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1251 }12521253 /**1254 * Get the last created token ID in a collection1255 *1256 * @param collectionId ID of collection1257 * @example getLastTokenId(10);1258 * @returns id of the last created token1259 */1260 async getLastTokenId(collectionId: number): Promise<number> {1261 return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1262 }12631264 /**1265 * Check if token exists1266 *1267 * @param collectionId ID of collection1268 * @param tokenId ID of token1269 * @example doesTokenExist(10, 20);1270 * @returns true if the token exists, otherwise false1271 */1272 async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1273 return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1274 }1275}12761277class NFTnRFT extends CollectionGroup {1278 /**1279 * Get tokens owned by account1280 *1281 * @param collectionId ID of collection1282 * @param addressObj tokens owner1283 * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1284 * @returns array of token ids owned by account1285 */1286 async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1287 return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1288 }12891290 /**1291 * Get token data1292 *1293 * @param collectionId ID of collection1294 * @param tokenId ID of token1295 * @param propertyKeys optionally filter the token properties to only these keys1296 * @param blockHashAt optionally query the data at some block with this hash1297 * @example getToken(10, 5);1298 * @returns human readable token data1299 */1300 async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1301 properties: IProperty[];1302 owner: CrossAccountId;1303 normalizedOwner: CrossAccountId;1304 }| null> {1305 let tokenData;1306 if(typeof blockHashAt === 'undefined') {1307 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);1308 }1309 else {1310 if(propertyKeys.length == 0) {1311 const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1312 if(!collection) return null;1313 propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1314 }1315 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId, propertyKeys, blockHashAt]);1316 }1317 tokenData = tokenData.toHuman();1318 if (tokenData === null || tokenData.owner === null) return null;1319 const owner = {} as any;1320 for (const key of Object.keys(tokenData.owner)) {1321 owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate'1322 ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key])1323 : tokenData.owner[key];1324 }1325 tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner);1326 return tokenData;1327 }13281329 /**1330 * Set permissions to change token properties1331 *1332 * @param signer keyring of signer1333 * @param collectionId ID of collection1334 * @param permissions permissions to change a property by the collection admin or token owner1335 * @example setTokenPropertyPermissions(1336 * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1337 * )1338 * @returns true if extrinsic success otherwise false1339 */1340 async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1341 const result = await this.helper.executeExtrinsic(1342 signer,1343 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1344 true,1345 );13461347 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1348 }13491350 /**1351 * Get token property permissions.1352 *1353 * @param collectionId ID of collection1354 * @param propertyKeys optionally filter the returned property permissions to only these keys1355 * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1356 * @returns array of key-permission pairs1357 */1358 async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1359 return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1360 }13611362 /**1363 * Set token properties1364 *1365 * @param signer keyring of signer1366 * @param collectionId ID of collection1367 * @param tokenId ID of token1368 * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1369 * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1370 * @returns ```true``` if extrinsic success, otherwise ```false```1371 */1372 async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1373 const result = await this.helper.executeExtrinsic(1374 signer,1375 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1376 true,1377 );13781379 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1380 }13811382 /**1383 * Get properties, metadata assigned to a token.1384 *1385 * @param collectionId ID of collection1386 * @param tokenId ID of token1387 * @param propertyKeys optionally filter the returned properties to only these keys1388 * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1389 * @returns array of key-value pairs1390 */1391 async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1392 return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1393 }13941395 /**1396 * Delete the provided properties of a token1397 * @param signer keyring of signer1398 * @param collectionId ID of collection1399 * @param tokenId ID of token1400 * @param propertyKeys property keys to be deleted1401 * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1402 * @returns ```true``` if extrinsic success, otherwise ```false```1403 */1404 async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1405 const result = await this.helper.executeExtrinsic(1406 signer,1407 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1408 true,1409 );14101411 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1412 }14131414 /**1415 * Mint new collection1416 *1417 * @param signer keyring of signer1418 * @param collectionOptions basic collection options and properties1419 * @param mode NFT or RFT type of a collection1420 * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1421 * @returns object of the created collection1422 */1423 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1424 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1425 collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1426 for (const key of ['name', 'description', 'tokenPrefix']) {1427 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1428 }1429 const creationResult = await this.helper.executeExtrinsic(1430 signer,1431 'api.tx.unique.createCollectionEx', [collectionOptions],1432 true, // errorLabel,1433 );1434 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1435 }14361437 getCollectionObject(_collectionId: number): any {1438 return null;1439 }14401441 getTokenObject(_collectionId: number, _tokenId: number): any {1442 return null;1443 }14441445 /**1446 * Tells whether the given `owner` approves the `operator`.1447 * @param collectionId ID of collection1448 * @param owner owner address1449 * @param operator operator addrees1450 * @returns true if operator is enabled1451 */1452 async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {1453 return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();1454 }14551456 /** Sets or unsets the approval of a given operator.1457 * The `operator` is allowed to transfer all tokens of the `caller` on their behalf.1458 * @param operator Operator1459 * @param approved Should operator status be granted or revoked?1460 * @returns ```true``` if extrinsic success, otherwise ```false```1461 */1462 async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {1463 const result = await this.helper.executeExtrinsic(1464 signer,1465 'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],1466 true,1467 );1468 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');1469 }1470}147114721473class NFTGroup extends NFTnRFT {1474 /**1475 * Get collection object1476 * @param collectionId ID of collection1477 * @example getCollectionObject(2);1478 * @returns instance of UniqueNFTCollection1479 */1480 getCollectionObject(collectionId: number): UniqueNFTCollection {1481 return new UniqueNFTCollection(collectionId, this.helper);1482 }14831484 /**1485 * Get token object1486 * @param collectionId ID of collection1487 * @param tokenId ID of token1488 * @example getTokenObject(10, 5);1489 * @returns instance of UniqueNFTToken1490 */1491 getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1492 return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1493 }14941495 /**1496 * Get token's owner1497 * @param collectionId ID of collection1498 * @param tokenId ID of token1499 * @param blockHashAt optionally query the data at the block with this hash1500 * @example getTokenOwner(10, 5);1501 * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1502 */1503 async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId> {1504 let owner;1505 if (typeof blockHashAt === 'undefined') {1506 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1507 } else {1508 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1509 }1510 return CrossAccountId.fromLowerCaseKeys(owner.toJSON());1511 }15121513 /**1514 * Is token approved to transfer1515 * @param collectionId ID of collection1516 * @param tokenId ID of token1517 * @param toAccountObj address to be approved1518 * @returns ```true``` if extrinsic success, otherwise ```false```1519 */1520 async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1521 return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1522 }15231524 /**1525 * Changes the owner of the token.1526 *1527 * @param signer keyring of signer1528 * @param collectionId ID of collection1529 * @param tokenId ID of token1530 * @param addressObj address of a new owner1531 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1532 * @returns ```true``` if extrinsic success, otherwise ```false```1533 */1534 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1535 return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1536 }15371538 /**1539 *1540 * Change ownership of a NFT on behalf of the owner.1541 *1542 * @param signer keyring of signer1543 * @param collectionId ID of collection1544 * @param tokenId ID of token1545 * @param fromAddressObj address on behalf of which the token will be sent1546 * @param toAddressObj new token owner1547 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1548 * @returns ```true``` if extrinsic success, otherwise ```false```1549 */1550 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1551 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1552 }15531554 /**1555 * Recursively find the address that owns the token1556 * @param collectionId ID of collection1557 * @param tokenId ID of token1558 * @param blockHashAt1559 * @example getTokenTopmostOwner(10, 5);1560 * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1561 */1562 async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId | null> {1563 let owner;1564 if (typeof blockHashAt === 'undefined') {1565 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1566 } else {1567 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1568 }15691570 if (owner === null) return null;15711572 return owner.toHuman();1573 }15741575 /**1576 * Get tokens nested in the provided token1577 * @param collectionId ID of collection1578 * @param tokenId ID of token1579 * @param blockHashAt optionally query the data at the block with this hash1580 * @example getTokenChildren(10, 5);1581 * @returns tokens whose depth of nesting is <= 51582 */1583 async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1584 let children;1585 if(typeof blockHashAt === 'undefined') {1586 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1587 } else {1588 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1589 }15901591 return children.toJSON().map((x: any) => {1592 return {collectionId: x.collection, tokenId: x.token};1593 });1594 }15951596 /**1597 * Nest one token into another1598 * @param signer keyring of signer1599 * @param tokenObj token to be nested1600 * @param rootTokenObj token to be parent1601 * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1602 * @returns ```true``` if extrinsic success, otherwise ```false```1603 */1604 async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1605 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1606 const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1607 if(!result) {1608 throw Error('Unable to nest token!');1609 }1610 return result;1611 }16121613 /**1614 * Remove token from nested state1615 * @param signer keyring of signer1616 * @param tokenObj token to unnest1617 * @param rootTokenObj parent of a token1618 * @param toAddressObj address of a new token owner1619 * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1620 * @returns ```true``` if extrinsic success, otherwise ```false```1621 */1622 async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1623 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1624 const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1625 if(!result) {1626 throw Error('Unable to unnest token!');1627 }1628 return result;1629 }16301631 /**1632 * Mint new collection1633 * @param signer keyring of signer1634 * @param collectionOptions Collection options1635 * @example1636 * mintCollection(aliceKeyring, {1637 * name: 'New',1638 * description: 'New collection',1639 * tokenPrefix: 'NEW',1640 * })1641 * @returns object of the created collection1642 */1643 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1644 return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1645 }16461647 /**1648 * Mint new token1649 * @param signer keyring of signer1650 * @param data token data1651 * @returns created token object1652 */1653 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1654 const creationResult = await this.helper.executeExtrinsic(1655 signer,1656 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1657 nft: {1658 properties: data.properties,1659 },1660 }],1661 true,1662 );1663 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1664 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1665 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1666 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1667 }16681669 /**1670 * Mint multiple NFT tokens1671 * @param signer keyring of signer1672 * @param collectionId ID of collection1673 * @param tokens array of tokens with owner and properties1674 * @example1675 * mintMultipleTokens(aliceKeyring, 10, [{1676 * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1677 * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1678 * },{1679 * owner: {Ethereum: "0x9F0583DbB855d..."},1680 * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1681 * }]);1682 * @returns ```true``` if extrinsic success, otherwise ```false```1683 */1684 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1685 const creationResult = await this.helper.executeExtrinsic(1686 signer,1687 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1688 true,1689 );1690 const collection = this.getCollectionObject(collectionId);1691 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1692 }16931694 /**1695 * Mint multiple NFT tokens with one owner1696 * @param signer keyring of signer1697 * @param collectionId ID of collection1698 * @param owner tokens owner1699 * @param tokens array of tokens with owner and properties1700 * @example1701 * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1702 * properties: [{1703 * key: "gender",1704 * value: "female",1705 * },{1706 * key: "age",1707 * value: "33",1708 * }],1709 * }]);1710 * @returns array of newly created tokens1711 */1712 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1713 const rawTokens = [];1714 for (const token of tokens) {1715 const raw = {NFT: {properties: token.properties}};1716 rawTokens.push(raw);1717 }1718 const creationResult = await this.helper.executeExtrinsic(1719 signer,1720 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1721 true,1722 );1723 const collection = this.getCollectionObject(collectionId);1724 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1725 }17261727 /**1728 * Set, change, or remove approved address to transfer the ownership of the NFT.1729 *1730 * @param signer keyring of signer1731 * @param collectionId ID of collection1732 * @param tokenId ID of token1733 * @param toAddressObj address to approve1734 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1735 * @returns ```true``` if extrinsic success, otherwise ```false```1736 */1737 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1738 return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1739 }1740}174117421743class RFTGroup extends NFTnRFT {1744 /**1745 * Get collection object1746 * @param collectionId ID of collection1747 * @example getCollectionObject(2);1748 * @returns instance of UniqueRFTCollection1749 */1750 getCollectionObject(collectionId: number): UniqueRFTCollection {1751 return new UniqueRFTCollection(collectionId, this.helper);1752 }17531754 /**1755 * Get token object1756 * @param collectionId ID of collection1757 * @param tokenId ID of token1758 * @example getTokenObject(10, 5);1759 * @returns instance of UniqueNFTToken1760 */1761 getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1762 return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1763 }17641765 /**1766 * Get top 10 token owners with the largest number of pieces1767 * @param collectionId ID of collection1768 * @param tokenId ID of token1769 * @example getTokenTop10Owners(10, 5);1770 * @returns array of top 10 owners1771 */1772 async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<CrossAccountId[]> {1773 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys);1774 }17751776 /**1777 * Get number of pieces owned by address1778 * @param collectionId ID of collection1779 * @param tokenId ID of token1780 * @param addressObj address token owner1781 * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1782 * @returns number of pieces ownerd by address1783 */1784 async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1785 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1786 }17871788 /**1789 * Transfer pieces of token to another address1790 * @param signer keyring of signer1791 * @param collectionId ID of collection1792 * @param tokenId ID of token1793 * @param addressObj address of a new owner1794 * @param amount number of pieces to be transfered1795 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1796 * @returns ```true``` if extrinsic success, otherwise ```false```1797 */1798 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1799 return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1800 }18011802 /**1803 * Change ownership of some pieces of RFT on behalf of the owner.1804 * @param signer keyring of signer1805 * @param collectionId ID of collection1806 * @param tokenId ID of token1807 * @param fromAddressObj address on behalf of which the token will be sent1808 * @param toAddressObj new token owner1809 * @param amount number of pieces to be transfered1810 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1811 * @returns ```true``` if extrinsic success, otherwise ```false```1812 */1813 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1814 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1815 }18161817 /**1818 * Mint new collection1819 * @param signer keyring of signer1820 * @param collectionOptions Collection options1821 * @example1822 * mintCollection(aliceKeyring, {1823 * name: 'New',1824 * description: 'New collection',1825 * tokenPrefix: 'NEW',1826 * })1827 * @returns object of the created collection1828 */1829 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1830 return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1831 }18321833 /**1834 * Mint new token1835 * @param signer keyring of signer1836 * @param data token data1837 * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1838 * @returns created token object1839 */1840 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1841 const creationResult = await this.helper.executeExtrinsic(1842 signer,1843 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1844 refungible: {1845 pieces: data.pieces,1846 properties: data.properties,1847 },1848 }],1849 true,1850 );1851 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1852 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1853 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1854 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1855 }18561857 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1858 throw Error('Not implemented');1859 const creationResult = await this.helper.executeExtrinsic(1860 signer,1861 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],1862 true, // `Unable to mint RFT tokens for ${label}`,1863 );1864 const collection = this.getCollectionObject(collectionId);1865 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1866 }18671868 /**1869 * Mint multiple RFT tokens with one owner1870 * @param signer keyring of signer1871 * @param collectionId ID of collection1872 * @param owner tokens owner1873 * @param tokens array of tokens with properties and pieces1874 * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);1875 * @returns array of newly created RFT tokens1876 */1877 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1878 const rawTokens = [];1879 for (const token of tokens) {1880 const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};1881 rawTokens.push(raw);1882 }1883 const creationResult = await this.helper.executeExtrinsic(1884 signer,1885 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1886 true,1887 );1888 const collection = this.getCollectionObject(collectionId);1889 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1890 }18911892 /**1893 * Destroys a concrete instance of RFT.1894 * @param signer keyring of signer1895 * @param collectionId ID of collection1896 * @param tokenId ID of token1897 * @param amount number of pieces to be burnt1898 * @example burnToken(aliceKeyring, 10, 5);1899 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1900 */1901 async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1902 return await super.burnToken(signer, collectionId, tokenId, amount);1903 }19041905 /**1906 * Destroys a concrete instance of RFT on behalf of the owner.1907 * @param signer keyring of signer1908 * @param collectionId ID of collection1909 * @param tokenId ID of token1910 * @param fromAddressObj address on behalf of which the token will be burnt1911 * @param amount number of pieces to be burnt1912 * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)1913 * @returns ```true``` if extrinsic success, otherwise ```false```1914 */1915 async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1916 return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);1917 }19181919 /**1920 * Set, change, or remove approved address to transfer the ownership of the RFT.1921 *1922 * @param signer keyring of signer1923 * @param collectionId ID of collection1924 * @param tokenId ID of token1925 * @param toAddressObj address to approve1926 * @param amount number of pieces to be approved1927 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1928 * @returns true if the token success, otherwise false1929 */1930 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1931 return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1932 }19331934 /**1935 * Get total number of pieces1936 * @param collectionId ID of collection1937 * @param tokenId ID of token1938 * @example getTokenTotalPieces(10, 5);1939 * @returns number of pieces1940 */1941 async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {1942 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();1943 }19441945 /**1946 * Change number of token pieces. Signer must be the owner of all token pieces.1947 * @param signer keyring of signer1948 * @param collectionId ID of collection1949 * @param tokenId ID of token1950 * @param amount new number of pieces1951 * @example repartitionToken(aliceKeyring, 10, 5, 12345n);1952 * @returns true if the repartion was success, otherwise false1953 */1954 async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {1955 const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);1956 const repartitionResult = await this.helper.executeExtrinsic(1957 signer,1958 'api.tx.unique.repartition', [collectionId, tokenId, amount],1959 true,1960 );1961 if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');1962 return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');1963 }1964}196519661967class FTGroup extends CollectionGroup {1968 /**1969 * Get collection object1970 * @param collectionId ID of collection1971 * @example getCollectionObject(2);1972 * @returns instance of UniqueFTCollection1973 */1974 getCollectionObject(collectionId: number): UniqueFTCollection {1975 return new UniqueFTCollection(collectionId, this.helper);1976 }19771978 /**1979 * Mint new fungible collection1980 * @param signer keyring of signer1981 * @param collectionOptions Collection options1982 * @param decimalPoints number of token decimals1983 * @example1984 * mintCollection(aliceKeyring, {1985 * name: 'New',1986 * description: 'New collection',1987 * tokenPrefix: 'NEW',1988 * }, 18)1989 * @returns newly created fungible collection1990 */1991 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {1992 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1993 if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');1994 collectionOptions.mode = {fungible: decimalPoints};1995 for (const key of ['name', 'description', 'tokenPrefix']) {1996 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1997 }1998 const creationResult = await this.helper.executeExtrinsic(1999 signer,2000 'api.tx.unique.createCollectionEx', [collectionOptions],2001 true,2002 );2003 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));2004 }20052006 /**2007 * Mint tokens2008 * @param signer keyring of signer2009 * @param collectionId ID of collection2010 * @param owner address owner of new tokens2011 * @param amount amount of tokens to be meanted2012 * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);2013 * @returns ```true``` if extrinsic success, otherwise ```false```2014 */2015 async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {2016 const creationResult = await this.helper.executeExtrinsic(2017 signer,2018 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {2019 fungible: {2020 value: amount,2021 },2022 }],2023 true, // `Unable to mint fungible tokens for ${label}`,2024 );2025 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2026 }20272028 /**2029 * Mint multiple Fungible tokens with one owner2030 * @param signer keyring of signer2031 * @param collectionId ID of collection2032 * @param owner tokens owner2033 * @param tokens array of tokens with properties and pieces2034 * @returns ```true``` if extrinsic success, otherwise ```false```2035 */2036 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {2037 const rawTokens = [];2038 for (const token of tokens) {2039 const raw = {Fungible: {Value: token.value}};2040 rawTokens.push(raw);2041 }2042 const creationResult = await this.helper.executeExtrinsic(2043 signer,2044 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2045 true,2046 );2047 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2048 }20492050 /**2051 * Get the top 10 owners with the largest balance for the Fungible collection2052 * @param collectionId ID of collection2053 * @example getTop10Owners(10);2054 * @returns array of ```ICrossAccountId```2055 */2056 async getTop10Owners(collectionId: number): Promise<CrossAccountId[]> {2057 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys);2058 }20592060 /**2061 * Get account balance2062 * @param collectionId ID of collection2063 * @param addressObj address of owner2064 * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2065 * @returns amount of fungible tokens owned by address2066 */2067 async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2068 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2069 }20702071 /**2072 * Transfer tokens to address2073 * @param signer keyring of signer2074 * @param collectionId ID of collection2075 * @param toAddressObj address recipient2076 * @param amount amount of tokens to be sent2077 * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2078 * @returns ```true``` if extrinsic success, otherwise ```false```2079 */2080 async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2081 return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2082 }20832084 /**2085 * Transfer some tokens on behalf of the owner.2086 * @param signer keyring of signer2087 * @param collectionId ID of collection2088 * @param fromAddressObj address on behalf of which tokens will be sent2089 * @param toAddressObj address where token to be sent2090 * @param amount number of tokens to be sent2091 * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2092 * @returns ```true``` if extrinsic success, otherwise ```false```2093 */2094 async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {2095 return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2096 }20972098 /**2099 * Destroy some amount of tokens2100 * @param signer keyring of signer2101 * @param collectionId ID of collection2102 * @param amount amount of tokens to be destroyed2103 * @example burnTokens(aliceKeyring, 10, 1000n);2104 * @returns ```true``` if extrinsic success, otherwise ```false```2105 */2106 async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {2107 return await super.burnToken(signer, collectionId, 0, amount);2108 }21092110 /**2111 * Burn some tokens on behalf of the owner.2112 * @param signer keyring of signer2113 * @param collectionId ID of collection2114 * @param fromAddressObj address on behalf of which tokens will be burnt2115 * @param amount amount of tokens to be burnt2116 * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2117 * @returns ```true``` if extrinsic success, otherwise ```false```2118 */2119 async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {2120 return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2121 }21222123 /**2124 * Get total collection supply2125 * @param collectionId2126 * @returns2127 */2128 async getTotalPieces(collectionId: number): Promise<bigint> {2129 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2130 }21312132 /**2133 * Set, change, or remove approved address to transfer tokens.2134 *2135 * @param signer keyring of signer2136 * @param collectionId ID of collection2137 * @param toAddressObj address to be approved2138 * @param amount amount of tokens to be approved2139 * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2140 * @returns ```true``` if extrinsic success, otherwise ```false```2141 */2142 approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2143 return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2144 }21452146 /**2147 * Get amount of fungible tokens approved to transfer2148 * @param collectionId ID of collection2149 * @param fromAddressObj owner of tokens2150 * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2151 * @returns number of tokens approved for the transfer2152 */2153 getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2154 return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2155 }2156}215721582159class ChainGroup extends HelperGroup<ChainHelperBase> {2160 /**2161 * Get system properties of a chain2162 * @example getChainProperties();2163 * @returns ss58Format, token decimals, and token symbol2164 */2165 getChainProperties(): IChainProperties {2166 const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2167 return {2168 ss58Format: properties.ss58Format.toJSON(),2169 tokenDecimals: properties.tokenDecimals.toJSON(),2170 tokenSymbol: properties.tokenSymbol.toJSON(),2171 };2172 }21732174 /**2175 * Get chain header2176 * @example getLatestBlockNumber();2177 * @returns the number of the last block2178 */2179 async getLatestBlockNumber(): Promise<number> {2180 return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2181 }21822183 /**2184 * Get block hash by block number2185 * @param blockNumber number of block2186 * @example getBlockHashByNumber(12345);2187 * @returns hash of a block2188 */2189 async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2190 const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2191 if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2192 return blockHash;2193 }21942195 // TODO add docs2196 async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2197 const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2198 if (!blockHash) return null;2199 return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2200 }22012202 /**2203 * Get latest relay block2204 * @returns {number} relay block2205 */2206 async getRelayBlockNumber(): Promise<bigint> {2207 const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;2208 return BigInt(blockNumber);2209 }22102211 /**2212 * Get account nonce2213 * @param address substrate address2214 * @example getNonce("5GrwvaEF5zXb26Fz...");2215 * @returns number, account's nonce2216 */2217 async getNonce(address: TSubstrateAccount): Promise<number> {2218 return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2219 }2220}22212222class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2223 /**2224 * Get substrate address balance2225 * @param address substrate address2226 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2227 * @returns amount of tokens on address2228 */2229 async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2230 return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2231 }22322233 /**2234 * Transfer tokens to substrate address2235 * @param signer keyring of signer2236 * @param address substrate address of a recipient2237 * @param amount amount of tokens to be transfered2238 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2239 * @returns ```true``` if extrinsic success, otherwise ```false```2240 */2241 async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2242 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}`*/);22432244 let transfer = {from: null, to: null, amount: 0n} as any;2245 result.result.events.forEach(({event: {data, method, section}}) => {2246 if ((section === 'balances') && (method === 'Transfer')) {2247 transfer = {2248 from: this.helper.address.normalizeSubstrate(data[0]),2249 to: this.helper.address.normalizeSubstrate(data[1]),2250 amount: BigInt(data[2]),2251 };2252 }2253 });2254 const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2255 && this.helper.address.normalizeSubstrate(address) === transfer.to2256 && BigInt(amount) === transfer.amount;2257 return isSuccess;2258 }22592260 /**2261 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2262 * @param address substrate address2263 * @returns2264 */2265 async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2266 const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2267 return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2268 }22692270 async getLocked(address: TSubstrateAccount): Promise<[{id: string, amount: bigint, reason: string}]> {2271 const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();2272 return locks.map((lock: any) => {return {id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons};});2273 }2274}22752276class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2277 /**2278 * Get ethereum address balance2279 * @param address ethereum address2280 * @example getEthereum("0x9F0583DbB855d...")2281 * @returns amount of tokens on address2282 */2283 async getEthereum(address: TEthereumAccount): Promise<bigint> {2284 return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2285 }22862287 /**2288 * Transfer tokens to address2289 * @param signer keyring of signer2290 * @param address Ethereum address of a recipient2291 * @param amount amount of tokens to be transfered2292 * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2293 * @returns ```true``` if extrinsic success, otherwise ```false```2294 */2295 async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2296 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);22972298 let transfer = {from: null, to: null, amount: 0n} as any;2299 result.result.events.forEach(({event: {data, method, section}}) => {2300 if ((section === 'balances') && (method === 'Transfer')) {2301 transfer = {2302 from: data[0].toString(),2303 to: data[1].toString(),2304 amount: BigInt(data[2]),2305 };2306 }2307 });2308 const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2309 && address === transfer.to2310 && BigInt(amount) === transfer.amount;2311 return isSuccess;2312 }2313}23142315class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2316 subBalanceGroup: SubstrateBalanceGroup<T>;2317 ethBalanceGroup: EthereumBalanceGroup<T>;23182319 constructor(helper: T) {2320 super(helper);2321 this.subBalanceGroup = new SubstrateBalanceGroup(helper);2322 this.ethBalanceGroup = new EthereumBalanceGroup(helper);2323 }23242325 getCollectionCreationPrice(): bigint {2326 return 2n * this.getOneTokenNominal();2327 }2328 /**2329 * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2330 * @example getOneTokenNominal()2331 * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2332 */2333 getOneTokenNominal(): bigint {2334 const chainProperties = this.helper.chain.getChainProperties();2335 return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2336 }23372338 /**2339 * Get substrate address balance2340 * @param address substrate address2341 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2342 * @returns amount of tokens on address2343 */2344 getSubstrate(address: TSubstrateAccount): Promise<bigint> {2345 return this.subBalanceGroup.getSubstrate(address);2346 }23472348 /**2349 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2350 * @param address substrate address2351 * @returns2352 */2353 getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2354 return this.subBalanceGroup.getSubstrateFull(address);2355 }23562357 /**2358 * Get locked balances2359 * @param address substrate address2360 * @returns locked balances with reason via api.query.balances.locks2361 */2362 getLocked(address: TSubstrateAccount) {2363 return this.subBalanceGroup.getLocked(address);2364 }23652366 /**2367 * Get ethereum address balance2368 * @param address ethereum address2369 * @example getEthereum("0x9F0583DbB855d...")2370 * @returns amount of tokens on address2371 */2372 getEthereum(address: TEthereumAccount): Promise<bigint> {2373 return this.ethBalanceGroup.getEthereum(address);2374 }23752376 /**2377 * Transfer tokens to substrate address2378 * @param signer keyring of signer2379 * @param address substrate address of a recipient2380 * @param amount amount of tokens to be transfered2381 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2382 * @returns ```true``` if extrinsic success, otherwise ```false```2383 */2384 transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2385 return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2386 }23872388 async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2389 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);23902391 let transfer = {from: null, to: null, amount: 0n} as any;2392 result.result.events.forEach(({event: {data, method, section}}) => {2393 if ((section === 'balances') && (method === 'Transfer')) {2394 transfer = {2395 from: this.helper.address.normalizeSubstrate(data[0]),2396 to: this.helper.address.normalizeSubstrate(data[1]),2397 amount: BigInt(data[2]),2398 };2399 }2400 });2401 let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2402 isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2403 isSuccess = isSuccess && BigInt(amount) === transfer.amount;2404 return isSuccess;2405 }24062407 /**2408 * Transfer tokens with the unlock period2409 * @param signer signers Keyring2410 * @param address Substrate address of recipient2411 * @param schedule Schedule params2412 * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 50002413 */2414 async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: {start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}): Promise<void> {2415 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);2416 const event = result.result.events2417 .find(e => e.event.section === 'vesting' &&2418 e.event.method === 'VestingScheduleAdded' &&2419 e.event.data[0].toHuman() === signer.address);2420 if (!event) throw Error('Cannot find transfer in events');2421 }24222423 /**2424 * Get schedule for recepient of vested transfer2425 * @param address Substrate address of recipient2426 * @returns2427 */2428 async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> {2429 const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2430 return schedule.map((schedule: any) => {2431 return {2432 start: BigInt(schedule.start),2433 period: BigInt(schedule.period),2434 periodCount: BigInt(schedule.periodCount),2435 perPeriod: BigInt(schedule.perPeriod),2436 };2437 });2438 }24392440 /**2441 * Claim vested tokens2442 * @param signer signers Keyring2443 */2444 async claim(signer: TSigner) {2445 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);2446 const event = result.result.events2447 .find(e => e.event.section === 'vesting' &&2448 e.event.method === 'Claimed' &&2449 e.event.data[0].toHuman() === signer.address);2450 if (!event) throw Error('Cannot find claim in events');2451 }2452}24532454class AddressGroup extends HelperGroup<ChainHelperBase> {2455 /**2456 * Normalizes the address to the specified ss58 format, by default ```42```.2457 * @param address substrate address2458 * @param ss58Format format for address conversion, by default ```42```2459 * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2460 * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2461 */2462 normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2463 return CrossAccountId.normalizeSubstrateAddress(address, ss58Format);2464 }24652466 /**2467 * Get address in the connected chain format2468 * @param address substrate address2469 * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2470 * @returns address in chain format2471 */2472 normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2473 return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2474 }24752476 /**2477 * Get substrate mirror of an ethereum address2478 * @param ethAddress ethereum address2479 * @param toChainFormat false for normalized account2480 * @example ethToSubstrate('0x9F0583DbB855d...')2481 * @returns substrate mirror of a provided ethereum address2482 */2483 ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat=false): TSubstrateAccount {2484 return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2485 }24862487 /**2488 * Get ethereum mirror of a substrate address2489 * @param subAddress substrate account2490 * @example substrateToEth("5DnSF6RRjwteE3BrC...")2491 * @returns ethereum mirror of a provided substrate address2492 */2493 substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2494 return CrossAccountId.translateSubToEth(subAddress);2495 }24962497 /**2498 * Encode key to substrate address2499 * @param key key for encoding address2500 * @param ss58Format prefix for encoding to the address of the corresponding network2501 * @returns encoded substrate address2502 */2503 encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {2504 const u8a :Uint8Array = typeof key === 'string'2505 ? hexToU8a(key)2506 : typeof key === 'bigint'2507 ? hexToU8a(key.toString(16))2508 : key;25092510 if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2511 throw new Error(`ss58Format is not valid, received ${typeofss58Format} "${ss58Format}"`);2512 }25132514 const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2515 if (!allowedDecodedLengths.includes(u8a.length)) {2516 throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2517 }25182519 const u8aPrefix = ss58Format < 642520 ? new Uint8Array([ss58Format])2521 : new Uint8Array([2522 ((ss58Format & 0xfc) >> 2) | 0x40,2523 (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2524 ]);25252526 const input = u8aConcat(u8aPrefix, u8a);25272528 return base58Encode(u8aConcat(2529 input,2530 blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2531 ));2532 }25332534 /**2535 * Restore substrate address from bigint representation2536 * @param number decimal representation of substrate address2537 * @returns substrate address2538 */2539 restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2540 if (this.helper.api === null) {2541 throw 'Not connected';2542 }2543 const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2544 if (res === undefined || res === null) {2545 throw 'Restore address error';2546 }2547 return res.toString();2548 }25492550 /**2551 * Convert etherium cross account id to substrate cross account id2552 * @param ethCrossAccount etherium cross account2553 * @returns substrate cross account id2554 */2555 convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2556 if (ethCrossAccount.sub === '0') {2557 return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2558 }25592560 const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2561 return {Substrate: ss58};2562 }25632564 paraSiblingSovereignAccount(paraid: number) {2565 // We are getting a *sibling* parachain sovereign account,2566 // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2567 const siblingPrefix = '0x7369626c';25682569 const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2570 const suffix = '000000000000000000000000000000000000000000000000';25712572 return siblingPrefix + encodedParaId + suffix;2573 }2574}25752576class StakingGroup extends HelperGroup<UniqueHelper> {2577 /**2578 * Stake tokens for App Promotion2579 * @param signer keyring of signer2580 * @param amountToStake amount of tokens to stake2581 * @param label extra label for log2582 * @returns2583 */2584 async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2585 if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2586 const _stakeResult = await this.helper.executeExtrinsic(2587 signer, 'api.tx.appPromotion.stake',2588 [amountToStake], true,2589 );2590 // TODO extract info from stakeResult2591 return true;2592 }25932594 /**2595 * Unstake tokens for App Promotion2596 * @param signer keyring of signer2597 * @param amountToUnstake amount of tokens to unstake2598 * @param label extra label for log2599 * @returns block number where balances will be unlocked2600 */2601 async unstake(signer: TSigner, label?: string): Promise<number> {2602 if(typeof label === 'undefined') label = `${signer.address}`;2603 const _unstakeResult = await this.helper.executeExtrinsic(2604 signer, 'api.tx.appPromotion.unstake',2605 [], true,2606 );2607 // TODO extract block number fron events2608 return 1;2609 }26102611 /**2612 * Get total staked amount for address2613 * @param address substrate or ethereum address2614 * @returns total staked amount2615 */2616 async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2617 if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2618 return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2619 }26202621 /**2622 * Get total staked per block2623 * @param address substrate or ethereum address2624 * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2625 */2626 async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2627 const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2628 return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {2629 return {2630 block: block.toBigInt(),2631 amount: amount.toBigInt(),2632 };2633 });2634 }26352636 /**2637 * Get total pending unstake amount for address2638 * @param address substrate or ethereum address2639 * @returns total pending unstake amount2640 */2641 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2642 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2643 }26442645 /**2646 * Get pending unstake amount per block for address2647 * @param address substrate or ethereum address2648 * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2649 */2650 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2651 const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2652 const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {2653 return {2654 block: block.toBigInt(),2655 amount: amount.toBigInt(),2656 };2657 });2658 return result;2659 }2660}26612662class SchedulerGroup extends HelperGroup<UniqueHelper> {2663 constructor(helper: UniqueHelper) {2664 super(helper);2665 }26662667 cancelScheduled(signer: TSigner, scheduledId: string) {2668 return this.helper.executeExtrinsic(2669 signer,2670 'api.tx.scheduler.cancelNamed',2671 [scheduledId],2672 true,2673 );2674 }26752676 changePriority(signer: TSigner, scheduledId: string, priority: number) {2677 return this.helper.executeExtrinsic(2678 signer,2679 'api.tx.scheduler.changeNamedPriority',2680 [scheduledId, priority],2681 true,2682 );2683 }26842685 scheduleAt<T extends UniqueHelper>(2686 executionBlockNumber: number,2687 options: ISchedulerOptions = {},2688 ) {2689 return this.schedule<T>('schedule', executionBlockNumber, options);2690 }26912692 scheduleAfter<T extends UniqueHelper>(2693 blocksBeforeExecution: number,2694 options: ISchedulerOptions = {},2695 ) {2696 return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2697 }26982699 schedule<T extends UniqueHelper>(2700 scheduleFn: 'schedule' | 'scheduleAfter',2701 blocksNum: number,2702 options: ISchedulerOptions = {},2703 ) {2704 // eslint-disable-next-line @typescript-eslint/naming-convention2705 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2706 return this.helper.clone(ScheduledHelperType, {2707 scheduleFn,2708 blocksNum,2709 options,2710 }) as T;2711 }2712}27132714class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {2715 async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {2716 await this.helper.executeExtrinsic(2717 signer,2718 'api.tx.foreignAssets.registerForeignAsset',2719 [ownerAddress, location, metadata],2720 true,2721 );2722 }27232724 async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {2725 await this.helper.executeExtrinsic(2726 signer,2727 'api.tx.foreignAssets.updateForeignAsset',2728 [foreignAssetId, location, metadata],2729 true,2730 );2731 }2732}27332734class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {2735 palletName: string;27362737 constructor(helper: T, palletName: string) {2738 super(helper);27392740 this.palletName = palletName;2741 }27422743 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) {2744 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);2745 }27462747 async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {2748 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);2749 }27502751 async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint) {2752 const destination = {2753 V1: {2754 parents: 0,2755 interior: {2756 X1: {2757 Parachain: destinationParaId,2758 },2759 },2760 },2761 };27622763 const beneficiary = {2764 V1: {2765 parents: 0,2766 interior: {2767 X1: {2768 AccountId32: {2769 network: 'Any',2770 id: targetAccount,2771 },2772 },2773 },2774 },2775 };27762777 const assets = {2778 V1: [2779 {2780 id: {2781 Concrete: {2782 parents: 0,2783 interior: 'Here',2784 },2785 },2786 fun: {2787 Fungible: amount,2788 },2789 },2790 ],2791 };27922793 const feeAssetItem = 0;27942795 await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem);2796 }2797}27982799class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2800 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) {2801 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2802 }28032804 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) {2805 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2806 }28072808 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) {2809 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2810 }2811}28122813class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2814 async accounts(address: string, currencyId: any) {2815 const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;2816 return BigInt(free);2817 }2818}28192820class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {2821 async create(signer: TSigner, assetId: number, admin: string, minimalBalance: bigint) {2822 await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);2823 }28242825 async setMetadata(signer: TSigner, assetId: number, name: string, symbol: string, decimals: number) {2826 await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);2827 }28282829 async mint(signer: TSigner, assetId: number, beneficiary: string, amount: bigint) {2830 await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);2831 }28322833 async account(assetId: string | number, address: string) {2834 const accountAsset = (2835 await this.helper.callRpc('api.query.assets.account', [assetId, address])2836 ).toJSON()! as any;28372838 if (accountAsset !== null) {2839 return BigInt(accountAsset['balance']);2840 } else {2841 return null;2842 }2843 }2844}28452846class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {2847 async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {2848 await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);2849 }2850}28512852class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {2853 makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {2854 const apiPrefix = 'api.tx.assetManager.';28552856 const registerTx = this.helper.constructApiCall(2857 apiPrefix + 'registerForeignAsset',2858 [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],2859 );28602861 const setUnitsTx = this.helper.constructApiCall(2862 apiPrefix + 'setAssetUnitsPerSecond',2863 [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],2864 );28652866 const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);2867 const encodedProposal = batchCall?.method.toHex() || '';2868 return encodedProposal;2869 }28702871 async assetTypeId(location: any) {2872 return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);2873 }2874}28752876class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2877 notePreimagePallet: string;28782879 constructor(helper: MoonbeamHelper, options: {[key: string]: any} = {}) {2880 super(helper);2881 this.notePreimagePallet = options.notePreimagePallet;2882 }28832884 async notePreimage(signer: TSigner, encodedProposal: string) {2885 await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);2886 }28872888 externalProposeMajority(proposal: any) {2889 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);2890 }28912892 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2893 return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);2894 }28952896 async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {2897 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);2898 }2899}29002901class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {2902 collective: string;29032904 constructor(helper: MoonbeamHelper, collective: string) {2905 super(helper);29062907 this.collective = collective;2908 }29092910 async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {2911 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);2912 }29132914 async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {2915 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2916 }29172918 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {2919 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2920 }29212922 async proposalCount() {2923 return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));2924 }2925}29262927export type ChainHelperBaseConstructor = new(...args: any[]) => ChainHelperBase;2928export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;29292930export class UniqueHelper extends ChainHelperBase {2931 balance: BalanceGroup<UniqueHelper>;2932 collection: CollectionGroup;2933 nft: NFTGroup;2934 rft: RFTGroup;2935 ft: FTGroup;2936 staking: StakingGroup;2937 scheduler: SchedulerGroup;2938 foreignAssets: ForeignAssetsGroup;2939 xcm: XcmGroup<UniqueHelper>;2940 xTokens: XTokensGroup<UniqueHelper>;2941 tokens: TokensGroup<UniqueHelper>;29422943 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2944 super(logger, options.helperBase ?? UniqueHelper);29452946 this.balance = new BalanceGroup(this);2947 this.collection = new CollectionGroup(this);2948 this.nft = new NFTGroup(this);2949 this.rft = new RFTGroup(this);2950 this.ft = new FTGroup(this);2951 this.staking = new StakingGroup(this);2952 this.scheduler = new SchedulerGroup(this);2953 this.foreignAssets = new ForeignAssetsGroup(this);2954 this.xcm = new XcmGroup(this, 'polkadotXcm');2955 this.xTokens = new XTokensGroup(this);2956 this.tokens = new TokensGroup(this);2957 }29582959 getSudo<T extends UniqueHelper>() {2960 // eslint-disable-next-line @typescript-eslint/naming-convention2961 const SudoHelperType = SudoHelper(this.helperBase);2962 return this.clone(SudoHelperType) as T;2963 }2964}29652966export class XcmChainHelper extends ChainHelperBase {2967 async connect(wsEndpoint: string, _listeners?: any): Promise<void> {2968 const wsProvider = new WsProvider(wsEndpoint);2969 this.api = new ApiPromise({2970 provider: wsProvider,2971 });2972 await this.api.isReadyOrError;2973 this.network = await UniqueHelper.detectNetwork(this.api);2974 }2975}29762977export class RelayHelper extends XcmChainHelper {2978 balance: SubstrateBalanceGroup<RelayHelper>;2979 xcm: XcmGroup<RelayHelper>;29802981 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2982 super(logger, options.helperBase ?? RelayHelper);29832984 this.balance = new SubstrateBalanceGroup(this);2985 this.xcm = new XcmGroup(this, 'xcmPallet');2986 }2987}29882989export class WestmintHelper extends XcmChainHelper {2990 balance: SubstrateBalanceGroup<WestmintHelper>;2991 xcm: XcmGroup<WestmintHelper>;2992 assets: AssetsGroup<WestmintHelper>;2993 xTokens: XTokensGroup<WestmintHelper>;29942995 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2996 super(logger, options.helperBase ?? WestmintHelper);29972998 this.balance = new SubstrateBalanceGroup(this);2999 this.xcm = new XcmGroup(this, 'polkadotXcm');3000 this.assets = new AssetsGroup(this);3001 this.xTokens = new XTokensGroup(this);3002 }3003}30043005export class MoonbeamHelper extends XcmChainHelper {3006 balance: EthereumBalanceGroup<MoonbeamHelper>;3007 assetManager: MoonbeamAssetManagerGroup;3008 assets: AssetsGroup<MoonbeamHelper>;3009 xTokens: XTokensGroup<MoonbeamHelper>;3010 democracy: MoonbeamDemocracyGroup;3011 collective: {3012 council: MoonbeamCollectiveGroup,3013 techCommittee: MoonbeamCollectiveGroup,3014 };30153016 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {3017 super(logger, options.helperBase ?? MoonbeamHelper);30183019 this.balance = new EthereumBalanceGroup(this);3020 this.assetManager = new MoonbeamAssetManagerGroup(this);3021 this.assets = new AssetsGroup(this);3022 this.xTokens = new XTokensGroup(this);3023 this.democracy = new MoonbeamDemocracyGroup(this, options);3024 this.collective = {3025 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),3026 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),3027 };3028 }3029}30303031export class AcalaHelper extends XcmChainHelper {3032 balance: SubstrateBalanceGroup<AcalaHelper>;3033 assetRegistry: AcalaAssetRegistryGroup;3034 xTokens: XTokensGroup<AcalaHelper>;3035 tokens: TokensGroup<AcalaHelper>;30363037 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {3038 super(logger, options.helperBase ?? AcalaHelper);30393040 this.balance = new SubstrateBalanceGroup(this);3041 this.assetRegistry = new AcalaAssetRegistryGroup(this);3042 this.xTokens = new XTokensGroup(this);3043 this.tokens = new TokensGroup(this);3044 }30453046 getSudo<T extends AcalaHelper>() {3047 // eslint-disable-next-line @typescript-eslint/naming-convention3048 const SudoHelperType = SudoHelper(this.helperBase);3049 return this.clone(SudoHelperType) as T;3050 }3051}30523053// eslint-disable-next-line @typescript-eslint/naming-convention3054function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {3055 return class extends Base {3056 scheduleFn: 'schedule' | 'scheduleAfter';3057 blocksNum: number;3058 options: ISchedulerOptions;30593060 constructor(...args: any[]) {3061 const logger = args[0] as ILogger;3062 const options = args[1] as {3063 scheduleFn: 'schedule' | 'scheduleAfter',3064 blocksNum: number,3065 options: ISchedulerOptions3066 };30673068 super(logger);30693070 this.scheduleFn = options.scheduleFn;3071 this.blocksNum = options.blocksNum;3072 this.options = options.options;3073 }30743075 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {3076 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);30773078 const mandatorySchedArgs = [3079 this.blocksNum,3080 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,3081 this.options.priority ?? null,3082 scheduledTx,3083 ];30843085 let schedArgs;3086 let scheduleFn;30873088 if (this.options.scheduledId) {3089 schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];30903091 if (this.scheduleFn == 'schedule') {3092 scheduleFn = 'scheduleNamed';3093 } else if (this.scheduleFn == 'scheduleAfter') {3094 scheduleFn = 'scheduleNamedAfter';3095 }3096 } else {3097 schedArgs = mandatorySchedArgs;3098 scheduleFn = this.scheduleFn;3099 }31003101 const extrinsic = 'api.tx.scheduler.' + scheduleFn;31023103 return super.executeExtrinsic(3104 sender,3105 extrinsic,3106 schedArgs,3107 expectSuccess,3108 );3109 }3110 };3111}31123113// eslint-disable-next-line @typescript-eslint/naming-convention3114function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {3115 return class extends Base {3116 constructor(...args: any[]) {3117 super(...args);3118 }31193120 executeExtrinsic (3121 sender: IKeyringPair,3122 extrinsic: string,3123 params: any[],3124 expectSuccess?: boolean,3125 ): Promise<ITransactionResult> {3126 const call = this.constructApiCall(extrinsic, params);3127 return super.executeExtrinsic(3128 sender,3129 'api.tx.sudo.sudo',3130 [call],3131 expectSuccess,3132 );3133 }3134 };3135}31363137export class UniqueBaseCollection {3138 helper: UniqueHelper;3139 collectionId: number;31403141 constructor(collectionId: number, uniqueHelper: UniqueHelper) {3142 this.collectionId = collectionId;3143 this.helper = uniqueHelper;3144 }31453146 async getData() {3147 return await this.helper.collection.getData(this.collectionId);3148 }31493150 async getLastTokenId() {3151 return await this.helper.collection.getLastTokenId(this.collectionId);3152 }31533154 async doesTokenExist(tokenId: number) {3155 return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);3156 }31573158 async getAdmins() {3159 return await this.helper.collection.getAdmins(this.collectionId);3160 }31613162 async getAllowList() {3163 return await this.helper.collection.getAllowList(this.collectionId);3164 }31653166 async getEffectiveLimits() {3167 return await this.helper.collection.getEffectiveLimits(this.collectionId);3168 }31693170 async getProperties(propertyKeys?: string[] | null) {3171 return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3172 }31733174 async getPropertiesConsumedSpace() {3175 return await this.helper.collection.getPropertiesConsumedSpace(this.collectionId);3176 }31773178 async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3179 return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3180 }31813182 async getOptions() {3183 return await this.helper.collection.getCollectionOptions(this.collectionId);3184 }31853186 async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3187 return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3188 }31893190 async confirmSponsorship(signer: TSigner) {3191 return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3192 }31933194 async removeSponsor(signer: TSigner) {3195 return await this.helper.collection.removeSponsor(signer, this.collectionId);3196 }31973198 async setLimits(signer: TSigner, limits: ICollectionLimits) {3199 return await this.helper.collection.setLimits(signer, this.collectionId, limits);3200 }32013202 async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3203 return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3204 }32053206 async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3207 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3208 }32093210 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3211 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3212 }32133214 async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3215 return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3216 }32173218 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3219 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3220 }32213222 async setProperties(signer: TSigner, properties: IProperty[]) {3223 return await this.helper.collection.setProperties(signer, this.collectionId, properties);3224 }32253226 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3227 return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3228 }32293230 async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3231 return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3232 }32333234 async enableNesting(signer: TSigner, permissions: INestingPermissions) {3235 return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3236 }32373238 async disableNesting(signer: TSigner) {3239 return await this.helper.collection.disableNesting(signer, this.collectionId);3240 }32413242 async burn(signer: TSigner) {3243 return await this.helper.collection.burn(signer, this.collectionId);3244 }32453246 scheduleAt<T extends UniqueHelper>(3247 executionBlockNumber: number,3248 options: ISchedulerOptions = {},3249 ) {3250 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3251 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3252 }32533254 scheduleAfter<T extends UniqueHelper>(3255 blocksBeforeExecution: number,3256 options: ISchedulerOptions = {},3257 ) {3258 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3259 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3260 }32613262 getSudo<T extends UniqueHelper>() {3263 return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());3264 }3265}326632673268export class UniqueNFTCollection extends UniqueBaseCollection {3269 getTokenObject(tokenId: number) {3270 return new UniqueNFToken(tokenId, this);3271 }32723273 async getTokensByAddress(addressObj: ICrossAccountId) {3274 return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3275 }32763277 async getToken(tokenId: number, blockHashAt?: string) {3278 return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3279 }32803281 async getTokenOwner(tokenId: number, blockHashAt?: string) {3282 return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3283 }32843285 async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3286 return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3287 }32883289 async getTokenChildren(tokenId: number, blockHashAt?: string) {3290 return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3291 }32923293 async getPropertyPermissions(propertyKeys: string[] | null = null) {3294 return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3295 }32963297 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3298 return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3299 }33003301 async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3302 const api = this.helper.getApi();3303 const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON();33043305 return (props! as any).consumedSpace;3306 }33073308 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3309 return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3310 }33113312 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3313 return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3314 }33153316 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3317 return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3318 }33193320 async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3321 return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3322 }33233324 async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3325 return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3326 }33273328 async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {3329 return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3330 }33313332 async burnToken(signer: TSigner, tokenId: number) {3333 return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3334 }33353336 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3337 return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3338 }33393340 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3341 return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3342 }33433344 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3345 return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3346 }33473348 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3349 return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3350 }33513352 async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3353 return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3354 }33553356 async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3357 return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3358 }33593360 scheduleAt<T extends UniqueHelper>(3361 executionBlockNumber: number,3362 options: ISchedulerOptions = {},3363 ) {3364 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3365 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3366 }33673368 scheduleAfter<T extends UniqueHelper>(3369 blocksBeforeExecution: number,3370 options: ISchedulerOptions = {},3371 ) {3372 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3373 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3374 }33753376 getSudo<T extends UniqueHelper>() {3377 return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());3378 }3379}338033813382export class UniqueRFTCollection extends UniqueBaseCollection {3383 getTokenObject(tokenId: number) {3384 return new UniqueRFToken(tokenId, this);3385 }33863387 async getToken(tokenId: number, blockHashAt?: string) {3388 return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3389 }33903391 async getTokensByAddress(addressObj: ICrossAccountId) {3392 return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3393 }33943395 async getTop10TokenOwners(tokenId: number) {3396 return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3397 }33983399 async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3400 return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3401 }34023403 async getTokenTotalPieces(tokenId: number) {3404 return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3405 }34063407 async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3408 return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3409 }34103411 async getPropertyPermissions(propertyKeys: string[] | null = null) {3412 return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3413 }34143415 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3416 return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3417 }34183419 async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3420 const api = this.helper.getApi();3421 const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON();34223423 return (props! as any).consumedSpace;3424 }34253426 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {3427 return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3428 }34293430 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3431 return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3432 }34333434 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {3435 return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3436 }34373438 async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3439 return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3440 }34413442 async mintToken(signer: TSigner, pieces=1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3443 return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3444 }34453446 async mintMultipleTokens(signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) {3447 return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3448 }34493450 async burnToken(signer: TSigner, tokenId: number, amount=1n) {3451 return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3452 }34533454 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n) {3455 return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3456 }34573458 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3459 return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3460 }34613462 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3463 return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3464 }34653466 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3467 return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3468 }34693470 scheduleAt<T extends UniqueHelper>(3471 executionBlockNumber: number,3472 options: ISchedulerOptions = {},3473 ) {3474 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3475 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3476 }34773478 scheduleAfter<T extends UniqueHelper>(3479 blocksBeforeExecution: number,3480 options: ISchedulerOptions = {},3481 ) {3482 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3483 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3484 }34853486 getSudo<T extends UniqueHelper>() {3487 return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());3488 }3489}349034913492export class UniqueFTCollection extends UniqueBaseCollection {3493 async getBalance(addressObj: ICrossAccountId) {3494 return await this.helper.ft.getBalance(this.collectionId, addressObj);3495 }34963497 async getTotalPieces() {3498 return await this.helper.ft.getTotalPieces(this.collectionId);3499 }35003501 async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3502 return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3503 }35043505 async getTop10Owners() {3506 return await this.helper.ft.getTop10Owners(this.collectionId);3507 }35083509 async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {3510 return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3511 }35123513 async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {3514 return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3515 }35163517 async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3518 return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3519 }35203521 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3522 return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3523 }35243525 async burnTokens(signer: TSigner, amount=1n) {3526 return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3527 }35283529 async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3530 return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3531 }35323533 async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3534 return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3535 }35363537 scheduleAt<T extends UniqueHelper>(3538 executionBlockNumber: number,3539 options: ISchedulerOptions = {},3540 ) {3541 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3542 return new UniqueFTCollection(this.collectionId, scheduledHelper);3543 }35443545 scheduleAfter<T extends UniqueHelper>(3546 blocksBeforeExecution: number,3547 options: ISchedulerOptions = {},3548 ) {3549 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3550 return new UniqueFTCollection(this.collectionId, scheduledHelper);3551 }35523553 getSudo<T extends UniqueHelper>() {3554 return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());3555 }3556}355735583559export class UniqueBaseToken {3560 collection: UniqueNFTCollection | UniqueRFTCollection;3561 collectionId: number;3562 tokenId: number;35633564 constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3565 this.collection = collection;3566 this.collectionId = collection.collectionId;3567 this.tokenId = tokenId;3568 }35693570 async getNextSponsored(addressObj: ICrossAccountId) {3571 return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3572 }35733574 async getProperties(propertyKeys?: string[] | null) {3575 return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3576 }35773578 async getTokenPropertiesConsumedSpace() {3579 return await this.collection.getTokenPropertiesConsumedSpace(this.tokenId);3580 }35813582 async setProperties(signer: TSigner, properties: IProperty[]) {3583 return await this.collection.setTokenProperties(signer, this.tokenId, properties);3584 }35853586 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3587 return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3588 }35893590 async doesExist() {3591 return await this.collection.doesTokenExist(this.tokenId);3592 }35933594 nestingAccount() {3595 return this.collection.helper.util.getTokenAccount(this);3596 }35973598 scheduleAt<T extends UniqueHelper>(3599 executionBlockNumber: number,3600 options: ISchedulerOptions = {},3601 ) {3602 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3603 return new UniqueBaseToken(this.tokenId, scheduledCollection);3604 }36053606 scheduleAfter<T extends UniqueHelper>(3607 blocksBeforeExecution: number,3608 options: ISchedulerOptions = {},3609 ) {3610 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3611 return new UniqueBaseToken(this.tokenId, scheduledCollection);3612 }36133614 getSudo<T extends UniqueHelper>() {3615 return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());3616 }3617}361836193620export class UniqueNFToken extends UniqueBaseToken {3621 collection: UniqueNFTCollection;36223623 constructor(tokenId: number, collection: UniqueNFTCollection) {3624 super(tokenId, collection);3625 this.collection = collection;3626 }36273628 async getData(blockHashAt?: string) {3629 return await this.collection.getToken(this.tokenId, blockHashAt);3630 }36313632 async getOwner(blockHashAt?: string) {3633 return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3634 }36353636 async getTopmostOwner(blockHashAt?: string) {3637 return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3638 }36393640 async getChildren(blockHashAt?: string) {3641 return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3642 }36433644 async nest(signer: TSigner, toTokenObj: IToken) {3645 return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3646 }36473648 async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3649 return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3650 }36513652 async transfer(signer: TSigner, addressObj: ICrossAccountId) {3653 return await this.collection.transferToken(signer, this.tokenId, addressObj);3654 }36553656 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3657 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3658 }36593660 async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3661 return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3662 }36633664 async isApproved(toAddressObj: ICrossAccountId) {3665 return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3666 }36673668 async burn(signer: TSigner) {3669 return await this.collection.burnToken(signer, this.tokenId);3670 }36713672 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3673 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3674 }36753676 scheduleAt<T extends UniqueHelper>(3677 executionBlockNumber: number,3678 options: ISchedulerOptions = {},3679 ) {3680 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3681 return new UniqueNFToken(this.tokenId, scheduledCollection);3682 }36833684 scheduleAfter<T extends UniqueHelper>(3685 blocksBeforeExecution: number,3686 options: ISchedulerOptions = {},3687 ) {3688 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3689 return new UniqueNFToken(this.tokenId, scheduledCollection);3690 }36913692 getSudo<T extends UniqueHelper>() {3693 return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());3694 }3695}36963697export class UniqueRFToken extends UniqueBaseToken {3698 collection: UniqueRFTCollection;36993700 constructor(tokenId: number, collection: UniqueRFTCollection) {3701 super(tokenId, collection);3702 this.collection = collection;3703 }37043705 async getData(blockHashAt?: string) {3706 return await this.collection.getToken(this.tokenId, blockHashAt);3707 }37083709 async getTop10Owners() {3710 return await this.collection.getTop10TokenOwners(this.tokenId);3711 }37123713 async getBalance(addressObj: ICrossAccountId) {3714 return await this.collection.getTokenBalance(this.tokenId, addressObj);3715 }37163717 async getTotalPieces() {3718 return await this.collection.getTokenTotalPieces(this.tokenId);3719 }37203721 async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3722 return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3723 }37243725 async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {3726 return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3727 }37283729 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3730 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3731 }37323733 async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3734 return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3735 }37363737 async repartition(signer: TSigner, amount: bigint) {3738 return await this.collection.repartitionToken(signer, this.tokenId, amount);3739 }37403741 async burn(signer: TSigner, amount=1n) {3742 return await this.collection.burnToken(signer, this.tokenId, amount);3743 }37443745 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3746 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3747 }37483749 scheduleAt<T extends UniqueHelper>(3750 executionBlockNumber: number,3751 options: ISchedulerOptions = {},3752 ) {3753 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3754 return new UniqueRFToken(this.tokenId, scheduledCollection);3755 }37563757 scheduleAfter<T extends UniqueHelper>(3758 blocksBeforeExecution: number,3759 options: ISchedulerOptions = {},3760 ) {3761 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3762 return new UniqueRFToken(this.tokenId, scheduledCollection);3763 }37643765 getSudo<T extends UniqueHelper>() {3766 return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());3767 }3768}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';12import {hexToU8a} from '@polkadot/util/hex';13import {u8aConcat} from '@polkadot/util/u8a';14import {15 IApiListeners,16 IBlock,17 IEvent,18 IChainProperties,19 ICollectionCreationOptions,20 ICollectionLimits,21 ICollectionPermissions,22 ICrossAccountId,23 ICrossAccountIdLower,24 ILogger,25 INestingPermissions,26 IProperty,27 IStakingInfo,28 ISchedulerOptions,29 ISubstrateBalance,30 IToken,31 ITokenPropertyPermission,32 ITransactionResult,33 IUniqueHelperLog,34 TApiAllowedListeners,35 TEthereumAccount,36 TSigner,37 TSubstrateAccount,38 TNetworks,39 IForeignAssetMetadata,40 AcalaAssetMetadata,41 MoonbeamAssetInfo,42 DemocracyStandardAccountVote,43 IEthCrossAccountId,44} from './types';45import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';46import type {Vec} from '@polkadot/types-codec';47import {FrameSystemEventRecord} from '@polkadot/types/lookup';4849export class CrossAccountId implements ICrossAccountId {50 Substrate?: TSubstrateAccount;51 Ethereum?: TEthereumAccount;5253 constructor(account: ICrossAccountId) {54 if (account.Substrate) this.Substrate = account.Substrate;55 if (account.Ethereum) this.Ethereum = account.Ethereum;56 }5758 static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {59 switch (domain) {60 case 'Substrate': return new CrossAccountId({Substrate: account.address});61 case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();62 }63 }6465 static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {66 return new CrossAccountId({Substrate: address.substrate, Ethereum: address.ethereum});67 }6869 static normalizeSubstrateAddress(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {70 return encodeAddress(decodeAddress(address), ss58Format);71 }7273 static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId {74 return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)});75 }7677 withNormalizedSubstrate(ss58Format = 42): CrossAccountId {78 if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format);79 return this;80 }8182 static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {83 return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));84 }8586 toEthereum(): CrossAccountId {87 if (this.Substrate) return new CrossAccountId({Ethereum: CrossAccountId.translateSubToEth(this.Substrate)});88 return this;89 }9091 static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {92 return evmToAddress(address, ss58Format);93 }9495 toSubstrate(ss58Format?: number): CrossAccountId {96 if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)});97 return this;98 }99100 toLowerCase(): CrossAccountId {101 if (this.Substrate) this.Substrate = this.Substrate.toLowerCase();102 if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase();103 return this;104 }105}106107const nesting = {108 toChecksumAddress(address: string): string {109 if (typeof address === 'undefined') return '';110111 if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);112113 address = address.toLowerCase().replace(/^0x/i,'');114 const addressHash = keccakAsHex(address).replace(/^0x/i,'');115 const checksumAddress = ['0x'];116117 for (let i = 0; i < address.length; i++) {118 // If ith character is 8 to f then make it uppercase119 if (parseInt(addressHash[i], 16) > 7) {120 checksumAddress.push(address[i].toUpperCase());121 } else {122 checksumAddress.push(address[i]);123 }124 }125 return checksumAddress.join('');126 },127 tokenIdToAddress(collectionId: number, tokenId: number) {128 return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8,'0')}${tokenId.toString(16).padStart(8,'0')}`);129 },130};131132class UniqueUtil {133 static transactionStatus = {134 NOT_READY: 'NotReady',135 FAIL: 'Fail',136 SUCCESS: 'Success',137 };138139 static chainLogType = {140 EXTRINSIC: 'extrinsic',141 RPC: 'rpc',142 };143144 static getTokenAccount(token: IToken): CrossAccountId {145 return new CrossAccountId({Ethereum: this.getTokenAddress(token)});146 }147148 static getTokenAddress(token: IToken): string {149 return nesting.tokenIdToAddress(token.collectionId, token.tokenId);150 }151152 static getDefaultLogger(): ILogger {153 return {154 log(msg: any, level = 'INFO') {155 console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));156 },157 level: {158 ERROR: 'ERROR',159 WARNING: 'WARNING',160 INFO: 'INFO',161 },162 };163 }164165 static vec2str(arr: string[] | number[]) {166 return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');167 }168169 static str2vec(string: string) {170 if (typeof string !== 'string') return string;171 return Array.from(string).map(x => x.charCodeAt(0));172 }173174 static fromSeed(seed: string, ss58Format = 42) {175 const keyring = new Keyring({type: 'sr25519', ss58Format});176 return keyring.addFromUri(seed);177 }178179 static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {180 if (creationResult.status !== this.transactionStatus.SUCCESS) {181 throw Error('Unable to create collection!');182 }183184 let collectionId = null;185 creationResult.result.events.forEach(({event: {data, method, section}}) => {186 if ((section === 'common') && (method === 'CollectionCreated')) {187 collectionId = parseInt(data[0].toString(), 10);188 }189 });190191 if (collectionId === null) {192 throw Error('No CollectionCreated event was found!');193 }194195 return collectionId;196 }197198 static extractTokensFromCreationResult(creationResult: ITransactionResult): {199 success: boolean,200 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],201 } {202 if (creationResult.status !== this.transactionStatus.SUCCESS) {203 throw Error('Unable to create tokens!');204 }205 let success = false;206 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];207 creationResult.result.events.forEach(({event: {data, method, section}}) => {208 if (method === 'ExtrinsicSuccess') {209 success = true;210 } else if ((section === 'common') && (method === 'ItemCreated')) {211 tokens.push({212 collectionId: parseInt(data[0].toString(), 10),213 tokenId: parseInt(data[1].toString(), 10),214 owner: data[2].toHuman(),215 amount: data[3].toBigInt(),216 });217 }218 });219 return {success, tokens};220 }221222 static extractTokensFromBurnResult(burnResult: ITransactionResult): {223 success: boolean,224 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],225 } {226 if (burnResult.status !== this.transactionStatus.SUCCESS) {227 throw Error('Unable to burn tokens!');228 }229 let success = false;230 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];231 burnResult.result.events.forEach(({event: {data, method, section}}) => {232 if (method === 'ExtrinsicSuccess') {233 success = true;234 } else if ((section === 'common') && (method === 'ItemDestroyed')) {235 tokens.push({236 collectionId: parseInt(data[0].toString(), 10),237 tokenId: parseInt(data[1].toString(), 10),238 owner: data[2].toHuman(),239 amount: data[3].toBigInt(),240 });241 }242 });243 return {success, tokens};244 }245246 static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {247 let eventId = null;248 events.forEach(({event: {data, method, section}}) => {249 if ((section === expectedSection) && (method === expectedMethod)) {250 eventId = parseInt(data[0].toString(), 10);251 }252 });253254 if (eventId === null) {255 throw Error(`No ${expectedMethod} event was found!`);256 }257 return eventId === collectionId;258 }259260 static isTokenTransferSuccess(events: {event: IEvent}[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {261 const normalizeAddress = (address: string | ICrossAccountId) => {262 if(typeof address === 'string') return address;263 const obj = {} as any;264 Object.keys(address).forEach(k => {265 obj[k.toLocaleLowerCase()] = address[k as 'Substrate' | 'Ethereum'];266 });267 if(obj.substrate) return CrossAccountId.withNormalizedSubstrate(obj.substrate);268 if(obj.ethereum) return CrossAccountId.fromLowerCaseKeys(obj).toLowerCase();269 return address;270 };271 let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;272 events.forEach(({event: {data, method, section}}) => {273 if ((section === 'common') && (method === 'Transfer')) {274 const hData = (data as any).toJSON();275 transfer = {276 collectionId: hData[0],277 tokenId: hData[1],278 from: normalizeAddress(hData[2]),279 to: normalizeAddress(hData[3]),280 amount: BigInt(hData[4]),281 };282 }283 });284 let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;285 isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);286 isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);287 isSuccess = isSuccess && amount === transfer.amount;288 return isSuccess;289 }290291 static bigIntToDecimals(number: bigint, decimals = 18) {292 const numberStr = number.toString();293 const dotPos = numberStr.length - decimals;294295 if (dotPos <= 0) {296 return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;297 } else {298 const intPart = numberStr.substring(0, dotPos);299 const fractPart = numberStr.substring(dotPos);300 return intPart + '.' + fractPart;301 }302 }303}304305class UniqueEventHelper {306 private static extractIndex(index: any): [number, number] | string {307 if(index.toRawType() === '[u8;2]') return [index[0], index[1]];308 return index.toJSON();309 }310311 private static extractSub(data: any, subTypes: any): {[key: string]: any} {312 let obj: any = {};313 let index = 0;314315 if (data.entries) {316 for(const [key, value] of data.entries()) {317 obj[key] = this.extractData(value, subTypes[index]);318 index++;319 }320 } else obj = data.toJSON();321322 return obj;323 }324325 private static toHuman(data: any) {326 return data && data.toHuman ? data.toHuman() : `${data}`;327 }328329 private static extractData(data: any, type: any): any {330 if(!type) return this.toHuman(data);331 if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();332 if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();333 if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);334 return this.toHuman(data);335 }336337 public static extractEvents(events: {event: any, phase: any}[]): IEvent[] {338 const parsedEvents: IEvent[] = [];339340 events.forEach((record) => {341 const {event, phase} = record;342 const types = event.typeDef;343344 const eventData: IEvent = {345 section: event.section.toString(),346 method: event.method.toString(),347 index: this.extractIndex(event.index),348 data: [],349 phase: phase.toJSON(),350 };351352 event.data.forEach((val: any, index: number) => {353 eventData.data.push(this.extractData(val, types[index]));354 });355356 parsedEvents.push(eventData);357 });358359 return parsedEvents;360 }361}362363export class ChainHelperBase {364 helperBase: any;365366 transactionStatus = UniqueUtil.transactionStatus;367 chainLogType = UniqueUtil.chainLogType;368 util: typeof UniqueUtil;369 eventHelper: typeof UniqueEventHelper;370 logger: ILogger;371 api: ApiPromise | null;372 forcedNetwork: TNetworks | null;373 network: TNetworks | null;374 wsEndpoint: string | null;375 chainLog: IUniqueHelperLog[];376 children: ChainHelperBase[];377 address: AddressGroup;378 chain: ChainGroup;379380 constructor(logger?: ILogger, helperBase?: any) {381 this.helperBase = helperBase;382383 this.util = UniqueUtil;384 this.eventHelper = UniqueEventHelper;385 if (typeof logger == 'undefined') logger = this.util.getDefaultLogger();386 this.logger = logger;387 this.api = null;388 this.forcedNetwork = null;389 this.network = null;390 this.wsEndpoint = null;391 this.chainLog = [];392 this.children = [];393 this.address = new AddressGroup(this);394 this.chain = new ChainGroup(this);395 }396397 clone(helperCls: ChainHelperBaseConstructor, options: {[key: string]: any} = {}) {398 Object.setPrototypeOf(helperCls.prototype, this);399 const newHelper = new helperCls(this.logger, options);400401 newHelper.api = this.api;402 newHelper.network = this.network;403 newHelper.forceNetwork = this.forceNetwork;404405 this.children.push(newHelper);406407 return newHelper;408 }409410 getEndpoint(): string {411 if (this.wsEndpoint === null) throw Error('No connection was established');412 return this.wsEndpoint;413 }414415 getApi(): ApiPromise {416 if(this.api === null) throw Error('API not initialized');417 return this.api;418 }419420 async subscribeEvents(expectedEvents: {section: string, names: string[]}[]) {421 const collectedEvents: IEvent[] = [];422 const unsubscribe = await this.getApi().query.system.events((events: Vec<FrameSystemEventRecord>) => {423 const ievents = this.eventHelper.extractEvents(events);424 ievents.forEach((event) => {425 expectedEvents.forEach((e => {426 if (event.section === e.section && e.names.includes(event.method)) {427 collectedEvents.push(event);428 }429 }));430 });431 });432 return {unsubscribe: unsubscribe as any, collectedEvents};433 }434435 clearChainLog(): void {436 this.chainLog = [];437 }438439 forceNetwork(value: TNetworks): void {440 this.forcedNetwork = value;441 }442443 async connect(wsEndpoint: string, listeners?: IApiListeners) {444 if (this.api !== null) throw Error('Already connected');445 const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);446 this.wsEndpoint = wsEndpoint;447 this.api = api;448 this.network = network;449 }450451 async disconnect() {452 for (const child of this.children) {453 child.clearApi();454 }455456 if (this.api === null) return;457 await this.api.disconnect();458 this.clearApi();459 }460461 clearApi() {462 this.api = null;463 this.network = null;464 }465466 static async detectNetwork(api: ApiPromise): Promise<TNetworks> {467 const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;468 const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];469470 if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;471472 if(['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;473 return 'opal';474 }475476 static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {477 const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});478 await api.isReady;479480 const network = await this.detectNetwork(api);481482 await api.disconnect();483484 return network;485 }486487 static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{488 api: ApiPromise;489 network: TNetworks;490 }> {491 if(typeof network === 'undefined' || network === null) network = 'opal';492 const supportedRPC = {493 opal: {494 unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,495 },496 quartz: {497 unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,498 },499 unique: {500 unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,501 },502 rococo: {},503 westend: {},504 moonbeam: {},505 moonriver: {},506 acala: {},507 karura: {},508 westmint: {},509 };510 if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);511 const rpc = supportedRPC[network];512513 // TODO: investigate how to replace rpc in runtime514 // api._rpcCore.addUserInterfaces(rpc);515516 const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});517518 await api.isReadyOrError;519520 if (typeof listeners === 'undefined') listeners = {};521 for (const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {522 if (!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;523 api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);524 }525526 return {api, network};527 }528529 getTransactionStatus(data: {events: {event: IEvent}[], status: any}) {530 const {events, status} = data;531 if (status.isReady) {532 return this.transactionStatus.NOT_READY;533 }534 if (status.isBroadcast) {535 return this.transactionStatus.NOT_READY;536 }537 if (status.isInBlock || status.isFinalized) {538 const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');539 if (errors.length > 0) {540 return this.transactionStatus.FAIL;541 }542 if (events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {543 return this.transactionStatus.SUCCESS;544 }545 }546547 return this.transactionStatus.FAIL;548 }549550 signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {551 const sign = (callback: any) => {552 if(options !== null) return transaction.signAndSend(sender, options, callback);553 return transaction.signAndSend(sender, callback);554 };555 // eslint-disable-next-line no-async-promise-executor556 return new Promise(async (resolve, reject) => {557 try {558 const unsub = await sign((result: any) => {559 const status = this.getTransactionStatus(result);560561 if (status === this.transactionStatus.SUCCESS) {562 this.logger.log(`${label} successful`);563 unsub();564 resolve({result, status});565 } else if (status === this.transactionStatus.FAIL) {566 let moduleError = null;567568 if (result.hasOwnProperty('dispatchError')) {569 const dispatchError = result['dispatchError'];570571 if (dispatchError) {572 if (dispatchError.isModule) {573 const modErr = dispatchError.asModule;574 const errorMeta = dispatchError.registry.findMetaError(modErr);575576 moduleError = `${errorMeta.section}.${errorMeta.name}`;577 } else {578 moduleError = dispatchError.toHuman();579 }580 } else {581 this.logger.log(result, this.logger.level.ERROR);582 }583 }584585 this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);586 unsub();587 reject({status, moduleError, result});588 }589 });590 } catch (e) {591 this.logger.log(e, this.logger.level.ERROR);592 reject(e);593 }594 });595 }596597 async signTransactionWithoutSending(signer: TSigner, tx: any) {598 const api = this.getApi();599 const signingInfo = await api.derive.tx.signingInfo(signer.address);600601 tx.sign(signer, {602 blockHash: api.genesisHash,603 genesisHash: api.genesisHash,604 runtimeVersion: api.runtimeVersion,605 nonce: signingInfo.nonce,606 });607608 return tx.toHex();609 }610611 async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {612 const api = this.getApi();613 const signingInfo = await api.derive.tx.signingInfo(signer.address);614615 // We need to sign the tx because616 // unsigned transactions does not have an inclusion fee617 tx.sign(signer, {618 blockHash: api.genesisHash,619 genesisHash: api.genesisHash,620 runtimeVersion: api.runtimeVersion,621 nonce: signingInfo.nonce,622 });623624 if (len === null) {625 return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;626 } else {627 return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;628 }629 }630631 constructApiCall(apiCall: string, params: any[]) {632 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);633 let call = this.getApi() as any;634 for(const part of apiCall.slice(4).split('.')) {635 call = call[part];636 }637 return call(...params);638 }639640 async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {641 if(this.api === null) throw Error('API not initialized');642 if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);643644 const startTime = (new Date()).getTime();645 let result: ITransactionResult;646 let events: IEvent[] = [];647 try {648 result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;649 events = this.eventHelper.extractEvents(result.result.events);650 }651 catch(e) {652 if(!(e as object).hasOwnProperty('status')) throw e;653 result = e as ITransactionResult;654 }655656 const endTime = (new Date()).getTime();657658 const log = {659 executedAt: endTime,660 executionTime: endTime - startTime,661 type: this.chainLogType.EXTRINSIC,662 status: result.status,663 call: extrinsic,664 signer: this.getSignerAddress(sender),665 params,666 } as IUniqueHelperLog;667668 if(result.status !== this.transactionStatus.SUCCESS) {669 if (result.moduleError) log.moduleError = result.moduleError;670 else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;671 }672 if(events.length > 0) log.events = events;673674 this.chainLog.push(log);675676 if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {677 if (result.moduleError) throw Error(`${result.moduleError}`);678 else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));679 }680 return result;681 }682683 async callRpc(rpc: string, params?: any[]) {684 if(typeof params === 'undefined') params = [];685 if(this.api === null) throw Error('API not initialized');686 if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);687688 const startTime = (new Date()).getTime();689 let result;690 let error = null;691 const log = {692 type: this.chainLogType.RPC,693 call: rpc,694 params,695 } as IUniqueHelperLog;696697 try {698 result = await this.constructApiCall(rpc, params);699 }700 catch(e) {701 error = e;702 }703704 const endTime = (new Date()).getTime();705706 log.executedAt = endTime;707 log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';708 log.executionTime = endTime - startTime;709710 this.chainLog.push(log);711712 if(error !== null) throw error;713714 return result;715 }716717 getSignerAddress(signer: IKeyringPair | string): string {718 if(typeof signer === 'string') return signer;719 return signer.address;720 }721722 fetchAllPalletNames(): string[] {723 if(this.api === null) throw Error('API not initialized');724 return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());725 }726727 fetchMissingPalletNames(requiredPallets: string[]): string[] {728 const palletNames = this.fetchAllPalletNames();729 return requiredPallets.filter(p => !palletNames.includes(p));730 }731}732733734class HelperGroup<T extends ChainHelperBase> {735 helper: T;736737 constructor(uniqueHelper: T) {738 this.helper = uniqueHelper;739 }740}741742743class CollectionGroup extends HelperGroup<UniqueHelper> {744 /**745 * Get number of blocks when sponsored transaction is available.746 *747 * @param collectionId ID of collection748 * @param tokenId ID of token749 * @param addressObj address for which the sponsorship is checked750 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});751 * @returns number of blocks or null if sponsorship hasn't been set752 */753 async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {754 return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();755 }756757 /**758 * Get the number of created collections.759 *760 * @returns number of created collections761 */762 async getTotalCount(): Promise<number> {763 return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();764 }765766 /**767 * Get information about the collection with additional data,768 * including the number of tokens it contains, its administrators,769 * the normalized address of the collection's owner, and decoded name and description.770 *771 * @param collectionId ID of collection772 * @example await getData(2)773 * @returns collection information object774 */775 async getData(collectionId: number): Promise<{776 id: number;777 name: string;778 description: string;779 tokensCount: number;780 admins: CrossAccountId[];781 normalizedOwner: TSubstrateAccount;782 raw: any783 } | null> {784 const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);785 const humanCollection = collection.toHuman(), collectionData = {786 id: collectionId, name: null, description: null, tokensCount: 0, admins: [],787 raw: humanCollection,788 } as any, jsonCollection = collection.toJSON();789 if (humanCollection === null) return null;790 collectionData.raw.limits = jsonCollection.limits;791 collectionData.raw.permissions = jsonCollection.permissions;792 collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);793 for (const key of ['name', 'description']) {794 collectionData[key] = this.helper.util.vec2str(humanCollection[key]);795 }796797 collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))798 ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)799 : 0;800 collectionData.admins = await this.getAdmins(collectionId);801802 return collectionData;803 }804805 /**806 * Get the addresses of the collection's administrators, optionally normalized.807 *808 * @param collectionId ID of collection809 * @param normalize whether to normalize the addresses to the default ss58 format810 * @example await getAdmins(1)811 * @returns array of administrators812 */813 async getAdmins(collectionId: number, normalize = false): Promise<CrossAccountId[]> {814 const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();815816 return normalize817 ? admins.map((address: CrossAccountId) => address.withNormalizedSubstrate())818 : admins;819 }820821 /**822 * Get the addresses added to the collection allow-list, optionally normalized.823 * @param collectionId ID of collection824 * @param normalize whether to normalize the addresses to the default ss58 format825 * @example await getAllowList(1)826 * @returns array of allow-listed addresses827 */828 async getAllowList(collectionId: number, normalize = false): Promise<CrossAccountId[]> {829 const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();830 return normalize831 ? allowListed.map((address: CrossAccountId) => address.withNormalizedSubstrate())832 : allowListed;833 }834835 /**836 * Get the effective limits of the collection instead of null for default values837 *838 * @param collectionId ID of collection839 * @example await getEffectiveLimits(2)840 * @returns object of collection limits841 */842 async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {843 return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();844 }845846 /**847 * Burns the collection if the signer has sufficient permissions and collection is empty.848 *849 * @param signer keyring of signer850 * @param collectionId ID of collection851 * @example await helper.collection.burn(aliceKeyring, 3);852 * @returns ```true``` if extrinsic success, otherwise ```false```853 */854 async burn(signer: TSigner, collectionId: number): Promise<boolean> {855 const result = await this.helper.executeExtrinsic(856 signer,857 'api.tx.unique.destroyCollection', [collectionId],858 true,859 );860861 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');862 }863864 /**865 * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.866 *867 * @param signer keyring of signer868 * @param collectionId ID of collection869 * @param sponsorAddress Sponsor substrate address870 * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")871 * @returns ```true``` if extrinsic success, otherwise ```false```872 */873 async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {874 const result = await this.helper.executeExtrinsic(875 signer,876 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],877 true,878 );879880 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');881 }882883 /**884 * Confirms consent to sponsor the collection on behalf of the signer.885 *886 * @param signer keyring of signer887 * @param collectionId ID of collection888 * @example confirmSponsorship(aliceKeyring, 10)889 * @returns ```true``` if extrinsic success, otherwise ```false```890 */891 async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {892 const result = await this.helper.executeExtrinsic(893 signer,894 'api.tx.unique.confirmSponsorship', [collectionId],895 true,896 );897898 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');899 }900901 /**902 * Removes the sponsor of a collection, regardless if it consented or not.903 *904 * @param signer keyring of signer905 * @param collectionId ID of collection906 * @example removeSponsor(aliceKeyring, 10)907 * @returns ```true``` if extrinsic success, otherwise ```false```908 */909 async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {910 const result = await this.helper.executeExtrinsic(911 signer,912 'api.tx.unique.removeCollectionSponsor', [collectionId],913 true,914 );915916 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');917 }918919 /**920 * Sets the limits of the collection. At least one limit must be specified for a correct call.921 *922 * @param signer keyring of signer923 * @param collectionId ID of collection924 * @param limits collection limits object925 * @example926 * await setLimits(927 * aliceKeyring,928 * 10,929 * {930 * sponsorTransferTimeout: 0,931 * ownerCanDestroy: false932 * }933 * )934 * @returns ```true``` if extrinsic success, otherwise ```false```935 */936 async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {937 const result = await this.helper.executeExtrinsic(938 signer,939 'api.tx.unique.setCollectionLimits', [collectionId, limits],940 true,941 );942943 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');944 }945946 /**947 * Changes the owner of the collection to the new Substrate address.948 *949 * @param signer keyring of signer950 * @param collectionId ID of collection951 * @param ownerAddress substrate address of new owner952 * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")953 * @returns ```true``` if extrinsic success, otherwise ```false```954 */955 async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {956 const result = await this.helper.executeExtrinsic(957 signer,958 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],959 true,960 );961962 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');963 }964965 /**966 * Adds a collection administrator.967 *968 * @param signer keyring of signer969 * @param collectionId ID of collection970 * @param adminAddressObj Administrator address (substrate or ethereum)971 * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})972 * @returns ```true``` if extrinsic success, otherwise ```false```973 */974 async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {975 const result = await this.helper.executeExtrinsic(976 signer,977 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],978 true,979 );980981 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');982 }983984 /**985 * Removes a collection administrator.986 *987 * @param signer keyring of signer988 * @param collectionId ID of collection989 * @param adminAddressObj Administrator address (substrate or ethereum)990 * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})991 * @returns ```true``` if extrinsic success, otherwise ```false```992 */993 async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {994 const result = await this.helper.executeExtrinsic(995 signer,996 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],997 true,998 );9991000 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');1001 }10021003 /**1004 * Check if user is in allow list.1005 *1006 * @param collectionId ID of collection1007 * @param user Account to check1008 * @example await getAdmins(1)1009 * @returns is user in allow list1010 */1011 async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {1012 return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();1013 }10141015 /**1016 * Adds an address to allow list1017 * @param signer keyring of signer1018 * @param collectionId ID of collection1019 * @param addressObj address to add to the allow list1020 * @returns ```true``` if extrinsic success, otherwise ```false```1021 */1022 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1023 const result = await this.helper.executeExtrinsic(1024 signer,1025 'api.tx.unique.addToAllowList', [collectionId, addressObj],1026 true,1027 );10281029 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');1030 }10311032 /**1033 * Removes an address from allow list1034 *1035 * @param signer keyring of signer1036 * @param collectionId ID of collection1037 * @param addressObj address to remove from the allow list1038 * @returns ```true``` if extrinsic success, otherwise ```false```1039 */1040 async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1041 const result = await this.helper.executeExtrinsic(1042 signer,1043 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1044 true,1045 );10461047 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');1048 }10491050 /**1051 * Sets onchain permissions for selected collection.1052 *1053 * @param signer keyring of signer1054 * @param collectionId ID of collection1055 * @param permissions collection permissions object1056 * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1057 * @returns ```true``` if extrinsic success, otherwise ```false```1058 */1059 async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1060 const result = await this.helper.executeExtrinsic(1061 signer,1062 'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1063 true,1064 );10651066 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');1067 }10681069 /**1070 * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1071 *1072 * @param signer keyring of signer1073 * @param collectionId ID of collection1074 * @param permissions nesting permissions object1075 * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1076 * @returns ```true``` if extrinsic success, otherwise ```false```1077 */1078 async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1079 return await this.setPermissions(signer, collectionId, {nesting: permissions});1080 }10811082 /**1083 * Disables nesting for selected collection.1084 *1085 * @param signer keyring of signer1086 * @param collectionId ID of collection1087 * @example disableNesting(aliceKeyring, 10);1088 * @returns ```true``` if extrinsic success, otherwise ```false```1089 */1090 async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1091 return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1092 }10931094 /**1095 * Sets onchain properties to the collection.1096 *1097 * @param signer keyring of signer1098 * @param collectionId ID of collection1099 * @param properties array of property objects1100 * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1101 * @returns ```true``` if extrinsic success, otherwise ```false```1102 */1103 async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1104 const result = await this.helper.executeExtrinsic(1105 signer,1106 'api.tx.unique.setCollectionProperties', [collectionId, properties],1107 true,1108 );11091110 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1111 }11121113 /**1114 * Get collection properties.1115 *1116 * @param collectionId ID of collection1117 * @param propertyKeys optionally filter the returned properties to only these keys1118 * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1119 * @returns array of key-value pairs1120 */1121 async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1122 return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1123 }11241125 async getPropertiesConsumedSpace(collectionId: number): Promise<number> {1126 const api = this.helper.getApi();1127 const props = (await api.query.common.collectionProperties(collectionId)).toJSON();11281129 return (props! as any).consumedSpace;1130 }11311132 async getCollectionOptions(collectionId: number) {1133 return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1134 }11351136 /**1137 * Deletes onchain properties from the collection.1138 *1139 * @param signer keyring of signer1140 * @param collectionId ID of collection1141 * @param propertyKeys array of property keys to delete1142 * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1143 * @returns ```true``` if extrinsic success, otherwise ```false```1144 */1145 async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1146 const result = await this.helper.executeExtrinsic(1147 signer,1148 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1149 true,1150 );11511152 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1153 }11541155 /**1156 * Changes the owner of the token.1157 *1158 * @param signer keyring of signer1159 * @param collectionId ID of collection1160 * @param tokenId ID of token1161 * @param addressObj address of a new owner1162 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1163 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1164 * @returns true if the token success, otherwise false1165 */1166 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1167 const result = await this.helper.executeExtrinsic(1168 signer,1169 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1170 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1171 );11721173 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1174 }11751176 /**1177 *1178 * Change ownership of a token(s) on behalf of the owner.1179 *1180 * @param signer keyring of signer1181 * @param collectionId ID of collection1182 * @param tokenId ID of token1183 * @param fromAddressObj address on behalf of which the token will be sent1184 * @param toAddressObj new token owner1185 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1186 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1187 * @returns true if the token success, otherwise false1188 */1189 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1190 const result = await this.helper.executeExtrinsic(1191 signer,1192 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1193 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1194 );1195 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1196 }11971198 /**1199 *1200 * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1201 *1202 * @param signer keyring of signer1203 * @param collectionId ID of collection1204 * @param tokenId ID of token1205 * @param amount amount of tokens to be burned. For NFT must be set to 1n1206 * @example burnToken(aliceKeyring, 10, 5);1207 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1208 */1209 async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1210 const burnResult = await this.helper.executeExtrinsic(1211 signer,1212 'api.tx.unique.burnItem', [collectionId, tokenId, amount],1213 true, // `Unable to burn token for ${label}`,1214 );1215 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1216 if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1217 return burnedTokens.success;1218 }12191220 /**1221 * Destroys a concrete instance of NFT on behalf of the owner1222 *1223 * @param signer keyring of signer1224 * @param collectionId ID of collection1225 * @param tokenId ID of token1226 * @param fromAddressObj address on behalf of which the token will be burnt1227 * @param amount amount of tokens to be burned. For NFT must be set to 1n1228 * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1229 * @returns ```true``` if extrinsic success, otherwise ```false```1230 */1231 async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1232 const burnResult = await this.helper.executeExtrinsic(1233 signer,1234 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1235 true, // `Unable to burn token from for ${label}`,1236 );1237 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1238 return burnedTokens.success && burnedTokens.tokens.length > 0;1239 }12401241 /**1242 * Set, change, or remove approved address to transfer the ownership of the NFT.1243 *1244 * @param signer keyring of signer1245 * @param collectionId ID of collection1246 * @param tokenId ID of token1247 * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1248 * @param amount amount of token to be approved. For NFT must be set to 1n1249 * @returns ```true``` if extrinsic success, otherwise ```false```1250 */1251 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1252 const approveResult = await this.helper.executeExtrinsic(1253 signer,1254 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1255 true, // `Unable to approve token for ${label}`,1256 );12571258 return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1259 }12601261 /**1262 * Get the amount of token pieces approved to transfer or burn. Normally 0.1263 *1264 * @param collectionId ID of collection1265 * @param tokenId ID of token1266 * @param toAccountObj address which is approved to use token pieces1267 * @param fromAccountObj address which may have allowed the use of its owned tokens1268 * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1269 * @returns number of approved to transfer pieces1270 */1271 async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1272 return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1273 }12741275 /**1276 * Get the last created token ID in a collection1277 *1278 * @param collectionId ID of collection1279 * @example getLastTokenId(10);1280 * @returns id of the last created token1281 */1282 async getLastTokenId(collectionId: number): Promise<number> {1283 return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1284 }12851286 /**1287 * Check if token exists1288 *1289 * @param collectionId ID of collection1290 * @param tokenId ID of token1291 * @example doesTokenExist(10, 20);1292 * @returns true if the token exists, otherwise false1293 */1294 async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1295 return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1296 }1297}12981299class NFTnRFT extends CollectionGroup {1300 /**1301 * Get tokens owned by account1302 *1303 * @param collectionId ID of collection1304 * @param addressObj tokens owner1305 * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1306 * @returns array of token ids owned by account1307 */1308 async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1309 return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1310 }13111312 /**1313 * Get token data1314 *1315 * @param collectionId ID of collection1316 * @param tokenId ID of token1317 * @param propertyKeys optionally filter the token properties to only these keys1318 * @param blockHashAt optionally query the data at some block with this hash1319 * @example getToken(10, 5);1320 * @returns human readable token data1321 */1322 async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1323 properties: IProperty[];1324 owner: CrossAccountId;1325 normalizedOwner: CrossAccountId;1326 }| null> {1327 let tokenData;1328 if(typeof blockHashAt === 'undefined') {1329 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);1330 }1331 else {1332 if(propertyKeys.length == 0) {1333 const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1334 if(!collection) return null;1335 propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1336 }1337 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId, propertyKeys, blockHashAt]);1338 }1339 tokenData = tokenData.toHuman();1340 if (tokenData === null || tokenData.owner === null) return null;1341 const owner = {} as any;1342 for (const key of Object.keys(tokenData.owner)) {1343 owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate'1344 ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key])1345 : tokenData.owner[key];1346 }1347 tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner);1348 return tokenData;1349 }13501351 /**1352 * Set permissions to change token properties1353 *1354 * @param signer keyring of signer1355 * @param collectionId ID of collection1356 * @param permissions permissions to change a property by the collection admin or token owner1357 * @example setTokenPropertyPermissions(1358 * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1359 * )1360 * @returns true if extrinsic success otherwise false1361 */1362 async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1363 const result = await this.helper.executeExtrinsic(1364 signer,1365 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1366 true,1367 );13681369 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1370 }13711372 /**1373 * Get token property permissions.1374 *1375 * @param collectionId ID of collection1376 * @param propertyKeys optionally filter the returned property permissions to only these keys1377 * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1378 * @returns array of key-permission pairs1379 */1380 async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1381 return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1382 }13831384 /**1385 * Set token properties1386 *1387 * @param signer keyring of signer1388 * @param collectionId ID of collection1389 * @param tokenId ID of token1390 * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1391 * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1392 * @returns ```true``` if extrinsic success, otherwise ```false```1393 */1394 async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1395 const result = await this.helper.executeExtrinsic(1396 signer,1397 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1398 true,1399 );14001401 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1402 }14031404 /**1405 * Get properties, metadata assigned to a token.1406 *1407 * @param collectionId ID of collection1408 * @param tokenId ID of token1409 * @param propertyKeys optionally filter the returned properties to only these keys1410 * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1411 * @returns array of key-value pairs1412 */1413 async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1414 return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1415 }14161417 /**1418 * Delete the provided properties of a token1419 * @param signer keyring of signer1420 * @param collectionId ID of collection1421 * @param tokenId ID of token1422 * @param propertyKeys property keys to be deleted1423 * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1424 * @returns ```true``` if extrinsic success, otherwise ```false```1425 */1426 async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1427 const result = await this.helper.executeExtrinsic(1428 signer,1429 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1430 true,1431 );14321433 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1434 }14351436 /**1437 * Mint new collection1438 *1439 * @param signer keyring of signer1440 * @param collectionOptions basic collection options and properties1441 * @param mode NFT or RFT type of a collection1442 * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1443 * @returns object of the created collection1444 */1445 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1446 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1447 collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1448 for (const key of ['name', 'description', 'tokenPrefix']) {1449 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1450 }1451 const creationResult = await this.helper.executeExtrinsic(1452 signer,1453 'api.tx.unique.createCollectionEx', [collectionOptions],1454 true, // errorLabel,1455 );1456 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1457 }14581459 getCollectionObject(_collectionId: number): any {1460 return null;1461 }14621463 getTokenObject(_collectionId: number, _tokenId: number): any {1464 return null;1465 }14661467 /**1468 * Tells whether the given `owner` approves the `operator`.1469 * @param collectionId ID of collection1470 * @param owner owner address1471 * @param operator operator addrees1472 * @returns true if operator is enabled1473 */1474 async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {1475 return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();1476 }14771478 /** Sets or unsets the approval of a given operator.1479 * The `operator` is allowed to transfer all tokens of the `caller` on their behalf.1480 * @param operator Operator1481 * @param approved Should operator status be granted or revoked?1482 * @returns ```true``` if extrinsic success, otherwise ```false```1483 */1484 async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {1485 const result = await this.helper.executeExtrinsic(1486 signer,1487 'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],1488 true,1489 );1490 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');1491 }1492}149314941495class NFTGroup extends NFTnRFT {1496 /**1497 * Get collection object1498 * @param collectionId ID of collection1499 * @example getCollectionObject(2);1500 * @returns instance of UniqueNFTCollection1501 */1502 getCollectionObject(collectionId: number): UniqueNFTCollection {1503 return new UniqueNFTCollection(collectionId, this.helper);1504 }15051506 /**1507 * Get token object1508 * @param collectionId ID of collection1509 * @param tokenId ID of token1510 * @example getTokenObject(10, 5);1511 * @returns instance of UniqueNFTToken1512 */1513 getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1514 return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1515 }15161517 /**1518 * Get token's owner1519 * @param collectionId ID of collection1520 * @param tokenId ID of token1521 * @param blockHashAt optionally query the data at the block with this hash1522 * @example getTokenOwner(10, 5);1523 * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1524 */1525 async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId> {1526 let owner;1527 if (typeof blockHashAt === 'undefined') {1528 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1529 } else {1530 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1531 }1532 return CrossAccountId.fromLowerCaseKeys(owner.toJSON());1533 }15341535 /**1536 * Is token approved to transfer1537 * @param collectionId ID of collection1538 * @param tokenId ID of token1539 * @param toAccountObj address to be approved1540 * @returns ```true``` if extrinsic success, otherwise ```false```1541 */1542 async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1543 return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1544 }15451546 /**1547 * Changes the owner of the token.1548 *1549 * @param signer keyring of signer1550 * @param collectionId ID of collection1551 * @param tokenId ID of token1552 * @param addressObj address of a new owner1553 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1554 * @returns ```true``` if extrinsic success, otherwise ```false```1555 */1556 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1557 return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1558 }15591560 /**1561 *1562 * Change ownership of a NFT on behalf of the owner.1563 *1564 * @param signer keyring of signer1565 * @param collectionId ID of collection1566 * @param tokenId ID of token1567 * @param fromAddressObj address on behalf of which the token will be sent1568 * @param toAddressObj new token owner1569 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1570 * @returns ```true``` if extrinsic success, otherwise ```false```1571 */1572 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1573 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1574 }15751576 /**1577 * Recursively find the address that owns the token1578 * @param collectionId ID of collection1579 * @param tokenId ID of token1580 * @param blockHashAt1581 * @example getTokenTopmostOwner(10, 5);1582 * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1583 */1584 async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId | null> {1585 let owner;1586 if (typeof blockHashAt === 'undefined') {1587 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1588 } else {1589 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1590 }15911592 if (owner === null) return null;15931594 return owner.toHuman();1595 }15961597 /**1598 * Get tokens nested in the provided token1599 * @param collectionId ID of collection1600 * @param tokenId ID of token1601 * @param blockHashAt optionally query the data at the block with this hash1602 * @example getTokenChildren(10, 5);1603 * @returns tokens whose depth of nesting is <= 51604 */1605 async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1606 let children;1607 if(typeof blockHashAt === 'undefined') {1608 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1609 } else {1610 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1611 }16121613 return children.toJSON().map((x: any) => {1614 return {collectionId: x.collection, tokenId: x.token};1615 });1616 }16171618 /**1619 * Nest one token into another1620 * @param signer keyring of signer1621 * @param tokenObj token to be nested1622 * @param rootTokenObj token to be parent1623 * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1624 * @returns ```true``` if extrinsic success, otherwise ```false```1625 */1626 async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1627 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1628 const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1629 if(!result) {1630 throw Error('Unable to nest token!');1631 }1632 return result;1633 }16341635 /**1636 * Remove token from nested state1637 * @param signer keyring of signer1638 * @param tokenObj token to unnest1639 * @param rootTokenObj parent of a token1640 * @param toAddressObj address of a new token owner1641 * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1642 * @returns ```true``` if extrinsic success, otherwise ```false```1643 */1644 async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1645 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1646 const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1647 if(!result) {1648 throw Error('Unable to unnest token!');1649 }1650 return result;1651 }16521653 /**1654 * Mint new collection1655 * @param signer keyring of signer1656 * @param collectionOptions Collection options1657 * @example1658 * mintCollection(aliceKeyring, {1659 * name: 'New',1660 * description: 'New collection',1661 * tokenPrefix: 'NEW',1662 * })1663 * @returns object of the created collection1664 */1665 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1666 return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1667 }16681669 /**1670 * Mint new token1671 * @param signer keyring of signer1672 * @param data token data1673 * @returns created token object1674 */1675 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1676 const creationResult = await this.helper.executeExtrinsic(1677 signer,1678 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1679 nft: {1680 properties: data.properties,1681 },1682 }],1683 true,1684 );1685 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1686 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1687 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1688 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1689 }16901691 /**1692 * Mint multiple NFT tokens1693 * @param signer keyring of signer1694 * @param collectionId ID of collection1695 * @param tokens array of tokens with owner and properties1696 * @example1697 * mintMultipleTokens(aliceKeyring, 10, [{1698 * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1699 * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1700 * },{1701 * owner: {Ethereum: "0x9F0583DbB855d..."},1702 * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1703 * }]);1704 * @returns ```true``` if extrinsic success, otherwise ```false```1705 */1706 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1707 const creationResult = await this.helper.executeExtrinsic(1708 signer,1709 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1710 true,1711 );1712 const collection = this.getCollectionObject(collectionId);1713 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1714 }17151716 /**1717 * Mint multiple NFT tokens with one owner1718 * @param signer keyring of signer1719 * @param collectionId ID of collection1720 * @param owner tokens owner1721 * @param tokens array of tokens with owner and properties1722 * @example1723 * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1724 * properties: [{1725 * key: "gender",1726 * value: "female",1727 * },{1728 * key: "age",1729 * value: "33",1730 * }],1731 * }]);1732 * @returns array of newly created tokens1733 */1734 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1735 const rawTokens = [];1736 for (const token of tokens) {1737 const raw = {NFT: {properties: token.properties}};1738 rawTokens.push(raw);1739 }1740 const creationResult = await this.helper.executeExtrinsic(1741 signer,1742 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1743 true,1744 );1745 const collection = this.getCollectionObject(collectionId);1746 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1747 }17481749 /**1750 * Set, change, or remove approved address to transfer the ownership of the NFT.1751 *1752 * @param signer keyring of signer1753 * @param collectionId ID of collection1754 * @param tokenId ID of token1755 * @param toAddressObj address to approve1756 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1757 * @returns ```true``` if extrinsic success, otherwise ```false```1758 */1759 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1760 return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1761 }1762}176317641765class RFTGroup extends NFTnRFT {1766 /**1767 * Get collection object1768 * @param collectionId ID of collection1769 * @example getCollectionObject(2);1770 * @returns instance of UniqueRFTCollection1771 */1772 getCollectionObject(collectionId: number): UniqueRFTCollection {1773 return new UniqueRFTCollection(collectionId, this.helper);1774 }17751776 /**1777 * Get token object1778 * @param collectionId ID of collection1779 * @param tokenId ID of token1780 * @example getTokenObject(10, 5);1781 * @returns instance of UniqueNFTToken1782 */1783 getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1784 return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1785 }17861787 /**1788 * Get top 10 token owners with the largest number of pieces1789 * @param collectionId ID of collection1790 * @param tokenId ID of token1791 * @example getTokenTop10Owners(10, 5);1792 * @returns array of top 10 owners1793 */1794 async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<CrossAccountId[]> {1795 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys);1796 }17971798 /**1799 * Get number of pieces owned by address1800 * @param collectionId ID of collection1801 * @param tokenId ID of token1802 * @param addressObj address token owner1803 * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1804 * @returns number of pieces ownerd by address1805 */1806 async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1807 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1808 }18091810 /**1811 * Transfer pieces of token to another address1812 * @param signer keyring of signer1813 * @param collectionId ID of collection1814 * @param tokenId ID of token1815 * @param addressObj address of a new owner1816 * @param amount number of pieces to be transfered1817 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1818 * @returns ```true``` if extrinsic success, otherwise ```false```1819 */1820 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1821 return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1822 }18231824 /**1825 * Change ownership of some pieces of RFT on behalf of the owner.1826 * @param signer keyring of signer1827 * @param collectionId ID of collection1828 * @param tokenId ID of token1829 * @param fromAddressObj address on behalf of which the token will be sent1830 * @param toAddressObj new token owner1831 * @param amount number of pieces to be transfered1832 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1833 * @returns ```true``` if extrinsic success, otherwise ```false```1834 */1835 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1836 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1837 }18381839 /**1840 * Mint new collection1841 * @param signer keyring of signer1842 * @param collectionOptions Collection options1843 * @example1844 * mintCollection(aliceKeyring, {1845 * name: 'New',1846 * description: 'New collection',1847 * tokenPrefix: 'NEW',1848 * })1849 * @returns object of the created collection1850 */1851 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1852 return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1853 }18541855 /**1856 * Mint new token1857 * @param signer keyring of signer1858 * @param data token data1859 * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1860 * @returns created token object1861 */1862 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1863 const creationResult = await this.helper.executeExtrinsic(1864 signer,1865 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1866 refungible: {1867 pieces: data.pieces,1868 properties: data.properties,1869 },1870 }],1871 true,1872 );1873 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1874 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1875 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1876 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1877 }18781879 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1880 throw Error('Not implemented');1881 const creationResult = await this.helper.executeExtrinsic(1882 signer,1883 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],1884 true, // `Unable to mint RFT tokens for ${label}`,1885 );1886 const collection = this.getCollectionObject(collectionId);1887 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1888 }18891890 /**1891 * Mint multiple RFT tokens with one owner1892 * @param signer keyring of signer1893 * @param collectionId ID of collection1894 * @param owner tokens owner1895 * @param tokens array of tokens with properties and pieces1896 * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);1897 * @returns array of newly created RFT tokens1898 */1899 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1900 const rawTokens = [];1901 for (const token of tokens) {1902 const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};1903 rawTokens.push(raw);1904 }1905 const creationResult = await this.helper.executeExtrinsic(1906 signer,1907 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1908 true,1909 );1910 const collection = this.getCollectionObject(collectionId);1911 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1912 }19131914 /**1915 * Destroys a concrete instance of RFT.1916 * @param signer keyring of signer1917 * @param collectionId ID of collection1918 * @param tokenId ID of token1919 * @param amount number of pieces to be burnt1920 * @example burnToken(aliceKeyring, 10, 5);1921 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1922 */1923 async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1924 return await super.burnToken(signer, collectionId, tokenId, amount);1925 }19261927 /**1928 * Destroys a concrete instance of RFT on behalf of the owner.1929 * @param signer keyring of signer1930 * @param collectionId ID of collection1931 * @param tokenId ID of token1932 * @param fromAddressObj address on behalf of which the token will be burnt1933 * @param amount number of pieces to be burnt1934 * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)1935 * @returns ```true``` if extrinsic success, otherwise ```false```1936 */1937 async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1938 return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);1939 }19401941 /**1942 * Set, change, or remove approved address to transfer the ownership of the RFT.1943 *1944 * @param signer keyring of signer1945 * @param collectionId ID of collection1946 * @param tokenId ID of token1947 * @param toAddressObj address to approve1948 * @param amount number of pieces to be approved1949 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1950 * @returns true if the token success, otherwise false1951 */1952 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1953 return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1954 }19551956 /**1957 * Get total number of pieces1958 * @param collectionId ID of collection1959 * @param tokenId ID of token1960 * @example getTokenTotalPieces(10, 5);1961 * @returns number of pieces1962 */1963 async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {1964 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();1965 }19661967 /**1968 * Change number of token pieces. Signer must be the owner of all token pieces.1969 * @param signer keyring of signer1970 * @param collectionId ID of collection1971 * @param tokenId ID of token1972 * @param amount new number of pieces1973 * @example repartitionToken(aliceKeyring, 10, 5, 12345n);1974 * @returns true if the repartion was success, otherwise false1975 */1976 async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {1977 const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);1978 const repartitionResult = await this.helper.executeExtrinsic(1979 signer,1980 'api.tx.unique.repartition', [collectionId, tokenId, amount],1981 true,1982 );1983 if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');1984 return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');1985 }1986}198719881989class FTGroup extends CollectionGroup {1990 /**1991 * Get collection object1992 * @param collectionId ID of collection1993 * @example getCollectionObject(2);1994 * @returns instance of UniqueFTCollection1995 */1996 getCollectionObject(collectionId: number): UniqueFTCollection {1997 return new UniqueFTCollection(collectionId, this.helper);1998 }19992000 /**2001 * Mint new fungible collection2002 * @param signer keyring of signer2003 * @param collectionOptions Collection options2004 * @param decimalPoints number of token decimals2005 * @example2006 * mintCollection(aliceKeyring, {2007 * name: 'New',2008 * description: 'New collection',2009 * tokenPrefix: 'NEW',2010 * }, 18)2011 * @returns newly created fungible collection2012 */2013 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {2014 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object2015 if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');2016 collectionOptions.mode = {fungible: decimalPoints};2017 for (const key of ['name', 'description', 'tokenPrefix']) {2018 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);2019 }2020 const creationResult = await this.helper.executeExtrinsic(2021 signer,2022 'api.tx.unique.createCollectionEx', [collectionOptions],2023 true,2024 );2025 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));2026 }20272028 /**2029 * Mint tokens2030 * @param signer keyring of signer2031 * @param collectionId ID of collection2032 * @param owner address owner of new tokens2033 * @param amount amount of tokens to be meanted2034 * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);2035 * @returns ```true``` if extrinsic success, otherwise ```false```2036 */2037 async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {2038 const creationResult = await this.helper.executeExtrinsic(2039 signer,2040 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {2041 fungible: {2042 value: amount,2043 },2044 }],2045 true, // `Unable to mint fungible tokens for ${label}`,2046 );2047 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2048 }20492050 /**2051 * Mint multiple Fungible tokens with one owner2052 * @param signer keyring of signer2053 * @param collectionId ID of collection2054 * @param owner tokens owner2055 * @param tokens array of tokens with properties and pieces2056 * @returns ```true``` if extrinsic success, otherwise ```false```2057 */2058 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {2059 const rawTokens = [];2060 for (const token of tokens) {2061 const raw = {Fungible: {Value: token.value}};2062 rawTokens.push(raw);2063 }2064 const creationResult = await this.helper.executeExtrinsic(2065 signer,2066 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2067 true,2068 );2069 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2070 }20712072 /**2073 * Get the top 10 owners with the largest balance for the Fungible collection2074 * @param collectionId ID of collection2075 * @example getTop10Owners(10);2076 * @returns array of ```ICrossAccountId```2077 */2078 async getTop10Owners(collectionId: number): Promise<CrossAccountId[]> {2079 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys);2080 }20812082 /**2083 * Get account balance2084 * @param collectionId ID of collection2085 * @param addressObj address of owner2086 * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2087 * @returns amount of fungible tokens owned by address2088 */2089 async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2090 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2091 }20922093 /**2094 * Transfer tokens to address2095 * @param signer keyring of signer2096 * @param collectionId ID of collection2097 * @param toAddressObj address recipient2098 * @param amount amount of tokens to be sent2099 * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2100 * @returns ```true``` if extrinsic success, otherwise ```false```2101 */2102 async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2103 return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2104 }21052106 /**2107 * Transfer some tokens on behalf of the owner.2108 * @param signer keyring of signer2109 * @param collectionId ID of collection2110 * @param fromAddressObj address on behalf of which tokens will be sent2111 * @param toAddressObj address where token to be sent2112 * @param amount number of tokens to be sent2113 * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2114 * @returns ```true``` if extrinsic success, otherwise ```false```2115 */2116 async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {2117 return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2118 }21192120 /**2121 * Destroy some amount of tokens2122 * @param signer keyring of signer2123 * @param collectionId ID of collection2124 * @param amount amount of tokens to be destroyed2125 * @example burnTokens(aliceKeyring, 10, 1000n);2126 * @returns ```true``` if extrinsic success, otherwise ```false```2127 */2128 async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {2129 return await super.burnToken(signer, collectionId, 0, amount);2130 }21312132 /**2133 * Burn some tokens on behalf of the owner.2134 * @param signer keyring of signer2135 * @param collectionId ID of collection2136 * @param fromAddressObj address on behalf of which tokens will be burnt2137 * @param amount amount of tokens to be burnt2138 * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2139 * @returns ```true``` if extrinsic success, otherwise ```false```2140 */2141 async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {2142 return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2143 }21442145 /**2146 * Get total collection supply2147 * @param collectionId2148 * @returns2149 */2150 async getTotalPieces(collectionId: number): Promise<bigint> {2151 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2152 }21532154 /**2155 * Set, change, or remove approved address to transfer tokens.2156 *2157 * @param signer keyring of signer2158 * @param collectionId ID of collection2159 * @param toAddressObj address to be approved2160 * @param amount amount of tokens to be approved2161 * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2162 * @returns ```true``` if extrinsic success, otherwise ```false```2163 */2164 approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2165 return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2166 }21672168 /**2169 * Get amount of fungible tokens approved to transfer2170 * @param collectionId ID of collection2171 * @param fromAddressObj owner of tokens2172 * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2173 * @returns number of tokens approved for the transfer2174 */2175 getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2176 return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2177 }2178}217921802181class ChainGroup extends HelperGroup<ChainHelperBase> {2182 /**2183 * Get system properties of a chain2184 * @example getChainProperties();2185 * @returns ss58Format, token decimals, and token symbol2186 */2187 getChainProperties(): IChainProperties {2188 const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2189 return {2190 ss58Format: properties.ss58Format.toJSON(),2191 tokenDecimals: properties.tokenDecimals.toJSON(),2192 tokenSymbol: properties.tokenSymbol.toJSON(),2193 };2194 }21952196 /**2197 * Get chain header2198 * @example getLatestBlockNumber();2199 * @returns the number of the last block2200 */2201 async getLatestBlockNumber(): Promise<number> {2202 return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2203 }22042205 /**2206 * Get block hash by block number2207 * @param blockNumber number of block2208 * @example getBlockHashByNumber(12345);2209 * @returns hash of a block2210 */2211 async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2212 const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2213 if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2214 return blockHash;2215 }22162217 // TODO add docs2218 async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2219 const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2220 if (!blockHash) return null;2221 return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2222 }22232224 /**2225 * Get latest relay block2226 * @returns {number} relay block2227 */2228 async getRelayBlockNumber(): Promise<bigint> {2229 const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;2230 return BigInt(blockNumber);2231 }22322233 /**2234 * Get account nonce2235 * @param address substrate address2236 * @example getNonce("5GrwvaEF5zXb26Fz...");2237 * @returns number, account's nonce2238 */2239 async getNonce(address: TSubstrateAccount): Promise<number> {2240 return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2241 }2242}22432244class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2245 /**2246 * Get substrate address balance2247 * @param address substrate address2248 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2249 * @returns amount of tokens on address2250 */2251 async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2252 return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2253 }22542255 /**2256 * Transfer tokens to substrate address2257 * @param signer keyring of signer2258 * @param address substrate address of a recipient2259 * @param amount amount of tokens to be transfered2260 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2261 * @returns ```true``` if extrinsic success, otherwise ```false```2262 */2263 async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2264 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}`*/);22652266 let transfer = {from: null, to: null, amount: 0n} as any;2267 result.result.events.forEach(({event: {data, method, section}}) => {2268 if ((section === 'balances') && (method === 'Transfer')) {2269 transfer = {2270 from: this.helper.address.normalizeSubstrate(data[0]),2271 to: this.helper.address.normalizeSubstrate(data[1]),2272 amount: BigInt(data[2]),2273 };2274 }2275 });2276 const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2277 && this.helper.address.normalizeSubstrate(address) === transfer.to2278 && BigInt(amount) === transfer.amount;2279 return isSuccess;2280 }22812282 /**2283 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2284 * @param address substrate address2285 * @returns2286 */2287 async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2288 const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2289 return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2290 }22912292 async getLocked(address: TSubstrateAccount): Promise<[{id: string, amount: bigint, reason: string}]> {2293 const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();2294 return locks.map((lock: any) => {return {id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons};});2295 }2296}22972298class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2299 /**2300 * Get ethereum address balance2301 * @param address ethereum address2302 * @example getEthereum("0x9F0583DbB855d...")2303 * @returns amount of tokens on address2304 */2305 async getEthereum(address: TEthereumAccount): Promise<bigint> {2306 return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2307 }23082309 /**2310 * Transfer tokens to address2311 * @param signer keyring of signer2312 * @param address Ethereum address of a recipient2313 * @param amount amount of tokens to be transfered2314 * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2315 * @returns ```true``` if extrinsic success, otherwise ```false```2316 */2317 async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2318 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);23192320 let transfer = {from: null, to: null, amount: 0n} as any;2321 result.result.events.forEach(({event: {data, method, section}}) => {2322 if ((section === 'balances') && (method === 'Transfer')) {2323 transfer = {2324 from: data[0].toString(),2325 to: data[1].toString(),2326 amount: BigInt(data[2]),2327 };2328 }2329 });2330 const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2331 && address === transfer.to2332 && BigInt(amount) === transfer.amount;2333 return isSuccess;2334 }2335}23362337class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2338 subBalanceGroup: SubstrateBalanceGroup<T>;2339 ethBalanceGroup: EthereumBalanceGroup<T>;23402341 constructor(helper: T) {2342 super(helper);2343 this.subBalanceGroup = new SubstrateBalanceGroup(helper);2344 this.ethBalanceGroup = new EthereumBalanceGroup(helper);2345 }23462347 getCollectionCreationPrice(): bigint {2348 return 2n * this.getOneTokenNominal();2349 }2350 /**2351 * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2352 * @example getOneTokenNominal()2353 * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2354 */2355 getOneTokenNominal(): bigint {2356 const chainProperties = this.helper.chain.getChainProperties();2357 return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2358 }23592360 /**2361 * Get substrate address balance2362 * @param address substrate address2363 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2364 * @returns amount of tokens on address2365 */2366 getSubstrate(address: TSubstrateAccount): Promise<bigint> {2367 return this.subBalanceGroup.getSubstrate(address);2368 }23692370 /**2371 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2372 * @param address substrate address2373 * @returns2374 */2375 getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2376 return this.subBalanceGroup.getSubstrateFull(address);2377 }23782379 /**2380 * Get locked balances2381 * @param address substrate address2382 * @returns locked balances with reason via api.query.balances.locks2383 */2384 getLocked(address: TSubstrateAccount) {2385 return this.subBalanceGroup.getLocked(address);2386 }23872388 /**2389 * Get ethereum address balance2390 * @param address ethereum address2391 * @example getEthereum("0x9F0583DbB855d...")2392 * @returns amount of tokens on address2393 */2394 getEthereum(address: TEthereumAccount): Promise<bigint> {2395 return this.ethBalanceGroup.getEthereum(address);2396 }23972398 /**2399 * Transfer tokens to substrate address2400 * @param signer keyring of signer2401 * @param address substrate address of a recipient2402 * @param amount amount of tokens to be transfered2403 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2404 * @returns ```true``` if extrinsic success, otherwise ```false```2405 */2406 transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2407 return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2408 }24092410 async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2411 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);24122413 let transfer = {from: null, to: null, amount: 0n} as any;2414 result.result.events.forEach(({event: {data, method, section}}) => {2415 if ((section === 'balances') && (method === 'Transfer')) {2416 transfer = {2417 from: this.helper.address.normalizeSubstrate(data[0]),2418 to: this.helper.address.normalizeSubstrate(data[1]),2419 amount: BigInt(data[2]),2420 };2421 }2422 });2423 let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2424 isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2425 isSuccess = isSuccess && BigInt(amount) === transfer.amount;2426 return isSuccess;2427 }24282429 /**2430 * Transfer tokens with the unlock period2431 * @param signer signers Keyring2432 * @param address Substrate address of recipient2433 * @param schedule Schedule params2434 * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 50002435 */2436 async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: {start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}): Promise<void> {2437 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);2438 const event = result.result.events2439 .find(e => e.event.section === 'vesting' &&2440 e.event.method === 'VestingScheduleAdded' &&2441 e.event.data[0].toHuman() === signer.address);2442 if (!event) throw Error('Cannot find transfer in events');2443 }24442445 /**2446 * Get schedule for recepient of vested transfer2447 * @param address Substrate address of recipient2448 * @returns2449 */2450 async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> {2451 const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2452 return schedule.map((schedule: any) => {2453 return {2454 start: BigInt(schedule.start),2455 period: BigInt(schedule.period),2456 periodCount: BigInt(schedule.periodCount),2457 perPeriod: BigInt(schedule.perPeriod),2458 };2459 });2460 }24612462 /**2463 * Claim vested tokens2464 * @param signer signers Keyring2465 */2466 async claim(signer: TSigner) {2467 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);2468 const event = result.result.events2469 .find(e => e.event.section === 'vesting' &&2470 e.event.method === 'Claimed' &&2471 e.event.data[0].toHuman() === signer.address);2472 if (!event) throw Error('Cannot find claim in events');2473 }2474}24752476class AddressGroup extends HelperGroup<ChainHelperBase> {2477 /**2478 * Normalizes the address to the specified ss58 format, by default ```42```.2479 * @param address substrate address2480 * @param ss58Format format for address conversion, by default ```42```2481 * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2482 * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2483 */2484 normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2485 return CrossAccountId.normalizeSubstrateAddress(address, ss58Format);2486 }24872488 /**2489 * Get address in the connected chain format2490 * @param address substrate address2491 * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2492 * @returns address in chain format2493 */2494 normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2495 return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2496 }24972498 /**2499 * Get substrate mirror of an ethereum address2500 * @param ethAddress ethereum address2501 * @param toChainFormat false for normalized account2502 * @example ethToSubstrate('0x9F0583DbB855d...')2503 * @returns substrate mirror of a provided ethereum address2504 */2505 ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat=false): TSubstrateAccount {2506 return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2507 }25082509 /**2510 * Get ethereum mirror of a substrate address2511 * @param subAddress substrate account2512 * @example substrateToEth("5DnSF6RRjwteE3BrC...")2513 * @returns ethereum mirror of a provided substrate address2514 */2515 substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2516 return CrossAccountId.translateSubToEth(subAddress);2517 }25182519 /**2520 * Encode key to substrate address2521 * @param key key for encoding address2522 * @param ss58Format prefix for encoding to the address of the corresponding network2523 * @returns encoded substrate address2524 */2525 encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {2526 const u8a :Uint8Array = typeof key === 'string'2527 ? hexToU8a(key)2528 : typeof key === 'bigint'2529 ? hexToU8a(key.toString(16))2530 : key;25312532 if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2533 throw new Error(`ss58Format is not valid, received ${typeofss58Format} "${ss58Format}"`);2534 }25352536 const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2537 if (!allowedDecodedLengths.includes(u8a.length)) {2538 throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2539 }25402541 const u8aPrefix = ss58Format < 642542 ? new Uint8Array([ss58Format])2543 : new Uint8Array([2544 ((ss58Format & 0xfc) >> 2) | 0x40,2545 (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2546 ]);25472548 const input = u8aConcat(u8aPrefix, u8a);25492550 return base58Encode(u8aConcat(2551 input,2552 blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2553 ));2554 }25552556 /**2557 * Restore substrate address from bigint representation2558 * @param number decimal representation of substrate address2559 * @returns substrate address2560 */2561 restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2562 if (this.helper.api === null) {2563 throw 'Not connected';2564 }2565 const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2566 if (res === undefined || res === null) {2567 throw 'Restore address error';2568 }2569 return res.toString();2570 }25712572 /**2573 * Convert etherium cross account id to substrate cross account id2574 * @param ethCrossAccount etherium cross account2575 * @returns substrate cross account id2576 */2577 convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2578 if (ethCrossAccount.sub === '0') {2579 return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2580 }25812582 const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2583 return {Substrate: ss58};2584 }25852586 paraSiblingSovereignAccount(paraid: number) {2587 // We are getting a *sibling* parachain sovereign account,2588 // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2589 const siblingPrefix = '0x7369626c';25902591 const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2592 const suffix = '000000000000000000000000000000000000000000000000';25932594 return siblingPrefix + encodedParaId + suffix;2595 }2596}25972598class StakingGroup extends HelperGroup<UniqueHelper> {2599 /**2600 * Stake tokens for App Promotion2601 * @param signer keyring of signer2602 * @param amountToStake amount of tokens to stake2603 * @param label extra label for log2604 * @returns2605 */2606 async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2607 if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2608 const _stakeResult = await this.helper.executeExtrinsic(2609 signer, 'api.tx.appPromotion.stake',2610 [amountToStake], true,2611 );2612 // TODO extract info from stakeResult2613 return true;2614 }26152616 /**2617 * Unstake tokens for App Promotion2618 * @param signer keyring of signer2619 * @param amountToUnstake amount of tokens to unstake2620 * @param label extra label for log2621 * @returns block number where balances will be unlocked2622 */2623 async unstake(signer: TSigner, label?: string): Promise<number> {2624 if(typeof label === 'undefined') label = `${signer.address}`;2625 const _unstakeResult = await this.helper.executeExtrinsic(2626 signer, 'api.tx.appPromotion.unstake',2627 [], true,2628 );2629 // TODO extract block number fron events2630 return 1;2631 }26322633 /**2634 * Get total staked amount for address2635 * @param address substrate or ethereum address2636 * @returns total staked amount2637 */2638 async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2639 if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2640 return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2641 }26422643 /**2644 * Get total staked per block2645 * @param address substrate or ethereum address2646 * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2647 */2648 async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2649 const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2650 return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {2651 return {2652 block: block.toBigInt(),2653 amount: amount.toBigInt(),2654 };2655 });2656 }26572658 /**2659 * Get total pending unstake amount for address2660 * @param address substrate or ethereum address2661 * @returns total pending unstake amount2662 */2663 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2664 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2665 }26662667 /**2668 * Get pending unstake amount per block for address2669 * @param address substrate or ethereum address2670 * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2671 */2672 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2673 const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2674 const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {2675 return {2676 block: block.toBigInt(),2677 amount: amount.toBigInt(),2678 };2679 });2680 return result;2681 }2682}26832684class SchedulerGroup extends HelperGroup<UniqueHelper> {2685 constructor(helper: UniqueHelper) {2686 super(helper);2687 }26882689 cancelScheduled(signer: TSigner, scheduledId: string) {2690 return this.helper.executeExtrinsic(2691 signer,2692 'api.tx.scheduler.cancelNamed',2693 [scheduledId],2694 true,2695 );2696 }26972698 changePriority(signer: TSigner, scheduledId: string, priority: number) {2699 return this.helper.executeExtrinsic(2700 signer,2701 'api.tx.scheduler.changeNamedPriority',2702 [scheduledId, priority],2703 true,2704 );2705 }27062707 scheduleAt<T extends UniqueHelper>(2708 executionBlockNumber: number,2709 options: ISchedulerOptions = {},2710 ) {2711 return this.schedule<T>('schedule', executionBlockNumber, options);2712 }27132714 scheduleAfter<T extends UniqueHelper>(2715 blocksBeforeExecution: number,2716 options: ISchedulerOptions = {},2717 ) {2718 return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2719 }27202721 schedule<T extends UniqueHelper>(2722 scheduleFn: 'schedule' | 'scheduleAfter',2723 blocksNum: number,2724 options: ISchedulerOptions = {},2725 ) {2726 // eslint-disable-next-line @typescript-eslint/naming-convention2727 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2728 return this.helper.clone(ScheduledHelperType, {2729 scheduleFn,2730 blocksNum,2731 options,2732 }) as T;2733 }2734}27352736class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {2737 async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {2738 await this.helper.executeExtrinsic(2739 signer,2740 'api.tx.foreignAssets.registerForeignAsset',2741 [ownerAddress, location, metadata],2742 true,2743 );2744 }27452746 async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {2747 await this.helper.executeExtrinsic(2748 signer,2749 'api.tx.foreignAssets.updateForeignAsset',2750 [foreignAssetId, location, metadata],2751 true,2752 );2753 }2754}27552756class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {2757 palletName: string;27582759 constructor(helper: T, palletName: string) {2760 super(helper);27612762 this.palletName = palletName;2763 }27642765 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) {2766 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);2767 }27682769 async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {2770 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);2771 }27722773 async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint) {2774 const destination = {2775 V1: {2776 parents: 0,2777 interior: {2778 X1: {2779 Parachain: destinationParaId,2780 },2781 },2782 },2783 };27842785 const beneficiary = {2786 V1: {2787 parents: 0,2788 interior: {2789 X1: {2790 AccountId32: {2791 network: 'Any',2792 id: targetAccount,2793 },2794 },2795 },2796 },2797 };27982799 const assets = {2800 V1: [2801 {2802 id: {2803 Concrete: {2804 parents: 0,2805 interior: 'Here',2806 },2807 },2808 fun: {2809 Fungible: amount,2810 },2811 },2812 ],2813 };28142815 const feeAssetItem = 0;28162817 await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem);2818 }2819}28202821class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2822 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) {2823 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2824 }28252826 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) {2827 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2828 }28292830 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) {2831 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2832 }2833}28342835class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2836 async accounts(address: string, currencyId: any) {2837 const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;2838 return BigInt(free);2839 }2840}28412842class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {2843 async create(signer: TSigner, assetId: number, admin: string, minimalBalance: bigint) {2844 await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);2845 }28462847 async setMetadata(signer: TSigner, assetId: number, name: string, symbol: string, decimals: number) {2848 await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);2849 }28502851 async mint(signer: TSigner, assetId: number, beneficiary: string, amount: bigint) {2852 await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);2853 }28542855 async account(assetId: string | number, address: string) {2856 const accountAsset = (2857 await this.helper.callRpc('api.query.assets.account', [assetId, address])2858 ).toJSON()! as any;28592860 if (accountAsset !== null) {2861 return BigInt(accountAsset['balance']);2862 } else {2863 return null;2864 }2865 }2866}28672868class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {2869 async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {2870 await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);2871 }2872}28732874class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {2875 makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {2876 const apiPrefix = 'api.tx.assetManager.';28772878 const registerTx = this.helper.constructApiCall(2879 apiPrefix + 'registerForeignAsset',2880 [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],2881 );28822883 const setUnitsTx = this.helper.constructApiCall(2884 apiPrefix + 'setAssetUnitsPerSecond',2885 [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],2886 );28872888 const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);2889 const encodedProposal = batchCall?.method.toHex() || '';2890 return encodedProposal;2891 }28922893 async assetTypeId(location: any) {2894 return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);2895 }2896}28972898class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2899 notePreimagePallet: string;29002901 constructor(helper: MoonbeamHelper, options: {[key: string]: any} = {}) {2902 super(helper);2903 this.notePreimagePallet = options.notePreimagePallet;2904 }29052906 async notePreimage(signer: TSigner, encodedProposal: string) {2907 await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);2908 }29092910 externalProposeMajority(proposal: any) {2911 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);2912 }29132914 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2915 return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);2916 }29172918 async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {2919 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);2920 }2921}29222923class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {2924 collective: string;29252926 constructor(helper: MoonbeamHelper, collective: string) {2927 super(helper);29282929 this.collective = collective;2930 }29312932 async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {2933 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);2934 }29352936 async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {2937 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2938 }29392940 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {2941 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2942 }29432944 async proposalCount() {2945 return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));2946 }2947}29482949export type ChainHelperBaseConstructor = new(...args: any[]) => ChainHelperBase;2950export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;29512952export class UniqueHelper extends ChainHelperBase {2953 balance: BalanceGroup<UniqueHelper>;2954 collection: CollectionGroup;2955 nft: NFTGroup;2956 rft: RFTGroup;2957 ft: FTGroup;2958 staking: StakingGroup;2959 scheduler: SchedulerGroup;2960 foreignAssets: ForeignAssetsGroup;2961 xcm: XcmGroup<UniqueHelper>;2962 xTokens: XTokensGroup<UniqueHelper>;2963 tokens: TokensGroup<UniqueHelper>;29642965 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2966 super(logger, options.helperBase ?? UniqueHelper);29672968 this.balance = new BalanceGroup(this);2969 this.collection = new CollectionGroup(this);2970 this.nft = new NFTGroup(this);2971 this.rft = new RFTGroup(this);2972 this.ft = new FTGroup(this);2973 this.staking = new StakingGroup(this);2974 this.scheduler = new SchedulerGroup(this);2975 this.foreignAssets = new ForeignAssetsGroup(this);2976 this.xcm = new XcmGroup(this, 'polkadotXcm');2977 this.xTokens = new XTokensGroup(this);2978 this.tokens = new TokensGroup(this);2979 }29802981 getSudo<T extends UniqueHelper>() {2982 // eslint-disable-next-line @typescript-eslint/naming-convention2983 const SudoHelperType = SudoHelper(this.helperBase);2984 return this.clone(SudoHelperType) as T;2985 }2986}29872988export class XcmChainHelper extends ChainHelperBase {2989 async connect(wsEndpoint: string, _listeners?: any): Promise<void> {2990 const wsProvider = new WsProvider(wsEndpoint);2991 this.api = new ApiPromise({2992 provider: wsProvider,2993 });2994 await this.api.isReadyOrError;2995 this.network = await UniqueHelper.detectNetwork(this.api);2996 }2997}29982999export class RelayHelper extends XcmChainHelper {3000 balance: SubstrateBalanceGroup<RelayHelper>;3001 xcm: XcmGroup<RelayHelper>;30023003 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {3004 super(logger, options.helperBase ?? RelayHelper);30053006 this.balance = new SubstrateBalanceGroup(this);3007 this.xcm = new XcmGroup(this, 'xcmPallet');3008 }3009}30103011export class WestmintHelper extends XcmChainHelper {3012 balance: SubstrateBalanceGroup<WestmintHelper>;3013 xcm: XcmGroup<WestmintHelper>;3014 assets: AssetsGroup<WestmintHelper>;3015 xTokens: XTokensGroup<WestmintHelper>;30163017 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {3018 super(logger, options.helperBase ?? WestmintHelper);30193020 this.balance = new SubstrateBalanceGroup(this);3021 this.xcm = new XcmGroup(this, 'polkadotXcm');3022 this.assets = new AssetsGroup(this);3023 this.xTokens = new XTokensGroup(this);3024 }3025}30263027export class MoonbeamHelper extends XcmChainHelper {3028 balance: EthereumBalanceGroup<MoonbeamHelper>;3029 assetManager: MoonbeamAssetManagerGroup;3030 assets: AssetsGroup<MoonbeamHelper>;3031 xTokens: XTokensGroup<MoonbeamHelper>;3032 democracy: MoonbeamDemocracyGroup;3033 collective: {3034 council: MoonbeamCollectiveGroup,3035 techCommittee: MoonbeamCollectiveGroup,3036 };30373038 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {3039 super(logger, options.helperBase ?? MoonbeamHelper);30403041 this.balance = new EthereumBalanceGroup(this);3042 this.assetManager = new MoonbeamAssetManagerGroup(this);3043 this.assets = new AssetsGroup(this);3044 this.xTokens = new XTokensGroup(this);3045 this.democracy = new MoonbeamDemocracyGroup(this, options);3046 this.collective = {3047 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),3048 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),3049 };3050 }3051}30523053export class AcalaHelper extends XcmChainHelper {3054 balance: SubstrateBalanceGroup<AcalaHelper>;3055 assetRegistry: AcalaAssetRegistryGroup;3056 xTokens: XTokensGroup<AcalaHelper>;3057 tokens: TokensGroup<AcalaHelper>;30583059 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {3060 super(logger, options.helperBase ?? AcalaHelper);30613062 this.balance = new SubstrateBalanceGroup(this);3063 this.assetRegistry = new AcalaAssetRegistryGroup(this);3064 this.xTokens = new XTokensGroup(this);3065 this.tokens = new TokensGroup(this);3066 }30673068 getSudo<T extends AcalaHelper>() {3069 // eslint-disable-next-line @typescript-eslint/naming-convention3070 const SudoHelperType = SudoHelper(this.helperBase);3071 return this.clone(SudoHelperType) as T;3072 }3073}30743075// eslint-disable-next-line @typescript-eslint/naming-convention3076function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {3077 return class extends Base {3078 scheduleFn: 'schedule' | 'scheduleAfter';3079 blocksNum: number;3080 options: ISchedulerOptions;30813082 constructor(...args: any[]) {3083 const logger = args[0] as ILogger;3084 const options = args[1] as {3085 scheduleFn: 'schedule' | 'scheduleAfter',3086 blocksNum: number,3087 options: ISchedulerOptions3088 };30893090 super(logger);30913092 this.scheduleFn = options.scheduleFn;3093 this.blocksNum = options.blocksNum;3094 this.options = options.options;3095 }30963097 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {3098 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);30993100 const mandatorySchedArgs = [3101 this.blocksNum,3102 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,3103 this.options.priority ?? null,3104 scheduledTx,3105 ];31063107 let schedArgs;3108 let scheduleFn;31093110 if (this.options.scheduledId) {3111 schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];31123113 if (this.scheduleFn == 'schedule') {3114 scheduleFn = 'scheduleNamed';3115 } else if (this.scheduleFn == 'scheduleAfter') {3116 scheduleFn = 'scheduleNamedAfter';3117 }3118 } else {3119 schedArgs = mandatorySchedArgs;3120 scheduleFn = this.scheduleFn;3121 }31223123 const extrinsic = 'api.tx.scheduler.' + scheduleFn;31243125 return super.executeExtrinsic(3126 sender,3127 extrinsic,3128 schedArgs,3129 expectSuccess,3130 );3131 }3132 };3133}31343135// eslint-disable-next-line @typescript-eslint/naming-convention3136function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {3137 return class extends Base {3138 constructor(...args: any[]) {3139 super(...args);3140 }31413142 executeExtrinsic (3143 sender: IKeyringPair,3144 extrinsic: string,3145 params: any[],3146 expectSuccess?: boolean,3147 ): Promise<ITransactionResult> {3148 const call = this.constructApiCall(extrinsic, params);3149 return super.executeExtrinsic(3150 sender,3151 'api.tx.sudo.sudo',3152 [call],3153 expectSuccess,3154 );3155 }3156 };3157}31583159export class UniqueBaseCollection {3160 helper: UniqueHelper;3161 collectionId: number;31623163 constructor(collectionId: number, uniqueHelper: UniqueHelper) {3164 this.collectionId = collectionId;3165 this.helper = uniqueHelper;3166 }31673168 async getData() {3169 return await this.helper.collection.getData(this.collectionId);3170 }31713172 async getLastTokenId() {3173 return await this.helper.collection.getLastTokenId(this.collectionId);3174 }31753176 async doesTokenExist(tokenId: number) {3177 return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);3178 }31793180 async getAdmins() {3181 return await this.helper.collection.getAdmins(this.collectionId);3182 }31833184 async getAllowList() {3185 return await this.helper.collection.getAllowList(this.collectionId);3186 }31873188 async getEffectiveLimits() {3189 return await this.helper.collection.getEffectiveLimits(this.collectionId);3190 }31913192 async getProperties(propertyKeys?: string[] | null) {3193 return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3194 }31953196 async getPropertiesConsumedSpace() {3197 return await this.helper.collection.getPropertiesConsumedSpace(this.collectionId);3198 }31993200 async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3201 return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3202 }32033204 async getOptions() {3205 return await this.helper.collection.getCollectionOptions(this.collectionId);3206 }32073208 async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3209 return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3210 }32113212 async confirmSponsorship(signer: TSigner) {3213 return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3214 }32153216 async removeSponsor(signer: TSigner) {3217 return await this.helper.collection.removeSponsor(signer, this.collectionId);3218 }32193220 async setLimits(signer: TSigner, limits: ICollectionLimits) {3221 return await this.helper.collection.setLimits(signer, this.collectionId, limits);3222 }32233224 async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3225 return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3226 }32273228 async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3229 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3230 }32313232 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3233 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3234 }32353236 async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3237 return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3238 }32393240 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3241 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3242 }32433244 async setProperties(signer: TSigner, properties: IProperty[]) {3245 return await this.helper.collection.setProperties(signer, this.collectionId, properties);3246 }32473248 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3249 return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3250 }32513252 async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3253 return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3254 }32553256 async enableNesting(signer: TSigner, permissions: INestingPermissions) {3257 return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3258 }32593260 async disableNesting(signer: TSigner) {3261 return await this.helper.collection.disableNesting(signer, this.collectionId);3262 }32633264 async burn(signer: TSigner) {3265 return await this.helper.collection.burn(signer, this.collectionId);3266 }32673268 scheduleAt<T extends UniqueHelper>(3269 executionBlockNumber: number,3270 options: ISchedulerOptions = {},3271 ) {3272 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3273 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3274 }32753276 scheduleAfter<T extends UniqueHelper>(3277 blocksBeforeExecution: number,3278 options: ISchedulerOptions = {},3279 ) {3280 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3281 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3282 }32833284 getSudo<T extends UniqueHelper>() {3285 return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());3286 }3287}328832893290export class UniqueNFTCollection extends UniqueBaseCollection {3291 getTokenObject(tokenId: number) {3292 return new UniqueNFToken(tokenId, this);3293 }32943295 async getTokensByAddress(addressObj: ICrossAccountId) {3296 return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3297 }32983299 async getToken(tokenId: number, blockHashAt?: string) {3300 return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3301 }33023303 async getTokenOwner(tokenId: number, blockHashAt?: string) {3304 return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3305 }33063307 async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3308 return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3309 }33103311 async getTokenChildren(tokenId: number, blockHashAt?: string) {3312 return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3313 }33143315 async getPropertyPermissions(propertyKeys: string[] | null = null) {3316 return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3317 }33183319 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3320 return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3321 }33223323 async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3324 const api = this.helper.getApi();3325 const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON();33263327 return (props! as any).consumedSpace;3328 }33293330 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3331 return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3332 }33333334 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3335 return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3336 }33373338 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3339 return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3340 }33413342 async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3343 return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3344 }33453346 async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3347 return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3348 }33493350 async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {3351 return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3352 }33533354 async burnToken(signer: TSigner, tokenId: number) {3355 return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3356 }33573358 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3359 return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3360 }33613362 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3363 return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3364 }33653366 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3367 return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3368 }33693370 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3371 return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3372 }33733374 async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3375 return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3376 }33773378 async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3379 return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3380 }33813382 scheduleAt<T extends UniqueHelper>(3383 executionBlockNumber: number,3384 options: ISchedulerOptions = {},3385 ) {3386 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3387 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3388 }33893390 scheduleAfter<T extends UniqueHelper>(3391 blocksBeforeExecution: number,3392 options: ISchedulerOptions = {},3393 ) {3394 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3395 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3396 }33973398 getSudo<T extends UniqueHelper>() {3399 return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());3400 }3401}340234033404export class UniqueRFTCollection extends UniqueBaseCollection {3405 getTokenObject(tokenId: number) {3406 return new UniqueRFToken(tokenId, this);3407 }34083409 async getToken(tokenId: number, blockHashAt?: string) {3410 return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3411 }34123413 async getTokensByAddress(addressObj: ICrossAccountId) {3414 return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3415 }34163417 async getTop10TokenOwners(tokenId: number) {3418 return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3419 }34203421 async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3422 return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3423 }34243425 async getTokenTotalPieces(tokenId: number) {3426 return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3427 }34283429 async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3430 return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3431 }34323433 async getPropertyPermissions(propertyKeys: string[] | null = null) {3434 return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3435 }34363437 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3438 return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3439 }34403441 async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3442 const api = this.helper.getApi();3443 const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON();34443445 return (props! as any).consumedSpace;3446 }34473448 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {3449 return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3450 }34513452 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3453 return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3454 }34553456 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {3457 return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3458 }34593460 async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3461 return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3462 }34633464 async mintToken(signer: TSigner, pieces=1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3465 return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3466 }34673468 async mintMultipleTokens(signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) {3469 return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3470 }34713472 async burnToken(signer: TSigner, tokenId: number, amount=1n) {3473 return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3474 }34753476 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n) {3477 return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3478 }34793480 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3481 return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3482 }34833484 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3485 return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3486 }34873488 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3489 return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3490 }34913492 scheduleAt<T extends UniqueHelper>(3493 executionBlockNumber: number,3494 options: ISchedulerOptions = {},3495 ) {3496 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3497 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3498 }34993500 scheduleAfter<T extends UniqueHelper>(3501 blocksBeforeExecution: number,3502 options: ISchedulerOptions = {},3503 ) {3504 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3505 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3506 }35073508 getSudo<T extends UniqueHelper>() {3509 return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());3510 }3511}351235133514export class UniqueFTCollection extends UniqueBaseCollection {3515 async getBalance(addressObj: ICrossAccountId) {3516 return await this.helper.ft.getBalance(this.collectionId, addressObj);3517 }35183519 async getTotalPieces() {3520 return await this.helper.ft.getTotalPieces(this.collectionId);3521 }35223523 async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3524 return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3525 }35263527 async getTop10Owners() {3528 return await this.helper.ft.getTop10Owners(this.collectionId);3529 }35303531 async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {3532 return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3533 }35343535 async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {3536 return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3537 }35383539 async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3540 return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3541 }35423543 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3544 return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3545 }35463547 async burnTokens(signer: TSigner, amount=1n) {3548 return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3549 }35503551 async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3552 return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3553 }35543555 async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3556 return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3557 }35583559 scheduleAt<T extends UniqueHelper>(3560 executionBlockNumber: number,3561 options: ISchedulerOptions = {},3562 ) {3563 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3564 return new UniqueFTCollection(this.collectionId, scheduledHelper);3565 }35663567 scheduleAfter<T extends UniqueHelper>(3568 blocksBeforeExecution: number,3569 options: ISchedulerOptions = {},3570 ) {3571 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3572 return new UniqueFTCollection(this.collectionId, scheduledHelper);3573 }35743575 getSudo<T extends UniqueHelper>() {3576 return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());3577 }3578}357935803581export class UniqueBaseToken {3582 collection: UniqueNFTCollection | UniqueRFTCollection;3583 collectionId: number;3584 tokenId: number;35853586 constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3587 this.collection = collection;3588 this.collectionId = collection.collectionId;3589 this.tokenId = tokenId;3590 }35913592 async getNextSponsored(addressObj: ICrossAccountId) {3593 return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3594 }35953596 async getProperties(propertyKeys?: string[] | null) {3597 return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3598 }35993600 async getTokenPropertiesConsumedSpace() {3601 return await this.collection.getTokenPropertiesConsumedSpace(this.tokenId);3602 }36033604 async setProperties(signer: TSigner, properties: IProperty[]) {3605 return await this.collection.setTokenProperties(signer, this.tokenId, properties);3606 }36073608 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3609 return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3610 }36113612 async doesExist() {3613 return await this.collection.doesTokenExist(this.tokenId);3614 }36153616 nestingAccount() {3617 return this.collection.helper.util.getTokenAccount(this);3618 }36193620 scheduleAt<T extends UniqueHelper>(3621 executionBlockNumber: number,3622 options: ISchedulerOptions = {},3623 ) {3624 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3625 return new UniqueBaseToken(this.tokenId, scheduledCollection);3626 }36273628 scheduleAfter<T extends UniqueHelper>(3629 blocksBeforeExecution: number,3630 options: ISchedulerOptions = {},3631 ) {3632 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3633 return new UniqueBaseToken(this.tokenId, scheduledCollection);3634 }36353636 getSudo<T extends UniqueHelper>() {3637 return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());3638 }3639}364036413642export class UniqueNFToken extends UniqueBaseToken {3643 collection: UniqueNFTCollection;36443645 constructor(tokenId: number, collection: UniqueNFTCollection) {3646 super(tokenId, collection);3647 this.collection = collection;3648 }36493650 async getData(blockHashAt?: string) {3651 return await this.collection.getToken(this.tokenId, blockHashAt);3652 }36533654 async getOwner(blockHashAt?: string) {3655 return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3656 }36573658 async getTopmostOwner(blockHashAt?: string) {3659 return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3660 }36613662 async getChildren(blockHashAt?: string) {3663 return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3664 }36653666 async nest(signer: TSigner, toTokenObj: IToken) {3667 return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3668 }36693670 async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3671 return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3672 }36733674 async transfer(signer: TSigner, addressObj: ICrossAccountId) {3675 return await this.collection.transferToken(signer, this.tokenId, addressObj);3676 }36773678 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3679 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3680 }36813682 async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3683 return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3684 }36853686 async isApproved(toAddressObj: ICrossAccountId) {3687 return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3688 }36893690 async burn(signer: TSigner) {3691 return await this.collection.burnToken(signer, this.tokenId);3692 }36933694 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3695 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3696 }36973698 scheduleAt<T extends UniqueHelper>(3699 executionBlockNumber: number,3700 options: ISchedulerOptions = {},3701 ) {3702 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3703 return new UniqueNFToken(this.tokenId, scheduledCollection);3704 }37053706 scheduleAfter<T extends UniqueHelper>(3707 blocksBeforeExecution: number,3708 options: ISchedulerOptions = {},3709 ) {3710 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3711 return new UniqueNFToken(this.tokenId, scheduledCollection);3712 }37133714 getSudo<T extends UniqueHelper>() {3715 return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());3716 }3717}37183719export class UniqueRFToken extends UniqueBaseToken {3720 collection: UniqueRFTCollection;37213722 constructor(tokenId: number, collection: UniqueRFTCollection) {3723 super(tokenId, collection);3724 this.collection = collection;3725 }37263727 async getData(blockHashAt?: string) {3728 return await this.collection.getToken(this.tokenId, blockHashAt);3729 }37303731 async getTop10Owners() {3732 return await this.collection.getTop10TokenOwners(this.tokenId);3733 }37343735 async getBalance(addressObj: ICrossAccountId) {3736 return await this.collection.getTokenBalance(this.tokenId, addressObj);3737 }37383739 async getTotalPieces() {3740 return await this.collection.getTokenTotalPieces(this.tokenId);3741 }37423743 async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3744 return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3745 }37463747 async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {3748 return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3749 }37503751 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3752 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3753 }37543755 async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3756 return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3757 }37583759 async repartition(signer: TSigner, amount: bigint) {3760 return await this.collection.repartitionToken(signer, this.tokenId, amount);3761 }37623763 async burn(signer: TSigner, amount=1n) {3764 return await this.collection.burnToken(signer, this.tokenId, amount);3765 }37663767 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3768 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3769 }37703771 scheduleAt<T extends UniqueHelper>(3772 executionBlockNumber: number,3773 options: ISchedulerOptions = {},3774 ) {3775 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3776 return new UniqueRFToken(this.tokenId, scheduledCollection);3777 }37783779 scheduleAfter<T extends UniqueHelper>(3780 blocksBeforeExecution: number,3781 options: ISchedulerOptions = {},3782 ) {3783 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3784 return new UniqueRFToken(this.tokenId, scheduledCollection);3785 }37863787 getSudo<T extends UniqueHelper>() {3788 return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());3789 }3790}