git.delta.rocks / unique-network / refs/commits / 833ab943fbb5

difftreelog

feat merge native erc20 adapter

Yaroslav Bolyukin2023-05-30parents: #103f351 #c43c309.patch.diff
in: master

78 files changed

modifiedCargo.lockdiffbeforeafterboth
5871 "pallet-aura",5871 "pallet-aura",
5872 "pallet-authorship",5872 "pallet-authorship",
5873 "pallet-balances",5873 "pallet-balances",
5874 "pallet-balances-adapter",
5874 "pallet-base-fee",5875 "pallet-base-fee",
5875 "pallet-collator-selection",5876 "pallet-collator-selection",
5876 "pallet-common",5877 "pallet-common",
6251 "sp-std",6252 "sp-std",
6252]6253]
6254
6255[[package]]
6256name = "pallet-balances-adapter"
6257version = "0.1.0"
6258dependencies = [
6259 "evm-coder",
6260 "frame-support",
6261 "frame-system",
6262 "pallet-balances",
6263 "pallet-common",
6264 "pallet-evm",
6265 "pallet-evm-coder-substrate",
6266 "pallet-evm-transaction-payment",
6267 "pallet-structure",
6268 "parity-scale-codec",
6269 "scale-info",
6270 "sp-core",
6271 "sp-runtime",
6272 "sp-std",
6273 "up-data-structs",
6274]
62536275
6254[[package]]6276[[package]]
6255name = "pallet-base-fee"6277name = "pallet-base-fee"
6947 "frame-benchmarking",6969 "frame-benchmarking",
6948 "frame-support",6970 "frame-support",
6949 "frame-system",6971 "frame-system",
6972 "pallet-balances",
6950 "pallet-common",6973 "pallet-common",
6951 "pallet-evm",6974 "pallet-evm",
6952 "pallet-evm-coder-substrate",6975 "pallet-evm-coder-substrate",
7411 "frame-benchmarking",7434 "frame-benchmarking",
7412 "frame-support",7435 "frame-support",
7413 "frame-system",7436 "frame-system",
7437 "pallet-balances-adapter",
7414 "pallet-common",7438 "pallet-common",
7415 "pallet-evm",7439 "pallet-evm",
7416 "pallet-evm-coder-substrate",7440 "pallet-evm-coder-substrate",
9350 "pallet-aura",9374 "pallet-aura",
9351 "pallet-authorship",9375 "pallet-authorship",
9352 "pallet-balances",9376 "pallet-balances",
9377 "pallet-balances-adapter",
9353 "pallet-base-fee",9378 "pallet-base-fee",
9354 "pallet-collator-selection",9379 "pallet-collator-selection",
9355 "pallet-common",9380 "pallet-common",
12902 "frame-support",12927 "frame-support",
12903 "frame-system",12928 "frame-system",
12904 "pallet-balances",12929 "pallet-balances",
12930 "pallet-balances-adapter",
12905 "pallet-common",12931 "pallet-common",
12906 "pallet-configuration",
12907 "pallet-ethereum",12932 "pallet-ethereum",
12908 "pallet-evm",12933 "pallet-evm",
12909 "pallet-evm-coder-substrate",12934 "pallet-evm-coder-substrate",
12914 "pallet-timestamp",12939 "pallet-timestamp",
12915 "pallet-transaction-payment",12940 "pallet-transaction-payment",
12916 "pallet-unique",12941 "pallet-unique",
12917 "pallet-xcm",
12918 "parity-scale-codec",12942 "parity-scale-codec",
12919 "scale-info",12943 "scale-info",
12920 "sp-core",12944 "sp-core",
13767 "pallet-aura",13791 "pallet-aura",
13768 "pallet-authorship",13792 "pallet-authorship",
13769 "pallet-balances",13793 "pallet-balances",
13794 "pallet-balances-adapter",
13770 "pallet-base-fee",13795 "pallet-base-fee",
13771 "pallet-collator-selection",13796 "pallet-collator-selection",
13772 "pallet-common",13797 "pallet-common",
modifiedCargo.tomldiffbeforeafterboth
19panic = "unwind"19panic = "unwind"
2020
21[profile.production]21[profile.production]
22codegen-units = 1
22inherits = "release"23inherits = "release"
23lto = true24lto = true
24codegen-units = 1
25opt-level = 325opt-level = 3
2626
27[workspace.dependencies]27[workspace.dependencies]
28# Unique28# Unique
29app-promotion-rpc = { path = "primitives/app_promotion_rpc", default-features = false }29app-promotion-rpc = { path = "primitives/app_promotion_rpc", default-features = false }
30evm-coder = { git = "https://github.com/uniquenetwork/evm-coder", tag = "v0.3.1", default-features = false }30evm-coder = { git = "https://github.com/uniquenetwork/evm-coder", tag = "v0.3.1", default-features = false }
31pallet-app-promotion = { path = "pallets/app-promotion", default-features = false }31pallet-app-promotion = { path = "pallets/app-promotion", default-features = false }
32pallet-balances-adapter = { default-features = false, path = "pallets/balances-adapter" }
32pallet-charge-transaction = { package = "pallet-template-transaction-payment", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.42" }33pallet-charge-transaction = { package = "pallet-template-transaction-payment", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.42" }
33pallet-collator-selection = { default-features = false, path = "pallets/collator-selection" }34pallet-collator-selection = { default-features = false, path = "pallets/collator-selection" }
34pallet-common = { default-features = false, path = "pallets/common" }35pallet-common = { default-features = false, path = "pallets/common" }
123sc-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }124sc-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
124sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }125sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
125sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }126sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
127sc-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
126sc-consensus-manual-seal = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }128sc-consensus-manual-seal = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
127sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }129sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
128sc-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
129sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }130sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
130sc-network-sync = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }131sc-network-sync = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
131sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }132sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" }
180orml-tokens = { default-features = false , git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }181orml-tokens = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }
181orml-traits = { default-features = false , git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }182orml-traits = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }
182orml-vesting = { default-features = false , git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }183orml-vesting = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }
184orml-xcm-support = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }
183orml-xtokens = { default-features = false , git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }185orml-xtokens = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }
184orml-xcm-support = { default-features = false , git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "polkadot-v0.9.42" }
185186
186# Other187# Other
187derivative = { version = "2.2.0", features = ["use_core"] }188derivative = { version = "2.2.0", features = ["use_core"] }
modifiedMakefilediffbeforeafterboth
6 @echo " bench-evm-migration"6 @echo " bench-evm-migration"
7 @echo " bench-unique"7 @echo " bench-unique"
8
9NATIVE_FUNGIBLE_EVM_STUBS=./pallets/balances-adapter/src/stubs
10NATIVE_FUNGIBLE_EVM_ABI=./tests/src/eth/abi/nativeFungible.json
811
9FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs12FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs
10FUNGIBLE_EVM_ABI=./tests/src/eth/abi/fungible.json13FUNGIBLE_EVM_ABI=./tests/src/eth/abi/fungible.json
27.PHONY: regenerate_solidity30.PHONY: regenerate_solidity
28regenerate_solidity: UniqueFungible.sol UniqueNFT.sol UniqueRefungible.sol UniqueRefungibleToken.sol ContractHelpers.sol CollectionHelpers.sol31regenerate_solidity: UniqueFungible.sol UniqueNFT.sol UniqueRefungible.sol UniqueRefungibleToken.sol ContractHelpers.sol CollectionHelpers.sol
2932
33UniqueNativeFungible.sol:
34 PACKAGE=pallet-balances-adapter NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
35 PACKAGE=pallet-balances-adapter NAME=erc::gen_impl OUTPUT=$(NATIVE_FUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
36
30UniqueFungible.sol:37UniqueFungible.sol:
31 PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh38 PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
32 PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=$(FUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh39 PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=$(FUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
51 PACKAGE=pallet-unique NAME=eth::collection_helper_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh58 PACKAGE=pallet-unique NAME=eth::collection_helper_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
52 PACKAGE=pallet-unique NAME=eth::collection_helper_impl OUTPUT=$(COLLECTION_HELPER_STUBS)/$@ ./.maintain/scripts/generate_sol.sh59 PACKAGE=pallet-unique NAME=eth::collection_helper_impl OUTPUT=$(COLLECTION_HELPER_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
5360
61UniqueNativeFungible: UniqueNativeFungible.sol
62 INPUT=$(NATIVE_FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NATIVE_FUNGIBLE_EVM_STUBS)/UniqueNativeFungible.raw ./.maintain/scripts/compile_stub.sh
63 INPUT=$(NATIVE_FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NATIVE_FUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh
64
54UniqueFungible: UniqueFungible.sol65UniqueFungible: UniqueFungible.sol
55 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh66 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh
56 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh67 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
267pub fn development_config() -> DefaultChainSpec {267pub fn development_config() -> DefaultChainSpec {
268 let mut properties = Map::new();268 let mut properties = Map::new();
269 properties.insert("tokenSymbol".into(), default_runtime::TOKEN_SYMBOL.into());269 properties.insert("tokenSymbol".into(), default_runtime::TOKEN_SYMBOL.into());
270 properties.insert("tokenDecimals".into(), 18.into());270 properties.insert("tokenDecimals".into(), default_runtime::DECIMALS.into());
271 properties.insert(271 properties.insert(
272 "ss58Format".into(),272 "ss58Format".into(),
273 default_runtime::SS58Prefix::get().into(),273 default_runtime::SS58Prefix::get().into(),
341pub fn local_testnet_config() -> DefaultChainSpec {341pub fn local_testnet_config() -> DefaultChainSpec {
342 let mut properties = Map::new();342 let mut properties = Map::new();
343 properties.insert("tokenSymbol".into(), default_runtime::TOKEN_SYMBOL.into());343 properties.insert("tokenSymbol".into(), default_runtime::TOKEN_SYMBOL.into());
344 properties.insert("tokenDecimals".into(), 18.into());344 properties.insert("tokenDecimals".into(), default_runtime::DECIMALS.into());
345 properties.insert(345 properties.insert(
346 "ss58Format".into(),346 "ss58Format".into(),
347 default_runtime::SS58Prefix::get().into(),347 default_runtime::SS58Prefix::get().into(),
addedpallets/balances-adapter/Cargo.tomldiffbeforeafterboth

no changes

addedpallets/balances-adapter/src/common.rsdiffbeforeafterboth

no changes

addedpallets/balances-adapter/src/erc.rsdiffbeforeafterboth

no changes

addedpallets/balances-adapter/src/lib.rsdiffbeforeafterboth

no changes

addedpallets/balances-adapter/src/stubs/UniqueNativeFungible.rawdiffbeforeafterboth

binary blob — no preview

addedpallets/balances-adapter/src/stubs/UniqueNativeFungible.soldiffbeforeafterboth

no changes

modifiedpallets/common/src/dispatch.rsdiffbeforeafterboth
11use sp_runtime::DispatchError;11use sp_runtime::DispatchError;
12use up_data_structs::{CollectionId, CreateCollectionData, CollectionFlags};12use up_data_structs::{CollectionId, CreateCollectionData, CollectionFlags};
1313
14use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};14use crate::{pallet::Config, CommonCollectionOperations};
1515
16// TODO: move to benchmarking16// TODO: move to benchmarking
17/// Price of [`dispatch_tx`] call with noop `call` argument17/// Price of [`dispatch_tx`] call with noop `call` argument
34 collection: CollectionId,34 collection: CollectionId,
35 call: C,35 call: C,
36) -> DispatchResultWithPostInfo {36) -> DispatchResultWithPostInfo {
37 let handle =37 let dispatched = T::CollectionDispatch::dispatch(collection)
38 .and_then(|dispatched| {
39 dispatched.check_is_internal()?;
40 Ok(dispatched)
41 })
38 CollectionHandle::try_get(collection).map_err(|error| DispatchErrorWithPostInfo {42 .map_err(|error| DispatchErrorWithPostInfo {
39 post_info: PostDispatchInfo {43 post_info: PostDispatchInfo {
40 actual_weight: Some(dispatch_weight::<T>()),44 actual_weight: Some(dispatch_weight::<T>()),
41 pays_fee: Pays::Yes,45 pays_fee: Pays::Yes,
42 },46 },
43 error,47 error,
44 })?;48 })?;
45 handle
46 .check_is_internal()
47 .map_err(|error| DispatchErrorWithPostInfo {
48 post_info: PostDispatchInfo {
49 actual_weight: Some(dispatch_weight::<T>()),
50 pays_fee: Pays::Yes,
51 },
52 error,
53 })?;
54 let dispatched = T::CollectionDispatch::dispatch(handle);
55 let mut result = call(dispatched.as_dyn());49 let mut result = call(dispatched.as_dyn());
56 match &mut result {50 match &mut result {
57 Ok(PostDispatchInfo {51 Ok(PostDispatchInfo {
7266
73/// Interface for working with different collections through the dispatcher.67/// Interface for working with different collections through the dispatcher.
74pub trait CollectionDispatch<T: Config> {68pub trait CollectionDispatch<T: Config> {
69 /// Check if the collection is internal.
70 fn check_is_internal(&self) -> DispatchResult;
71
75 /// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode).72 /// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode).
76 ///73 ///
87 ///84 ///
88 /// * `sender` - The owner of the collection.85 /// * `sender` - The owner of the collection.
89 /// * `handle` - Collection handle.86 /// * `handle` - Collection handle.
90 fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;87 fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult;
9188
92 /// Get a specialized collection from the handle.89 /// Get a specialized collection from the handle.
93 ///90 ///
94 /// * `handle` - Collection handle.91 /// * `handle` - Collection handle.
95 fn dispatch(handle: CollectionHandle<T>) -> Self;92 fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError>
9693 where
97 /// Get the collection handle for the corresponding implementation.94 Self: Sized;
98 fn into_inner(self) -> CollectionHandle<T>;
9995
100 /// Get the implementation of [`CommonCollectionOperations`].96 /// Get the implementation of [`CommonCollectionOperations`].
101 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;97 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
72 dispatch::Pays,72 dispatch::Pays,
73 transactional, fail,73 transactional, fail,
74};74};
75use pallet_evm::GasWeightMapping;
76use up_data_structs::{75use up_data_structs::{
77 AccessMode, COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionFlags,76 AccessMode, COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionFlags,
78 RpcCollectionFlags, CollectionId, CreateItemData, MAX_TOKEN_PREFIX_LENGTH,77 RpcCollectionFlags, CollectionId, CreateItemData, MAX_TOKEN_PREFIX_LENGTH,
105/// Collection handle contains information about collection data and id.104/// Collection handle contains information about collection data and id.
106/// Also provides functionality to count consumed gas.105/// Also provides functionality to count consumed gas.
107///106///
108/// CollectionHandle is used as a generic wrapper for collections of all types.107/// CollectionHandle is used as a generic wrapper for collections of all types (except native fungible).
109/// It allows to perform common operations and queries on any collection type,108/// It allows to perform common operations and queries on any collection type,
110/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].109/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].
111#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]110#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]
129impl<T: Config> CollectionHandle<T> {128impl<T: Config> CollectionHandle<T> {
130 /// Same as [CollectionHandle::new] but with an explicit gas limit.129 /// Same as [CollectionHandle::new] but with an explicit gas limit.
131 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {130 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {
132 <CollectionById<T>>::get(id).map(|collection| Self {131 Self::new_with_recorder(id, SubstrateRecorder::new(gas_limit))
133 id,
134 collection,
135 recorder: SubstrateRecorder::new(gas_limit),
136 })
137 }132 }
138133
139 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].134 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].
161 &self,156 &self,
162 reads: u64,157 reads: u64,
163 ) -> pallet_evm_coder_substrate::execution::Result<()> {158 ) -> pallet_evm_coder_substrate::execution::Result<()> {
164 self.recorder159 self.recorder().consume_store_reads(reads)
165 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts(
166 <T as frame_system::Config>::DbWeight::get()
167 .read
168 .saturating_mul(reads),
169 // TODO: measure proof
170 0,
171 )))
172 }160 }
173161
174 /// Consume gas for writing.162 /// Consume gas for writing.
175 pub fn consume_store_writes(163 pub fn consume_store_writes(
176 &self,164 &self,
177 writes: u64,165 writes: u64,
178 ) -> pallet_evm_coder_substrate::execution::Result<()> {166 ) -> pallet_evm_coder_substrate::execution::Result<()> {
179 self.recorder167 self.recorder().consume_store_writes(writes)
180 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts(
181 <T as frame_system::Config>::DbWeight::get()
182 .write
183 .saturating_mul(writes),
184 // TODO: measure proof
185 0,
186 )))
187 }168 }
188169
189 /// Consume gas for reading and writing.170 /// Consume gas for reading and writing.
192 reads: u64,173 reads: u64,
193 writes: u64,174 writes: u64,
194 ) -> pallet_evm_coder_substrate::execution::Result<()> {175 ) -> pallet_evm_coder_substrate::execution::Result<()> {
195 let weight = <T as frame_system::Config>::DbWeight::get();
196 let reads = weight.read.saturating_mul(reads);
197 let writes = weight.read.saturating_mul(writes);
198 self.recorder176 self.recorder()
199 .consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts(177 .consume_store_reads_and_writes(reads, writes)
200 reads.saturating_add(writes),
201 // TODO: measure proof
202 0,
203 )))
204 }178 }
205179
206 /// Save collection to storage.180 /// Save collection to storage.
469 }443 }
470444
471 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);445 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
446 /// Collection id for native fungible collction.
447 pub const NATIVE_FUNGIBLE_COLLECTION_ID: CollectionId = CollectionId(0);
472448
473 #[pallet::pallet]449 #[pallet::pallet]
474 #[pallet::storage_version(STORAGE_VERSION)]450 #[pallet::storage_version(STORAGE_VERSION)]
modifiedpallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth
37 ExitError, ExitRevert, ExitSucceed, GasWeightMapping, PrecompileFailure, PrecompileOutput,37 ExitError, ExitRevert, ExitSucceed, GasWeightMapping, PrecompileFailure, PrecompileOutput,
38 PrecompileResult, PrecompileHandle,38 PrecompileResult, PrecompileHandle,
39};39};
40use sp_core::H160;40use sp_core::{Get, H160};
41// #[cfg(feature = "runtime-benchmarks")]41// #[cfg(feature = "runtime-benchmarks")]
42// pub mod benchmarking;42// pub mod benchmarking;
43pub mod execution;43pub mod execution;
205 })205 })
206 }206 }
207
208 /// Consume gas for reading.
209 pub fn consume_store_reads(&self, reads: u64) -> execution::Result<()> {
210 self.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts(
211 <T as frame_system::Config>::DbWeight::get()
212 .read
213 .saturating_mul(reads),
214 // TODO: measure proof
215 0,
216 )))
217 }
218
219 /// Consume gas for writing.
220 pub fn consume_store_writes(&self, writes: u64) -> execution::Result<()> {
221 self.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts(
222 <T as frame_system::Config>::DbWeight::get()
223 .write
224 .saturating_mul(writes),
225 // TODO: measure proof
226 0,
227 )))
228 }
229
230 /// Consume gas for reading and writing.
231 pub fn consume_store_reads_and_writes(&self, reads: u64, writes: u64) -> execution::Result<()> {
232 let weight = <T as frame_system::Config>::DbWeight::get();
233 let reads = weight.read.saturating_mul(reads);
234 let writes = weight.read.saturating_mul(writes);
235 self.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts(
236 reads.saturating_add(writes),
237 // TODO: measure proof
238 0,
239 )))
240 }
207}241}
208242
209pub fn dispatch_to_evm<T: Config>(err: DispatchError) -> execution::Error {243pub fn dispatch_to_evm<T: Config>(err: DispatchError) -> execution::Error {
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
109 .recorder109 .recorder
110 .weight_calls_budget(<StructureWeight<T>>::find_parent());110 .weight_calls_budget(<StructureWeight<T>>::find_parent());
111111
112 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;112 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget)
113 .map_err(|e| dispatch_to_evm::<T>(e.error))?;
113 Ok(true)114 Ok(true)
114 }115 }
115116
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
12frame-benchmarking = { workspace = true, optional = true }12frame-benchmarking = { workspace = true, optional = true }
13frame-support = { workspace = true }13frame-support = { workspace = true }
14frame-system = { workspace = true }14frame-system = { workspace = true }
15pallet-balances = { workspace = true }
15pallet-common = { workspace = true }16pallet-common = { workspace = true }
16pallet-evm = { workspace = true }17pallet-evm = { workspace = true }
17pallet-evm-coder-substrate = { workspace = true }18pallet-evm-coder-substrate = { workspace = true }
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
170 + pallet_common::Config
171 + pallet_structure::Config
172 + pallet_evm::Config
173 + pallet_balances::Config
170 {174 {
171 type WeightInfo: WeightInfo;175 type WeightInfo: WeightInfo;
172 }176 }
1325 }1329 }
13261330
1327 fn nest(under: (CollectionId, TokenId), to_nest: (CollectionId, TokenId)) {1331 fn nest(under: (CollectionId, TokenId), to_nest: (CollectionId, TokenId)) {
1332 if to_nest.0 != pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
1328 <TokenChildren<T>>::insert((under.0, under.1, (to_nest.0, to_nest.1)), true);1333 <TokenChildren<T>>::insert((under.0, under.1, to_nest), true);
1334 }
1329 }1335 }
13301336
1331 fn unnest(under: (CollectionId, TokenId), to_unnest: (CollectionId, TokenId)) {1337 fn unnest(under: (CollectionId, TokenId), to_unnest: (CollectionId, TokenId)) {
1338 if to_unnest.0 != pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
1332 <TokenChildren<T>>::remove((under.0, under.1, to_unnest));1339 <TokenChildren<T>>::remove((under.0, under.1, to_unnest));
1333 }1340 }
1341 }
13341342
1335 fn collection_has_tokens(collection_id: CollectionId) -> bool {1343 fn collection_has_tokens(collection_id: CollectionId) -> bool {
modifiedpallets/structure/src/benchmarking.rsdiffbeforeafterboth
42 },42 },
43 CollectionFlags::default(),43 CollectionFlags::default(),
44 )?;44 )?;
45 let dispatch = T::CollectionDispatch::dispatch(CollectionHandle::try_get(CollectionId(1))?);45 let dispatch = T::CollectionDispatch::dispatch(CollectionId(1))?;
46 let dispatch = dispatch.as_dyn();46 let dispatch = dispatch.as_dyn();
4747
48 dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()), &Unlimited)?;48 dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()), &Unlimited)?;
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
60use frame_support::dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo};60use frame_support::dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo};
61use frame_support::fail;61use frame_support::fail;
62pub use pallet::*;62pub use pallet::*;
63use pallet_common::{dispatch::CollectionDispatch, CollectionHandle};63use pallet_common::{dispatch::CollectionDispatch};
64use up_data_structs::{64use up_data_structs::{
65 CollectionId, TokenId, mapping::TokenAddressMapping, budget::Budget, TokenOwnerError,65 CollectionId, TokenId, mapping::TokenAddressMapping, budget::Budget, TokenOwnerError,
66};66};
155 token: TokenId,155 token: TokenId,
156 ) -> Result<Parent<T::CrossAccountId>, DispatchError> {156 ) -> Result<Parent<T::CrossAccountId>, DispatchError> {
157 // TODO: Reduce cost by not reading collection config157 // TODO: Reduce cost by not reading collection config
158 let handle = match CollectionHandle::try_get(collection) {158 let handle = match T::CollectionDispatch::dispatch(collection) {
159 Ok(v) => v,159 Ok(v) => v,
160 Err(_) => return Ok(Parent::TokenNotFound),160 Err(_) => return Ok(Parent::TokenNotFound),
161 };161 };
162 let handle = T::CollectionDispatch::dispatch(handle);
163 let handle = handle.as_dyn();162 let handle = handle.as_dyn();
164163
165 Ok(match handle.token_owner(token) {164 Ok(match handle.token_owner(token) {
279 self_budget: &dyn Budget,278 self_budget: &dyn Budget,
280 breadth_budget: &dyn Budget,279 breadth_budget: &dyn Budget,
281 ) -> DispatchResultWithPostInfo {280 ) -> DispatchResultWithPostInfo {
282 let handle = <CollectionHandle<T>>::try_get(collection)?;
283 let dispatch = T::CollectionDispatch::dispatch(handle);281 let dispatch = T::CollectionDispatch::dispatch(collection)?;
284 let dispatch = dispatch.as_dyn();282 let dispatch = dispatch.as_dyn();
285 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)283 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)
286 }284 }
405 return Ok(())403 return Ok(())
406 };404 };
407
408 let handle = <CollectionHandle<T>>::try_get(collection)?;
409405
410 let dispatch = T::CollectionDispatch::dispatch(handle);406 let dispatch = T::CollectionDispatch::dispatch(collection)?;
411 let dispatch = dispatch.as_dyn();407 let dispatch = dispatch.as_dyn();
412408
413 action(dispatch, token)409 action(dispatch, token)
modifiedpallets/unique/Cargo.tomldiffbeforeafterboth
24 'frame-benchmarking/std',24 'frame-benchmarking/std',
25 'frame-support/std',25 'frame-support/std',
26 'frame-system/std',26 'frame-system/std',
27 'pallet-balances-adapter/std',
27 'pallet-common/std',28 'pallet-common/std',
28 'pallet-evm-coder-substrate/std',29 'pallet-evm-coder-substrate/std',
29 'pallet-evm/std',30 'pallet-evm/std',
46frame-benchmarking = { workspace = true, optional = true }47frame-benchmarking = { workspace = true, optional = true }
47frame-support = { workspace = true }48frame-support = { workspace = true }
48frame-system = { workspace = true }49frame-system = { workspace = true }
50pallet-balances-adapter = { workspace = true }
49pallet-common = { workspace = true }51pallet-common = { workspace = true }
50pallet-evm = { workspace = true }52pallet-evm = { workspace = true }
51pallet-evm-coder-substrate = { workspace = true }53pallet-evm-coder-substrate = { workspace = true }
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
440 collection_id: CollectionId,440 collection_id: CollectionId,
441 address: T::CrossAccountId,441 address: T::CrossAccountId,
442 ) -> DispatchResult {442 ) -> DispatchResult {
443 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
444 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
445 }
446
443 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);447 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
444 let collection = <CollectionHandle<T>>::try_get(collection_id)?;448 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
467 collection_id: CollectionId,471 collection_id: CollectionId,
468 address: T::CrossAccountId,472 address: T::CrossAccountId,
469 ) -> DispatchResult {473 ) -> DispatchResult {
474 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
475 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
476 }
477
470 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);478 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
471 let collection = <CollectionHandle<T>>::try_get(collection_id)?;479 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
493 collection_id: CollectionId,501 collection_id: CollectionId,
494 new_owner: T::AccountId,502 new_owner: T::AccountId,
495 ) -> DispatchResult {503 ) -> DispatchResult {
504 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
505 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
506 }
496 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);507 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
497 let new_owner = T::CrossAccountId::from_sub(new_owner);508 let new_owner = T::CrossAccountId::from_sub(new_owner);
498 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;509 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
522 collection_id: CollectionId,533 collection_id: CollectionId,
523 new_admin_id: T::CrossAccountId,534 new_admin_id: T::CrossAccountId,
524 ) -> DispatchResult {535 ) -> DispatchResult {
536 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
537 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
538 }
525 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);539 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
526 let collection = <CollectionHandle<T>>::try_get(collection_id)?;540 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
527 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)541 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)
548 collection_id: CollectionId,562 collection_id: CollectionId,
549 account_id: T::CrossAccountId,563 account_id: T::CrossAccountId,
550 ) -> DispatchResult {564 ) -> DispatchResult {
565 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
566 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
567 }
551 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);568 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
552 let collection = <CollectionHandle<T>>::try_get(collection_id)?;569 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
553 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)570 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)
573 collection_id: CollectionId,590 collection_id: CollectionId,
574 new_sponsor: T::AccountId,591 new_sponsor: T::AccountId,
575 ) -> DispatchResult {592 ) -> DispatchResult {
593 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
594 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
595 }
576 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);596 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
577 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;597 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
578 target_collection.set_sponsor(&sender, new_sponsor.clone())598 target_collection.set_sponsor(&sender, new_sponsor.clone())
597 origin: OriginFor<T>,617 origin: OriginFor<T>,
598 collection_id: CollectionId,618 collection_id: CollectionId,
599 ) -> DispatchResult {619 ) -> DispatchResult {
620 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
621 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
622 }
600 let sender = ensure_signed(origin)?;623 let sender = ensure_signed(origin)?;
601 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;624 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
602 target_collection.confirm_sponsorship(&sender)625 target_collection.confirm_sponsorship(&sender)
617 origin: OriginFor<T>,640 origin: OriginFor<T>,
618 collection_id: CollectionId,641 collection_id: CollectionId,
619 ) -> DispatchResult {642 ) -> DispatchResult {
643 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
644 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
645 }
620 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);646 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
621 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;647 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
622 target_collection.remove_sponsor(&sender)648 target_collection.remove_sponsor(&sender)
894 collection_id: CollectionId,920 collection_id: CollectionId,
895 value: bool,921 value: bool,
896 ) -> DispatchResult {922 ) -> DispatchResult {
923 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
924 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
925 }
897 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);926 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
898 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;927 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
899 target_collection.check_is_internal()?;928 target_collection.check_is_internal()?;
1146 collection_id: CollectionId,1175 collection_id: CollectionId,
1147 new_limit: CollectionLimits,1176 new_limit: CollectionLimits,
1148 ) -> DispatchResult {1177 ) -> DispatchResult {
1178 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
1179 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
1180 }
1149 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1181 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
1150 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1182 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
1151 <PalletCommon<T>>::update_limits(&sender, &mut target_collection, new_limit)1183 <PalletCommon<T>>::update_limits(&sender, &mut target_collection, new_limit)
1170 collection_id: CollectionId,1202 collection_id: CollectionId,
1171 new_permission: CollectionPermissions,1203 new_permission: CollectionPermissions,
1172 ) -> DispatchResult {1204 ) -> DispatchResult {
1205 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
1206 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
1207 }
1173 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1208 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
1174 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1209 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
1175 <PalletCommon<T>>::update_permissions(&sender, &mut target_collection, new_permission)1210 <PalletCommon<T>>::update_permissions(&sender, &mut target_collection, new_permission)
1238 origin: OriginFor<T>,1273 origin: OriginFor<T>,
1239 collection_id: CollectionId,1274 collection_id: CollectionId,
1240 ) -> DispatchResult {1275 ) -> DispatchResult {
1276 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
1277 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
1278 }
1241 ensure_root(origin)?;1279 ensure_root(origin)?;
1242 <PalletCommon<T>>::repair_collection(collection_id)1280 <PalletCommon<T>>::repair_collection(collection_id)
1243 }1281 }
1296 sender: T::CrossAccountId,1334 sender: T::CrossAccountId,
1297 collection_id: CollectionId,1335 collection_id: CollectionId,
1298 ) -> DispatchResult {1336 ) -> DispatchResult {
1299 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
1300 collection.check_is_internal()?;
1301
1302 T::CollectionDispatch::destroy(sender, collection)?;1337 T::CollectionDispatch::destroy(sender, collection_id)?;
13031338
1304 // TODO: basket cleanup should be moved elsewhere1339 // TODO: basket cleanup should be moved elsewhere
1305 // Maybe runtime dispatch.rs should perform it?1340 // Maybe runtime dispatch.rs should perform it?
modifiedruntime/common/config/pallets/mod.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17use alloc::string::{String, ToString};
17use frame_support::parameter_types;18use frame_support::parameter_types;
18use sp_runtime::traits::AccountIdConversion;19use sp_runtime::traits::AccountIdConversion;
19use crate::{20use crate::{
23 weights::CommonWeights,24 weights::CommonWeights,
24 RelayChainBlockNumberProvider,25 RelayChainBlockNumberProvider,
25 },26 },
26 Runtime, RuntimeEvent, RuntimeCall, RuntimeOrigin, Balances,27 Runtime, RuntimeEvent, RuntimeCall, RuntimeOrigin, RUNTIME_NAME, TOKEN_SYMBOL, DECIMALS,
28 Balances,
27};29};
28use frame_support::traits::{ConstU32, ConstU64};30use frame_support::traits::{ConstU32, ConstU64, Currency};
29use up_common::{31use up_common::{
30 types::{AccountId, Balance, BlockNumber},32 types::{AccountId, Balance, BlockNumber},
31 constants::*,33 constants::*,
51pub mod preimage;53pub mod preimage;
5254
53parameter_types! {55parameter_types! {
56 pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
54 pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();57 pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
55 pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
56}58}
5759
58impl pallet_common::Config for Runtime {60impl pallet_common::Config for Runtime {
84 type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;86 type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
85}87}
88
89parameter_types! {
90 pub const Decimals: u8 = DECIMALS;
91 pub Name: String = RUNTIME_NAME.to_string();
92 pub Symbol: String = TOKEN_SYMBOL.to_string();
93}
94impl pallet_balances_adapter::Config for Runtime {
95 type Inspect = Balances;
96 type Mutate = Balances;
97 type CurrencyBalance = <Balances as Currency<Self::AccountId>>::Balance;
98 type Decimals = Decimals;
99 type Name = Name;
100 type Symbol = Symbol;
101 type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
102}
86103
87parameter_types! {104parameter_types! {
88 pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied105 pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
modifiedruntime/common/construct_runtime.rsdiffbeforeafterboth
106106
107 Maintenance: pallet_maintenance = 154,107 Maintenance: pallet_maintenance = 154,
108
109 BalancesAdapter: pallet_balances_adapter = 155,
108110
109 #[cfg(feature = "pallet-test-utils")]111 #[cfg(feature = "pallet-test-utils")]
110 TestUtils: pallet_test_utils = 255,112 TestUtils: pallet_test_utils = 255,
modifiedruntime/common/dispatch.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17use frame_support::{dispatch::DispatchResult, ensure};17use frame_support::{dispatch::DispatchResult, ensure, fail};
18use pallet_evm::{PrecompileHandle, PrecompileResult};18use pallet_evm::{PrecompileHandle, PrecompileResult};
19use sp_core::H160;19use sp_core::H160;
20use sp_runtime::DispatchError;20use sp_runtime::DispatchError;
25};25};
26pub use pallet_common::dispatch::CollectionDispatch;26pub use pallet_common::dispatch::CollectionDispatch;
27use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};27use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
28use pallet_balances_adapter::{NativeFungibleHandle};
28use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};29use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
29use pallet_refungible::{30use pallet_refungible::{
30 Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,31 Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,
42 T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,43 T: pallet_fungible::Config
44 + pallet_nonfungible::Config
45 + pallet_refungible::Config
46 + pallet_balances_adapter::Config,
43{47{
44 Fungible(FungibleHandle<T>),48 Fungible(FungibleHandle<T>),
45 Nonfungible(NonfungibleHandle<T>),49 Nonfungible(NonfungibleHandle<T>),
46 Refungible(RefungibleHandle<T>),50 Refungible(RefungibleHandle<T>),
51 NativeFungible(NativeFungibleHandle<T>),
47}52}
53
48impl<T> CollectionDispatch<T> for CollectionDispatchT<T>54impl<T> CollectionDispatch<T> for CollectionDispatchT<T>
49where55where
50 T: pallet_common::Config56 T: pallet_common::Config
51 + pallet_unique::Config57 + pallet_unique::Config
52 + pallet_fungible::Config58 + pallet_fungible::Config
53 + pallet_nonfungible::Config59 + pallet_nonfungible::Config
54 + pallet_refungible::Config,60 + pallet_refungible::Config
61 + pallet_balances_adapter::Config,
55{62{
63 fn check_is_internal(&self) -> DispatchResult {
64 match self {
65 Self::Fungible(h) => h.check_is_internal(),
66 Self::Nonfungible(h) => h.check_is_internal(),
67 Self::Refungible(h) => h.check_is_internal(),
68 Self::NativeFungible(h) => h.check_is_internal(),
69 }
70 }
71
56 fn create(72 fn create(
57 sender: T::CrossAccountId,73 sender: T::CrossAccountId,
83 Ok(id)99 Ok(id)
84 }100 }
85101
86 fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {102 fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult {
103 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
104 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
105 }
106
107 let collection = <CollectionHandle<T>>::try_get(collection_id)?;
108
87 match collection.mode {109 match collection.mode {
88 CollectionMode::ReFungible => {110 CollectionMode::ReFungible => {
98 Ok(())120 Ok(())
99 }121 }
100122
101 fn dispatch(handle: CollectionHandle<T>) -> Self {123 fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError> {
124 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
125 return Ok(Self::NativeFungible(
126 NativeFungibleHandle::new_with_gas_limit(u64::MAX),
127 ));
128 }
129
130 let handle = <CollectionHandle<T>>::try_get(collection_id)?;
102 match handle.mode {131 Ok(match handle.mode {
103 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),132 CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),
104 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),133 CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),
105 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),134 CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),
106 }135 })
107 }136 }
108
109 fn into_inner(self) -> CollectionHandle<T> {
110 match self {
111 Self::Fungible(f) => f.into_inner(),
112 Self::Nonfungible(f) => f.into_inner(),
113 Self::Refungible(f) => f.into_inner(),
114 }
115 }
116137
117 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {138 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {
118 match self {139 match self {
119 Self::Fungible(h) => h,140 Self::Fungible(h) => h,
120 Self::Nonfungible(h) => h,141 Self::Nonfungible(h) => h,
121 Self::Refungible(h) => h,142 Self::Refungible(h) => h,
143 Self::NativeFungible(h) => h,
122 }144 }
123 }145 }
124}146}
130 + pallet_fungible::Config152 + pallet_fungible::Config
131 + pallet_nonfungible::Config153 + pallet_nonfungible::Config
132 + pallet_refungible::Config,154 + pallet_refungible::Config
155 + pallet_balances_adapter::Config,
133 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,156 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
134{157{
135 fn is_reserved(target: &H160) -> bool {158 fn is_reserved(target: &H160) -> bool {
166 }189 }
167 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {190 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
168 if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {191 if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {
192 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {
193 <NativeFungibleHandle<T>>::new_with_gas_limit(handle.remaining_gas()).call(handle)
194 } else {
169 let collection =195 let collection = <CollectionHandle<T>>::new_with_gas_limit(
170 <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;196 collection_id,
171 let dispatched = Self::dispatch(collection);197 handle.remaining_gas(),
198 )?;
172199
173 match dispatched {200 match collection.mode {
174 Self::Fungible(h) => h.call(handle),201 CollectionMode::Fungible(_) => FungibleHandle::cast(collection).call(handle),
175 Self::Nonfungible(h) => h.call(handle),202 CollectionMode::NFT => NonfungibleHandle::cast(collection).call(handle),
176 Self::Refungible(h) => h.call(handle),203 CollectionMode::ReFungible => RefungibleHandle::cast(collection).call(handle),
177 }204 }
205 }
178 } else if let Some((collection_id, token_id)) =206 } else if let Some((collection_id, token_id)) =
179 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(207 <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(
180 &handle.code_address(),208 &handle.code_address(),
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
17#[macro_export]17#[macro_export]
18macro_rules! dispatch_unique_runtime {18macro_rules! dispatch_unique_runtime {
19 ($collection:ident.$method:ident($($name:ident),*) $($rest:tt)*) => {{19 ($collection:ident.$method:ident($($name:ident),*) $($rest:tt)*) => {{
20 let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);20 let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch($collection)?;
21 let dispatch = collection.as_dyn();21 let dispatch = collection.as_dyn();
2222
23 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)23 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)
modifiedruntime/common/weights/mod.rsdiffbeforeafterboth
18use frame_support::{weights::Weight};18use frame_support::{weights::Weight};
19use pallet_common::{CommonWeightInfo, dispatch::dispatch_weight, RefungibleExtensionsWeightInfo};19use pallet_common::{CommonWeightInfo, dispatch::dispatch_weight, RefungibleExtensionsWeightInfo};
2020
21use pallet_balances_adapter::{
22 Config as NativeFungibleConfig, common::CommonWeights as NativeFungibleWeights,
23};
21use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};24use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};
22use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};25use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};
2326
32macro_rules! max_weight_of {35macro_rules! max_weight_of {
33 ($method:ident ( $($args:tt)* )) => {{36 ($method:ident ( $($args:tt)* )) => {{
34 let max_weight = <FungibleWeights<T>>::$method($($args)*)37 let max_weight = <FungibleWeights<T>>::$method($($args)*)
38 .max(<NativeFungibleWeights<T>>::$method($($args)*))
35 .max(<NonfungibleWeights<T>>::$method($($args)*));39 .max(<NonfungibleWeights<T>>::$method($($args)*));
3640
37 #[cfg(feature = "refungible")]41 #[cfg(feature = "refungible")]
42}46}
4347
44#[cfg(not(feature = "refungible"))]48#[cfg(not(feature = "refungible"))]
45pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig {}49pub trait CommonWeightConfigs: FungibleConfig + NativeFungibleConfig + NonfungibleConfig {}
4650
47#[cfg(not(feature = "refungible"))]51#[cfg(not(feature = "refungible"))]
48impl<T: FungibleConfig + NonfungibleConfig> CommonWeightConfigs for T {}52impl<T: FungibleConfig + NativeFungibleConfig + NonfungibleConfig> CommonWeightConfigs for T {}
4953
50#[cfg(feature = "refungible")]54#[cfg(feature = "refungible")]
51pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig + RefungibleConfig {}55pub trait CommonWeightConfigs:
56 FungibleConfig + NativeFungibleConfig + NonfungibleConfig + RefungibleConfig
57{
58}
5259
53#[cfg(feature = "refungible")]60#[cfg(feature = "refungible")]
54impl<T: FungibleConfig + NonfungibleConfig + RefungibleConfig> CommonWeightConfigs for T {}61impl<T: FungibleConfig + NativeFungibleConfig + NonfungibleConfig + RefungibleConfig>
62 CommonWeightConfigs for T
63{
64}
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
18[features]18[features]
19default = ['opal-runtime', 'std']19default = ['opal-runtime', 'std']
20limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']20limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
21opal-runtime = ['app-promotion', 'collator-selection', 'foreign-assets', 'preimage', 'pallet-test-utils', 'refungible']21opal-runtime = ['app-promotion', 'collator-selection', 'foreign-assets', 'pallet-test-utils', 'preimage', 'refungible']
22pov-estimate = []22pov-estimate = []
23runtime-benchmarks = [23runtime-benchmarks = [
24 "pallet-preimage/runtime-benchmarks",
24 'cumulus-pallet-parachain-system/runtime-benchmarks',25 'cumulus-pallet-parachain-system/runtime-benchmarks',
25 'frame-benchmarking',26 'frame-benchmarking',
26 'frame-support/runtime-benchmarks',27 'frame-support/runtime-benchmarks',
41 'pallet-inflation/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',
42 'pallet-maintenance/runtime-benchmarks',43 'pallet-maintenance/runtime-benchmarks',
43 'pallet-nonfungible/runtime-benchmarks',44 'pallet-nonfungible/runtime-benchmarks',
44 "pallet-preimage/runtime-benchmarks",
45 'pallet-refungible/runtime-benchmarks',45 'pallet-refungible/runtime-benchmarks',
46 'pallet-structure/runtime-benchmarks',46 'pallet-structure/runtime-benchmarks',
47 'pallet-timestamp/runtime-benchmarks',47 'pallet-timestamp/runtime-benchmarks',
70 # 'pallet-contracts-primitives/std',70 # 'pallet-contracts-primitives/std',
71 # 'pallet-contracts-rpc-runtime-api/std',71 # 'pallet-contracts-rpc-runtime-api/std',
72 # 'pallet-contract-helpers/std',72 # 'pallet-contract-helpers/std',
73 "pallet-authorship/std",
73 "pallet-preimage/std",74 "pallet-preimage/std",
74 "pallet-authorship/std",
75 "pallet-session/std",75 "pallet-session/std",
76 "sp-consensus-aura/std",76 "sp-consensus-aura/std",
77 'app-promotion-rpc/std',77 'app-promotion-rpc/std',
78 'evm-coder/std',78 'evm-coder/std',
79 'fp-rpc/std',79 'fp-rpc/std',
80 'fp-self-contained/std',80 'fp-self-contained/std',
81 'pallet-app-promotion/std',81 'pallet-app-promotion/std',
82 'pallet-balances-adapter/std',
82 'pallet-base-fee/std',83 'pallet-base-fee/std',
83 'pallet-charge-transaction/std',84 'pallet-charge-transaction/std',
84 'pallet-collator-selection/std',85 'pallet-collator-selection/std',
128 "orml-tokens/std",129 "orml-tokens/std",
129 "orml-traits/std",130 "orml-traits/std",
130 "orml-vesting/std",131 "orml-vesting/std",
132 "orml-xcm-support/std",
131 "orml-xtokens/std",133 "orml-xtokens/std",
132 "orml-xcm-support/std",
133 "pallet-foreign-assets/std",134 "pallet-foreign-assets/std",
134135
135 'pallet-maintenance/std',136 'pallet-maintenance/std',
139 "pallet-authorship/try-runtime",140 "pallet-authorship/try-runtime",
140 "pallet-collator-selection/try-runtime",141 "pallet-collator-selection/try-runtime",
141 "pallet-identity/try-runtime",142 "pallet-identity/try-runtime",
143 "pallet-preimage/try-runtime",
142 "pallet-session/try-runtime",144 "pallet-session/try-runtime",
143 "pallet-preimage/try-runtime",
144 'cumulus-pallet-aura-ext/try-runtime',145 'cumulus-pallet-aura-ext/try-runtime',
145 'cumulus-pallet-dmp-queue/try-runtime',146 'cumulus-pallet-dmp-queue/try-runtime',
146 'cumulus-pallet-parachain-system/try-runtime',147 'cumulus-pallet-parachain-system/try-runtime',
158 'pallet-app-promotion/try-runtime',159 'pallet-app-promotion/try-runtime',
159 'pallet-aura/try-runtime',160 'pallet-aura/try-runtime',
160 'pallet-balances/try-runtime',161 'pallet-balances/try-runtime',
162 'pallet-balances-adapter/try-runtime',
161 'pallet-base-fee/try-runtime',163 'pallet-base-fee/try-runtime',
162 'pallet-charge-transaction/try-runtime',164 'pallet-charge-transaction/try-runtime',
163 'pallet-common/try-runtime',165 'pallet-common/try-runtime',
189app-promotion = []191app-promotion = []
190collator-selection = []192collator-selection = []
191foreign-assets = []193foreign-assets = []
192preimage = []194pallet-test-utils = []
193pallet-test-utils = []195preimage = []
194refungible = []196refungible = []
195scheduler = []197scheduler = []
196198
216orml-tokens = { workspace = true }218orml-tokens = { workspace = true }
217orml-traits = { workspace = true }219orml-traits = { workspace = true }
218orml-vesting = { workspace = true }220orml-vesting = { workspace = true }
219orml-xtokens = { workspace = true }221orml-xcm-support = { workspace = true }
220orml-xcm-support = { workspace = true }222orml-xtokens = { workspace = true }
221pallet-aura = { workspace = true }223pallet-aura = { workspace = true }
222pallet-authorship = { workspace = true }224pallet-authorship = { workspace = true }
223pallet-balances = { features = ["insecure_zero_ed"], workspace = true }225pallet-balances = { features = ["insecure_zero_ed"], workspace = true }
258log = { workspace = true }260log = { workspace = true }
259num_enum = { workspace = true }261num_enum = { workspace = true }
260pallet-app-promotion = { workspace = true }262pallet-app-promotion = { workspace = true }
263pallet-balances-adapter = { workspace = true }
261pallet-base-fee = { workspace = true }264pallet-base-fee = { workspace = true }
262pallet-charge-transaction = { workspace = true }265pallet-charge-transaction = { workspace = true }
263pallet-collator-selection = { workspace = true }266pallet-collator-selection = { workspace = true }
291################################################################################294################################################################################
292# Optional dependencies295# Optional dependencies
293296
297frame-benchmarking = { workspace = true, optional = true }
294frame-system-benchmarking = { workspace = true, optional = true}298frame-system-benchmarking = { workspace = true, optional = true }
295frame-benchmarking = { workspace = true, optional = true }
296frame-try-runtime = { workspace = true, optional = true }299frame-try-runtime = { workspace = true, optional = true }
300hex-literal = { workspace = true, optional = true }
297serde = { workspace = true, optional = true }301serde = { workspace = true, optional = true }
298hex-literal = { workspace = true, optional = true }
299302
300################################################################################303################################################################################
301# Test dependencies304# Test dependencies
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
4545
46pub const RUNTIME_NAME: &str = "opal";46pub const RUNTIME_NAME: &str = "opal";
47pub const TOKEN_SYMBOL: &str = "OPL";47pub const TOKEN_SYMBOL: &str = "OPL";
48pub const DECIMALS: u8 = 18;
4849
49/// This runtime version.50/// This runtime version.
50pub const VERSION: RuntimeVersion = RuntimeVersion {51pub const VERSION: RuntimeVersion = RuntimeVersion {
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
22pov-estimate = []22pov-estimate = []
23quartz-runtime = ['app-promotion', 'collator-selection', 'foreign-assets', 'preimage', 'refungible']23quartz-runtime = ['app-promotion', 'collator-selection', 'foreign-assets', 'preimage', 'refungible']
24runtime-benchmarks = [24runtime-benchmarks = [
25 "pallet-preimage/runtime-benchmarks",
25 'cumulus-pallet-parachain-system/runtime-benchmarks',26 'cumulus-pallet-parachain-system/runtime-benchmarks',
26 'frame-benchmarking',27 'frame-benchmarking',
27 'frame-support/runtime-benchmarks',28 'frame-support/runtime-benchmarks',
42 'pallet-inflation/runtime-benchmarks',43 'pallet-inflation/runtime-benchmarks',
43 'pallet-maintenance/runtime-benchmarks',44 'pallet-maintenance/runtime-benchmarks',
44 'pallet-nonfungible/runtime-benchmarks',45 'pallet-nonfungible/runtime-benchmarks',
45 "pallet-preimage/runtime-benchmarks",
46 'pallet-refungible/runtime-benchmarks',46 'pallet-refungible/runtime-benchmarks',
47 'pallet-structure/runtime-benchmarks',47 'pallet-structure/runtime-benchmarks',
48 'pallet-timestamp/runtime-benchmarks',48 'pallet-timestamp/runtime-benchmarks',
66 'frame-try-runtime/std',66 'frame-try-runtime/std',
67 'pallet-aura/std',67 'pallet-aura/std',
68 'pallet-balances/std',68 'pallet-balances/std',
69 'pallet-balances-adapter/std',
69 # 'pallet-contracts/std',70 # 'pallet-contracts/std',
70 # 'pallet-contracts-primitives/std',71 # 'pallet-contracts-primitives/std',
71 # 'pallet-contracts-rpc-runtime-api/std',72 # 'pallet-contracts-rpc-runtime-api/std',
72 # 'pallet-contract-helpers/std',73 # 'pallet-contract-helpers/std',
73 "pallet-preimage/std",
74 "pallet-authorship/std",74 "pallet-authorship/std",
75 "pallet-identity/std",75 "pallet-identity/std",
76 "pallet-preimage/std",
76 "pallet-session/std",77 "pallet-session/std",
77 "sp-consensus-aura/std",78 "sp-consensus-aura/std",
78 'app-promotion-rpc/std',79 'app-promotion-rpc/std',
127 "orml-tokens/std",128 "orml-tokens/std",
128 "orml-traits/std",129 "orml-traits/std",
129 "orml-vesting/std",130 "orml-vesting/std",
131 "orml-xcm-support/std",
130 "orml-xtokens/std",132 "orml-xtokens/std",
131 "orml-xcm-support/std",
132 "pallet-foreign-assets/std",133 "pallet-foreign-assets/std",
133 "pallet-maintenance/std",134 "pallet-maintenance/std",
134]135]
135try-runtime = [136try-runtime = [
136 "pallet-authorship/try-runtime",137 "pallet-authorship/try-runtime",
137 "pallet-collator-selection/try-runtime",138 "pallet-collator-selection/try-runtime",
138 "pallet-identity/try-runtime",139 "pallet-identity/try-runtime",
140 "pallet-preimage/try-runtime",
139 "pallet-session/try-runtime",141 "pallet-session/try-runtime",
140 "pallet-preimage/try-runtime",
141 'cumulus-pallet-aura-ext/try-runtime',142 'cumulus-pallet-aura-ext/try-runtime',
142 'cumulus-pallet-dmp-queue/try-runtime',143 'cumulus-pallet-dmp-queue/try-runtime',
143 'cumulus-pallet-parachain-system/try-runtime',144 'cumulus-pallet-parachain-system/try-runtime',
154 'pallet-app-promotion/try-runtime',155 'pallet-app-promotion/try-runtime',
155 'pallet-aura/try-runtime',156 'pallet-aura/try-runtime',
156 'pallet-balances/try-runtime',157 'pallet-balances/try-runtime',
158 'pallet-balances-adapter/try-runtime',
157 'pallet-charge-transaction/try-runtime',159 'pallet-charge-transaction/try-runtime',
158 'pallet-common/try-runtime',160 'pallet-common/try-runtime',
159 'pallet-configuration/try-runtime',161 'pallet-configuration/try-runtime',
208orml-tokens = { workspace = true }210orml-tokens = { workspace = true }
209orml-traits = { workspace = true }211orml-traits = { workspace = true }
210orml-vesting = { workspace = true }212orml-vesting = { workspace = true }
211orml-xtokens = { workspace = true }213orml-xcm-support = { workspace = true }
212orml-xcm-support = { workspace = true }214orml-xtokens = { workspace = true }
213pallet-aura = { workspace = true }215pallet-aura = { workspace = true }
214pallet-authorship = { workspace = true }216pallet-authorship = { workspace = true }
215pallet-balances = { features = ["insecure_zero_ed"], workspace = true }217pallet-balances = { features = ["insecure_zero_ed"], workspace = true }
246fp-evm = { workspace = true }248fp-evm = { workspace = true }
247log = { workspace = true }249log = { workspace = true }
248pallet-app-promotion = { workspace = true }250pallet-app-promotion = { workspace = true }
251pallet-balances-adapter = { workspace = true }
249pallet-collator-selection = { workspace = true }252pallet-collator-selection = { workspace = true }
250pallet-common = { workspace = true }253pallet-common = { workspace = true }
251pallet-configuration = { workspace = true }254pallet-configuration = { workspace = true }
283################################################################################286################################################################################
284# Optional dependencies287# Optional dependencies
285288
289frame-benchmarking = { workspace = true, optional = true }
286frame-system-benchmarking = { workspace = true, optional = true }290frame-system-benchmarking = { workspace = true, optional = true }
287frame-benchmarking = { workspace = true, optional = true }
288frame-try-runtime = { workspace = true, optional = true }291frame-try-runtime = { workspace = true, optional = true }
292hex-literal = { workspace = true, optional = true }
289serde = { workspace = true, optional = true }293serde = { workspace = true, optional = true }
290hex-literal = { workspace = true, optional = true }
291294
292295
293################################################################################296################################################################################
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
48#[cfg(not(feature = "become-sapphire"))]48#[cfg(not(feature = "become-sapphire"))]
49pub const RUNTIME_NAME: &str = "quartz";49pub const RUNTIME_NAME: &str = "quartz";
50pub const TOKEN_SYMBOL: &str = "QTZ";50pub const TOKEN_SYMBOL: &str = "QTZ";
51pub const DECIMALS: u8 = 18;
5152
52/// This runtime version.53/// This runtime version.
53pub const VERSION: RuntimeVersion = RuntimeVersion {54pub const VERSION: RuntimeVersion = RuntimeVersion {
modifiedruntime/tests/Cargo.tomldiffbeforeafterboth
26pallet-ethereum = { workspace = true }26pallet-ethereum = { workspace = true }
27pallet-evm = { workspace = true }27pallet-evm = { workspace = true }
2828
29pallet-balances-adapter = { workspace = true }
29pallet-common = { workspace = true }30pallet-common = { workspace = true }
30pallet-fungible = { workspace = true }31pallet-fungible = { workspace = true }
31pallet-nonfungible = { workspace = true }32pallet-nonfungible = { workspace = true }
41evm-coder = { workspace = true }42evm-coder = { workspace = true }
42up-sponsorship = { workspace = true }43up-sponsorship = { workspace = true }
43xcm = { workspace = true }44xcm = { workspace = true }
44pallet-xcm = { workspace = true }
45pallet-configuration = { workspace = true }
4645
modifiedruntime/tests/src/lib.rsdiffbeforeafterboth
19use sp_core::{H160, H256, U256};19use sp_core::{H160, H256, U256};
20use frame_support::{20use frame_support::{
21 parameter_types,21 parameter_types,
22 traits::{Everything, ConstU32, ConstU64},22 traits::{Everything, ConstU32, ConstU64, Currency},
23 weights::IdentityFee,23 weights::IdentityFee,
24 pallet_prelude::Weight,24 pallet_prelude::Weight,
25};25};
266impl pallet_nonfungible::Config for Test {266impl pallet_nonfungible::Config for Test {
267 type WeightInfo = ();267 type WeightInfo = ();
268}268}
269parameter_types! {
270 pub const Decimals: u8 = 18;
271 pub Name: String = "Test".to_string();
272 pub Symbol: String = "TST".to_string();
273}
274impl pallet_balances_adapter::Config for Test {
275 type Currency = Balances;
276 type CurrencyBalance = <Balances as Currency<Self::AccountId>>::Balance;
277 type Decimals = Decimals;
278 type Name = Name;
279 type Symbol = Symbol;
280 type WeightInfo = ();
281}
269282
270parameter_types! {283parameter_types! {
271 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f284 // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
20limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']20limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
21pov-estimate = []21pov-estimate = []
22runtime-benchmarks = [22runtime-benchmarks = [
23 "pallet-preimage/runtime-benchmarks",
23 'frame-benchmarking',24 'frame-benchmarking',
24 'frame-support/runtime-benchmarks',25 'frame-support/runtime-benchmarks',
25 'frame-system-benchmarking',26 'frame-system-benchmarking',
39 'pallet-inflation/runtime-benchmarks',40 'pallet-inflation/runtime-benchmarks',
40 'pallet-maintenance/runtime-benchmarks',41 'pallet-maintenance/runtime-benchmarks',
41 'pallet-nonfungible/runtime-benchmarks',42 'pallet-nonfungible/runtime-benchmarks',
42 "pallet-preimage/runtime-benchmarks",
43 'pallet-refungible/runtime-benchmarks',43 'pallet-refungible/runtime-benchmarks',
44 'pallet-structure/runtime-benchmarks',44 'pallet-structure/runtime-benchmarks',
45 'pallet-timestamp/runtime-benchmarks',45 'pallet-timestamp/runtime-benchmarks',
68 # 'pallet-contracts-primitives/std',68 # 'pallet-contracts-primitives/std',
69 # 'pallet-contracts-rpc-runtime-api/std',69 # 'pallet-contracts-rpc-runtime-api/std',
70 # 'pallet-contract-helpers/std',70 # 'pallet-contract-helpers/std',
71 "pallet-preimage/std",
72 "pallet-authorship/std",71 "pallet-authorship/std",
73 "pallet-identity/std",72 "pallet-identity/std",
73 "pallet-preimage/std",
74 "pallet-session/std",74 "pallet-session/std",
75 "sp-consensus-aura/std",75 "sp-consensus-aura/std",
76 'app-promotion-rpc/std',76 'app-promotion-rpc/std',
77 'evm-coder/std',77 'evm-coder/std',
78 'fp-rpc/std',78 'fp-rpc/std',
79 'fp-self-contained/std',79 'fp-self-contained/std',
80 'pallet-app-promotion/std',80 'pallet-app-promotion/std',
81 'pallet-balances-adapter/std',
81 'pallet-base-fee/std',82 'pallet-base-fee/std',
82 'pallet-charge-transaction/std',83 'pallet-charge-transaction/std',
83 'pallet-collator-selection/std',84 'pallet-collator-selection/std',
124 "orml-tokens/std",125 "orml-tokens/std",
125 "orml-traits/std",126 "orml-traits/std",
126 "orml-vesting/std",127 "orml-vesting/std",
128 "orml-xcm-support/std",
127 "orml-xtokens/std",129 "orml-xtokens/std",
128 "orml-xcm-support/std",
129 "pallet-foreign-assets/std",130 "pallet-foreign-assets/std",
130 "pallet-maintenance/std",131 "pallet-maintenance/std",
131]132]
134 "pallet-authorship/try-runtime",135 "pallet-authorship/try-runtime",
135 "pallet-collator-selection/try-runtime",136 "pallet-collator-selection/try-runtime",
136 "pallet-identity/try-runtime",137 "pallet-identity/try-runtime",
138 "pallet-preimage/try-runtime",
137 "pallet-session/try-runtime",139 "pallet-session/try-runtime",
138 "pallet-preimage/try-runtime",
139 'cumulus-pallet-aura-ext/try-runtime',140 'cumulus-pallet-aura-ext/try-runtime',
140 'cumulus-pallet-dmp-queue/try-runtime',141 'cumulus-pallet-dmp-queue/try-runtime',
141 'cumulus-pallet-parachain-system/try-runtime',142 'cumulus-pallet-parachain-system/try-runtime',
152 'pallet-app-promotion/try-runtime',153 'pallet-app-promotion/try-runtime',
153 'pallet-aura/try-runtime',154 'pallet-aura/try-runtime',
154 'pallet-balances/try-runtime',155 'pallet-balances/try-runtime',
156 'pallet-balances-adapter/try-runtime',
155 'pallet-charge-transaction/try-runtime',157 'pallet-charge-transaction/try-runtime',
156 'pallet-common/try-runtime',158 'pallet-common/try-runtime',
157 'pallet-configuration/try-runtime',159 'pallet-configuration/try-runtime',
207orml-tokens = { workspace = true }209orml-tokens = { workspace = true }
208orml-traits = { workspace = true }210orml-traits = { workspace = true }
209orml-vesting = { workspace = true }211orml-vesting = { workspace = true }
210orml-xtokens = { workspace = true }212orml-xcm-support = { workspace = true }
211orml-xcm-support = { workspace = true }213orml-xtokens = { workspace = true }
212pallet-aura = { workspace = true }214pallet-aura = { workspace = true }
213pallet-authorship = { workspace = true }215pallet-authorship = { workspace = true }
214pallet-balances = { features = ["insecure_zero_ed"], workspace = true }216pallet-balances = { features = ["insecure_zero_ed"], workspace = true }
244derivative = { workspace = true }246derivative = { workspace = true }
245log = { workspace = true }247log = { workspace = true }
246pallet-app-promotion = { workspace = true }248pallet-app-promotion = { workspace = true }
249pallet-balances-adapter = { workspace = true }
247pallet-collator-selection = { workspace = true }250pallet-collator-selection = { workspace = true }
248pallet-common = { workspace = true }251pallet-common = { workspace = true }
249pallet-configuration = { workspace = true }252pallet-configuration = { workspace = true }
282################################################################################285################################################################################
283# Optional dependencies286# Optional dependencies
284287
288frame-benchmarking = { workspace = true, optional = true }
285frame-system-benchmarking = { workspace = true, optional = true }289frame-system-benchmarking = { workspace = true, optional = true }
286frame-benchmarking = { workspace = true, optional = true }
287frame-try-runtime = { workspace = true, optional = true }290frame-try-runtime = { workspace = true, optional = true }
291hex-literal = { workspace = true, optional = true }
288serde = { workspace = true, optional = true }292serde = { workspace = true, optional = true }
289hex-literal = { workspace = true, optional = true }
290293
291################################################################################294################################################################################
292# Test dependencies295# Test dependencies
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
4545
46pub const RUNTIME_NAME: &str = "unique";46pub const RUNTIME_NAME: &str = "unique";
47pub const TOKEN_SYMBOL: &str = "UNQ";47pub const TOKEN_SYMBOL: &str = "UNQ";
48pub const DECIMALS: u8 = 18;
4849
49/// This runtime version.50/// This runtime version.
50pub const VERSION: RuntimeVersion = RuntimeVersion {51pub const VERSION: RuntimeVersion = RuntimeVersion {
modifiedtests/.eslintrc.jsondiffbeforeafterboth
86 "array-bracket-spacing": "warn",86 "array-bracket-spacing": "warn",
87 "template-curly-spacing": "warn",87 "template-curly-spacing": "warn",
88 "space-in-parens": "warn",88 "space-in-parens": "warn",
89 "arrow-body-style": ["warn", "as-needed"],
90 "no-restricted-syntax": [
91 "warn",
92 {
93 "message": "toHuman results in horrible, hard to debug conversions with no stability guarantees, use Codec/at least .toJson instead",
94 "selector": "MemberExpression > Identifier[name=\"toHuman\"]"
95 }
96 ],
89 "@typescript-eslint/naming-convention": [97 "@typescript-eslint/naming-convention": [
90 "warn",98 "warn",
91 {99 {
modifiedtests/package.jsondiffbeforeafterboth
39 "testParallelFull": "yarn testParallel && yarn testSequential",39 "testParallelFull": "yarn testParallel && yarn testSequential",
40 "testParallel": "yarn _testParallel './src/**/*.test.ts'",40 "testParallel": "yarn _testParallel './src/**/*.test.ts'",
41 "testSequential": "yarn _test './src/**/*.seqtest.ts'",41 "testSequential": "yarn _test './src/**/*.seqtest.ts'",
42 "testStructure": "yarn setup && yarn _test ./**/nesting/*.*test.ts",42 "testStructure": "yarn _test ./**/nesting/*.*test.ts",
43 "testEth": "yarn setup && yarn _test './**/eth/**/*.*test.ts'",43 "testEth": "yarn _test './**/eth/**/*.*test.ts'",
44 "testEthNesting": "yarn setup && yarn _test './**/eth/nesting/**/*.*test.ts'",44 "testEthNesting": "yarn _test './**/eth/nesting/**/*.*test.ts'",
45 "testEthFractionalizer": "yarn setup && yarn _test './**/eth/fractionalizer/**/*.*test.ts'",45 "testEthFractionalizer": "yarn _test './**/eth/fractionalizer/**/*.*test.ts'",
46 "testEthMarketplace": "yarn setup && yarn _test './**/eth/marketplace/**/*.*test.ts'",46 "testEthMarketplace": "yarn _test './**/eth/marketplace/**/*.*test.ts'",
47 "testSub": "yarn _test './**/sub/**/*.*test.ts'",
48 "testSubNesting": "yarn _test './**/sub/nesting/**/*.*test.ts'",
47 "testEvent": "yarn setup && yarn _test ./src/check-event/*.*test.ts",49 "testEvent": "yarn _test ./src/check-event/*.*test.ts",
48 "testEthPayable": "yarn _test './**/eth/payable.test.ts'",50 "testEthPayable": "yarn _test './**/eth/payable.test.ts'",
49 "testEvmCoder": "yarn _test './**/eth/evmCoder.test.ts'",51 "testEvmCoder": "yarn _test './**/eth/evmCoder.test.ts'",
50 "testNesting": "yarn _test ./**/nest.test.ts",52 "testNesting": "yarn _test ./**/nest.test.ts",
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itSub, usingPlaygrounds, expect} from './util';18import {itSub, usingPlaygrounds, expect} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {21describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
21 let donor: IKeyringPair;22 let donor: IKeyringPair;
8283
83 itSub("Can't add collection admin of not existing collection.", async ({helper}) => {84 itSub("Can't add collection admin of not existing collection.", async ({helper}) => {
84 const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);85 const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
85 const collectionId = (1 << 32) - 1;86 const collectionId = NON_EXISTENT_COLLECTION_ID;
8687
87 await expect(helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/);88 await expect(helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/);
8889
modifiedtests/src/allowLists.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {usingPlaygrounds, expect, itSub} from './util';18import {usingPlaygrounds, expect, itSub} from './util';
19import {ICollectionPermissions} from './util/playgrounds/types';19import {ICollectionPermissions, NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
2020
21describe('Integration Test ext. Allow list tests', () => {21describe('Integration Test ext. Allow list tests', () => {
22 let alice: IKeyringPair;22 let alice: IKeyringPair;
6060
61 describe('Negative', () => {61 describe('Negative', () => {
62 itSub('Nobody can add address to allow list of non-existing collection', async ({helper}) => {62 itSub('Nobody can add address to allow list of non-existing collection', async ({helper}) => {
63 const collectionId = (1<<32) - 1;63 const collectionId = NON_EXISTENT_COLLECTION_ID;
64 await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))64 await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}))
65 .to.be.rejectedWith(/common\.CollectionNotFound/);65 .to.be.rejectedWith(/common\.CollectionNotFound/);
66 });66 });
140 });140 });
141141
142 itSub('Nobody can remove address from allow list of non-existing collection', async ({helper}) => {142 itSub('Nobody can remove address from allow list of non-existing collection', async ({helper}) => {
143 const collectionId = (1<<32) - 1;143 const collectionId = NON_EXISTENT_COLLECTION_ID;
144 await expect(helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}))144 await expect(helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}))
145 .to.be.rejectedWith(/common\.CollectionNotFound/);145 .to.be.rejectedWith(/common\.CollectionNotFound/);
146 });146 });
modifiedtests/src/benchmarks/utils/common.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {usingPlaygrounds, expect, itSub} from './util';18import {usingPlaygrounds, expect, itSub} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('Integration Test changeCollectionOwner(collection_id, new_owner):', () => {21describe('Integration Test changeCollectionOwner(collection_id, new_owner):', () => {
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
127 });128 });
128129
129 itSub('Can\'t change owner of a non-existing collection.', async ({helper}) => {130 itSub('Can\'t change owner of a non-existing collection.', async ({helper}) => {
130 const collectionId = (1 << 32) - 1;131 const collectionId = NON_EXISTENT_COLLECTION_ID;
131 const changeOwnerTx = () => helper.collection.changeOwner(bob, collectionId, bob.address);132 const changeOwnerTx = () => helper.collection.changeOwner(bob, collectionId, bob.address);
132 await expect(changeOwnerTx()).to.be.rejectedWith(/common\.CollectionNotFound/);133 await expect(changeOwnerTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
133 });134 });
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {usingPlaygrounds, expect, itSub, Pallets} from './util';18import {usingPlaygrounds, expect, itSub, Pallets} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20async function setSponsorHelper(collection: any, signer: IKeyringPair, sponsorAddress: string) {21async function setSponsorHelper(collection: any, signer: IKeyringPair, sponsorAddress: string) {
21 await collection.setSponsor(signer, sponsorAddress);22 await collection.setSponsor(signer, sponsorAddress);
198 });199 });
199200
200 itSub('(!negative test!) Confirm sponsorship for a collection that never existed', async ({helper}) => {201 itSub('(!negative test!) Confirm sponsorship for a collection that never existed', async ({helper}) => {
201 const collectionId = (1 << 32) - 1;202 const collectionId = NON_EXISTENT_COLLECTION_ID;
202 const confirmSponsorshipTx = () => helper.collection.confirmSponsorship(bob, collectionId);203 const confirmSponsorshipTx = () => helper.collection.confirmSponsorship(bob, collectionId);
203 await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/);204 await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/);
204 });205 });
modifiedtests/src/creditFeesToTreasury.seqtest.tsdiffbeforeafterboth
88 expect(treasuryIncrease).to.be.equal(fee);88 expect(treasuryIncrease).to.be.equal(fee);
89 });89 });
9090
91 itSub.only('Treasury balance increased by failed tx fee', async ({helper}) => {91 itSub('Treasury balance increased by failed tx fee', async ({helper}) => {
92 const api = helper.getApi();92 const api = helper.getApi();
93 await helper.wait.newBlocks(1);93 await helper.wait.newBlocks(1);
9494
addedtests/src/eth/abi/nativeFungible.jsondiffbeforeafterboth

no changes

addedtests/src/eth/api/UniqueNativeFungible.soldiffbeforeafterboth

no changes

modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
18import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index';18import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index';
19import {itEth, expect} from './util';19import {itEth, expect} from './util';
2020
21describe.only('evm nft collection sponsoring', () => {21describe('evm nft collection sponsoring', () => {
22 let donor: IKeyringPair;22 let donor: IKeyringPair;
23 let alice: IKeyringPair;23 let alice: IKeyringPair;
24 let nominal: bigint;24 let nominal: bigint;
319 });319 });
320});320});
321321
322describe.only('evm RFT collection sponsoring', () => {322describe('evm RFT collection sponsoring', () => {
323 let donor: IKeyringPair;323 let donor: IKeyringPair;
324 let alice: IKeyringPair;324 let alice: IKeyringPair;
325 let nominal: bigint;325 let nominal: bigint;
modifiedtests/src/eth/createFTCollection.seqtest.tsdiffbeforeafterboth
2020
21const DECIMALS = 18;21const DECIMALS = 18;
2222
23describe.only('Create FT collection from EVM', () => {23describe('Create FT collection from EVM', () => {
24 let donor: IKeyringPair;24 let donor: IKeyringPair;
2525
26 before(async function() {26 before(async function() {
modifiedtests/src/eth/createFTCollection.test.tsdiffbeforeafterboth
2222
23const DECIMALS = 18;23const DECIMALS = 18;
2424
25describe.only('Create FT collection from EVM', () => {25describe('Create FT collection from EVM', () => {
26 let donor: IKeyringPair;26 let donor: IKeyringPair;
2727
28 before(async function() {28 before(async function() {
129 });129 });
130});130});
131131
132describe.only('(!negative tests!) Create FT collection from EVM', () => {132describe('(!negative tests!) Create FT collection from EVM', () => {
133 let donor: IKeyringPair;133 let donor: IKeyringPair;
134 let nominal: bigint;134 let nominal: bigint;
135135
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
21import {COLLECTION_HELPER} from '../util';21import {COLLECTION_HELPER} from '../util';
2222
2323
24describe.only('Create NFT collection from EVM', () => {24describe('Create NFT collection from EVM', () => {
25 let donor: IKeyringPair;25 let donor: IKeyringPair;
2626
27 before(async function () {27 before(async function () {
143 });143 });
144});144});
145145
146describe.only('(!negative tests!) Create NFT collection from EVM', () => {146describe('(!negative tests!) Create NFT collection from EVM', () => {
147 let donor: IKeyringPair;147 let donor: IKeyringPair;
148 let nominal: bigint;148 let nominal: bigint;
149149
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
21import {CollectionLimitField} from './util/playgrounds/types';21import {CollectionLimitField} from './util/playgrounds/types';
2222
2323
24describe.only('Create RFT collection from EVM', () => {24describe('Create RFT collection from EVM', () => {
25 let donor: IKeyringPair;25 let donor: IKeyringPair;
2626
27 before(async function() {27 before(async function() {
154 });154 });
155});155});
156156
157describe.only('(!negative tests!) Create RFT collection from EVM', () => {157describe('(!negative tests!) Create RFT collection from EVM', () => {
158 let donor: IKeyringPair;158 let donor: IKeyringPair;
159 let nominal: bigint;159 let nominal: bigint;
160160
modifiedtests/src/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth
80};80};
8181
8282
83describe.only('Fractionalizer contract usage', () => {83describe('Fractionalizer contract usage', () => {
84 let donor: IKeyringPair;84 let donor: IKeyringPair;
8585
86 before(async function() {86 before(async function() {
addedtests/src/eth/nativeFungible.test.tsdiffbeforeafterboth

no changes

addedtests/src/eth/nativeRpc/estimateGas.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/eth/nesting/nest.test.tsdiffbeforeafterboth
188 });188 });
189 });189 });
190
191 describe('Fungible', () => {
192 async function createFungibleCollection(helper: EthUniqueHelper, owner: string, mode: 'ft' | 'native ft') {
193 if (mode === 'ft') {
194 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, '', 18, '', '');
195 const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
196 await contract.methods.mint(owner, 100n).send({from: owner});
197 return {collectionAddress, contract};
198 }
199
200 // native ft
201 const collectionAddress = helper.ethAddress.fromCollectionId(0);
202 const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
203 return {collectionAddress, contract};
204 }
205
206 [
207 {mode: 'ft' as const},
208 {mode: 'native ft' as const},
209 ].map(testCase => {
210 itEth(`Allow nest [${testCase.mode}]`, async ({helper}) => {
211 const owner = await helper.eth.createAccountWithBalance(donor);
212 const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
213 const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
214
215 const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
216 const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
217 const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
218
219 await ftContract.methods.transfer(targetTokenAddress, 10n).send({from: owner});
220 expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('10');
221 });
222 });
223
224 [
225 {mode: 'ft' as const},
226 {mode: 'native ft' as const},
227 ].map(testCase => {
228 itEth(`Allow partial/full unnest [${testCase.mode}]`, async ({helper}) => {
229 const owner = await helper.eth.createAccountWithBalance(donor);
230 const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
231 const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
232
233 const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
234 const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
235 const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
236
237 await ftContract.methods.transfer(targetTokenAddress, 10n).send({from: owner});
238
239 await ftContract.methods.transferFrom(targetTokenAddress, owner, 5n).send({from: owner});
240 expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('5');
241
242 await ftContract.methods.transferFrom(targetTokenAddress, owner, 5n).send({from: owner});
243 expect(await ftContract.methods.balanceOf(targetTokenAddress).call({from: owner})).to.be.equal('0');
244 });
245 });
246
247 [
248 {mode: 'ft' as const},
249 {mode: 'native ft' as const},
250 ].map(testCase => {
251 itEth(`Disallow nest into collection without nesting permission [${testCase.mode}] (except for native fungible collection)`, async ({helper}) => {
252 const owner = await helper.eth.createAccountWithBalance(donor);
253 const {collectionId: targetCollectionId, contract: targetContract} = await createNestingCollection(helper, owner);
254 await targetContract.methods.setCollectionNesting(false).send({from: owner});
255
256 const {contract: ftContract} = await createFungibleCollection(helper, owner, testCase.mode);
257
258 const mintingTargetTokenIdResult = await targetContract.methods.mint(owner).send({from: owner});
259 const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;
260 const targetTokenAddress = helper.ethAddress.fromTokenId(targetCollectionId, targetTokenId);
261
262 if (testCase.mode === 'ft') {
263 await expect(ftContract.methods.transfer(targetTokenAddress, 10n).call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
264 } else {
265 await expect(ftContract.methods.transfer(targetTokenAddress, 10n).call({from: owner})).to.be.not.rejected;
266 }
267 });
268 });
269 });
190});270});
191271
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
929 });929 });
930 });930 });
931931
932 itEth.only('Returns collection name', async ({helper}) => {932 itEth('Returns collection name', async ({helper}) => {
933 // FIXME: should not have balance to use .call()933 // FIXME: should not have balance to use .call()
934 const caller = await helper.eth.createAccountWithBalance(donor);934 const caller = await helper.eth.createAccountWithBalance(donor);
935 const tokenPropertyPermissions = [{935 const tokenPropertyPermissions = [{
modifiedtests/src/eth/payable.test.tsdiffbeforeafterboth
41 expect(await contract.methods.getCollected().call()).to.be.equal('10000');41 expect(await contract.methods.getCollected().call()).to.be.equal('10000');
42 });42 });
4343
44 itEth.only('Evm contract can receive wei from substrate account', async ({helper}) => {44 itEth('Evm contract can receive wei from substrate account', async ({helper}) => {
45 const deployer = await helper.eth.createAccountWithBalance(donor);45 const deployer = await helper.eth.createAccountWithBalance(donor);
46 const contract = await helper.eth.deployCollectorContract(deployer);46 const contract = await helper.eth.deployCollectorContract(deployer);
47 const [alice] = await helper.arrange.createAccounts([40n], donor);47 const [alice] = await helper.arrange.createAccounts([40n], donor);
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
679 });679 });
680 });680 });
681681
682 itEth.only('Returns collection name', async ({helper}) => {682 itEth('Returns collection name', async ({helper}) => {
683 // FIXME: should not have balance to use .call()683 // FIXME: should not have balance to use .call()
684 const caller = await helper.eth.createAccountWithBalance(alice);684 const caller = await helper.eth.createAccountWithBalance(alice);
685 const tokenPropertyPermissions = [{685 const tokenPropertyPermissions = [{
modifiedtests/src/eth/tokenProperties.test.tsdiffbeforeafterboth
314 expect(result.length).to.equal(0);314 expect(result.length).to.equal(0);
315 }));315 }));
316316
317 itEth.only('Can be read', async({helper}) => {317 itEth('Can be read', async({helper}) => {
318 // FIXME: User with no balance should be able to call318 // FIXME: User with no balance should be able to call
319 const caller = await helper.eth.createAccountWithBalance(alice);319 const caller = await helper.eth.createAccountWithBalance(alice);
320 const collection = await helper.nft.mintCollection(alice, {320 const collection = await helper.nft.mintCollection(alice, {
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
2222
23// Native contracts ABI23// Native contracts ABI
24import collectionHelpersAbi from '../../abi/collectionHelpers.json' assert {type: 'json'};24import collectionHelpersAbi from '../../abi/collectionHelpers.json' assert {type: 'json'};
25import nativeFungibleAbi from '../../abi/nativeFungible.json' assert {type: 'json'};
25import fungibleAbi from '../../abi/fungible.json' assert {type: 'json'};26import fungibleAbi from '../../abi/fungible.json' assert {type: 'json'};
26import fungibleDeprecatedAbi from '../../abi/fungibleDeprecated.json' assert {type: 'json'};27import fungibleDeprecatedAbi from '../../abi/fungibleDeprecated.json' assert {type: 'json'};
27import nonFungibleAbi from '../../abi/nonFungible.json' assert {type: 'json'};28import nonFungibleAbi from '../../abi/nonFungible.json' assert {type: 'json'};
112 data: object,113 data: object,
113 from: signer,114 from: signer,
114 gas: gas ?? this.helper.eth.DEFAULT_GAS,115 gas: gas ?? this.helper.eth.DEFAULT_GAS,
115 gasPrice: await this.getGasPrice(),
116 });116 });
117 return await contract.deploy({data: object}).send({from: signer});117 return await contract.deploy({data: object}).send({from: signer});
118 }118 }
121121
122class NativeContractGroup extends EthGroupBase {122class NativeContractGroup extends EthGroupBase {
123123
124 async contractHelpers(caller: string): Promise<Contract> {124 contractHelpers(caller: string) {
125 const web3 = this.helper.getWeb3();125 const web3 = this.helper.getWeb3();
126 return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {126 return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {
127 from: caller,127 from: caller,
128 gas: this.helper.eth.DEFAULT_GAS,128 gas: this.helper.eth.DEFAULT_GAS,
129 gasPrice: await this.getGasPrice(),
130 });129 });
131 }130 }
132131
133 async collectionHelpers(caller: string) {132 collectionHelpers(caller: string) {
134 const web3 = this.helper.getWeb3();133 const web3 = this.helper.getWeb3();
135 return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {134 return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {
136 from: caller,135 from: caller,
137 gas: this.helper.eth.DEFAULT_GAS,136 gas: this.helper.eth.DEFAULT_GAS,
138 gasPrice: await this.getGasPrice(),
139 });137 });
140 }138 }
141139
142 async collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) {140 collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) {
143 let abi = {141 let abi;
142 if (address === this.helper.ethAddress.fromCollectionId(0)) {
143 abi = nativeFungibleAbi;
144 } else {
145 abi ={
144 'nft': nonFungibleAbi,146 'nft': nonFungibleAbi,
145 'rft': refungibleAbi,147 'rft': refungibleAbi,
146 'ft': fungibleAbi,148 'ft': fungibleAbi,
147 }[mode];149 }[mode];
150 }
148 if (mergeDeprecated) {151 if (mergeDeprecated) {
149 const deprecated = {152 const deprecated = {
150 'nft': nonFungibleDeprecatedAbi,153 'nft': nonFungibleDeprecatedAbi,
156 const web3 = this.helper.getWeb3();159 const web3 = this.helper.getWeb3();
157 return new web3.eth.Contract(abi as any, address, {160 return new web3.eth.Contract(abi as any, address, {
158 gas: this.helper.eth.DEFAULT_GAS,161 gas: this.helper.eth.DEFAULT_GAS,
159 gasPrice: await this.getGasPrice(),
160 ...(caller ? {from: caller} : {}),162 ...(caller ? {from: caller} : {}),
161 });163 });
162 }164 }
165 return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated);167 return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated);
166 }168 }
167169
168 async rftToken(address: string, caller?: string, mergeDeprecated = false) {170 rftToken(address: string, caller?: string, mergeDeprecated = false) {
169 const web3 = this.helper.getWeb3();171 const web3 = this.helper.getWeb3();
170 const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi;172 const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi;
171 return new web3.eth.Contract(abi as any, address, {173 return new web3.eth.Contract(abi as any, address, {
172 gas: this.helper.eth.DEFAULT_GAS,174 gas: this.helper.eth.DEFAULT_GAS,
173 gasPrice: await this.getGasPrice(),
174 ...(caller ? {from: caller} : {}),175 ...(caller ? {from: caller} : {}),
175 });176 });
176 }177 }
210 async sendEVM(signer: IKeyringPair, contractAddress: string, abi: string, value: string, gasLimit?: number) {211 async sendEVM(signer: IKeyringPair, contractAddress: string, abi: string, value: string, gasLimit?: number) {
211 if (!gasLimit) gasLimit = this.DEFAULT_GAS;212 if (!gasLimit) gasLimit = this.DEFAULT_GAS;
212 const web3 = this.helper.getWeb3();213 const web3 = this.helper.getWeb3();
214 // FIXME: can't send legacy transaction using tx.evm.call
213 const gasPrice = await web3.eth.getGasPrice();215 const gasPrice = await web3.eth.getGasPrice();
214 // TODO: check execution status216 // TODO: check execution status
215 await this.helper.executeExtrinsic(217 await this.helper.executeExtrinsic(
377class EthAddressGroup extends EthGroupBase {379class EthAddressGroup extends EthGroupBase {
378 extractCollectionId(address: string): number {380 extractCollectionId(address: string): number {
379 if (!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');381 if (!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
380 return parseInt(address.substr(address.length - 8), 16);382 return parseInt(address.slice(address.length - 8), 16);
381 }383 }
382384
383 fromCollectionId(collectionId: number): string {385 fromCollectionId(collectionId: number): string {
modifiedtests/src/maintenance.seqtest.tsdiffbeforeafterboth
325 expect(await helper.preimage.getPreimageInfo(preimageHashes[0])).to.have.property('unrequested');325 expect(await helper.preimage.getPreimageInfo(preimageHashes[0])).to.have.property('unrequested');
326 });326 });
327327
328 itSub.only('Does not allow execution of a preimage that would fail', async ({helper}) => {328 itSub('Does not allow execution of a preimage that would fail', async ({helper}) => {
329 const [zeroAccount] = await helper.arrange.createAccounts([0n], superuser);329 const [zeroAccount] = await helper.arrange.createAccounts([0n], superuser);
330330
331 const preimage = helper.constructApiCall('api.tx.balances.forceTransfer', [331 const preimage = helper.constructApiCall('api.tx.balances.forceTransfer', [
addedtests/src/nativeFungible.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
47 await expect(nestedToken.getOwner()).to.be.rejected;47 await expect(nestedToken.getOwner()).to.be.rejected;
48 });48 });
49
50 itSub('NativeFungible: allows the owner to successfully unnest a token', async ({helper}) => {
51 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
52 const targetToken = await collection.mintToken(alice);
53
54 const collectionFT = helper.ft.getCollectionObject(0);
55
56 // Nest
57 await collectionFT.transfer(alice, targetToken.nestingAccount(), 10n);
58 // Unnest
59 await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
60
61 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
62 });
4963
50 itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {64 itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {
51 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});65 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
19// Pallets that must always be present19// Pallets that must always be present
20const requiredPallets = [20const requiredPallets = [
21 'balances',21 'balances',
22 'balancesadapter',
22 'common',23 'common',
23 'timestamp',24 'timestamp',
24 'transactionpayment',25 'transactionpayment',
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itSub, usingPlaygrounds, expect} from './util';18import {itSub, usingPlaygrounds, expect} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('Integration Test removeCollectionAdmin(collection_id, account_id):', () => {21describe('Integration Test removeCollectionAdmin(collection_id, account_id):', () => {
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
68 });69 });
6970
70 itSub('Can\'t remove collection admin from not existing collection', async ({helper}) => {71 itSub('Can\'t remove collection admin from not existing collection', async ({helper}) => {
71 const collectionId = (1 << 32) - 1;72 const collectionId = NON_EXISTENT_COLLECTION_ID;
7273
73 await expect(helper.collection.removeAdmin(alice, collectionId, {Substrate: bob.address}))74 await expect(helper.collection.removeAdmin(alice, collectionId, {Substrate: bob.address}))
74 .to.be.rejectedWith(/common\.CollectionNotFound/);75 .to.be.rejectedWith(/common\.CollectionNotFound/);
modifiedtests/src/removeCollectionSponsor.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itSub, usingPlaygrounds, expect} from './util';18import {itSub, usingPlaygrounds, expect} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('integration test: ext. removeCollectionSponsor():', () => {21describe('integration test: ext. removeCollectionSponsor():', () => {
21 let donor: IKeyringPair;22 let donor: IKeyringPair;
91 });92 });
9293
93 itSub('(!negative test!) Remove sponsor for a collection that never existed', async ({helper}) => {94 itSub('(!negative test!) Remove sponsor for a collection that never existed', async ({helper}) => {
94 const collectionId = (1 << 32) - 1;95 const collectionId = NON_EXISTENT_COLLECTION_ID;
95 await expect(helper.collection.removeSponsor(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);96 await expect(helper.collection.removeSponsor(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);
96 });97 });
9798
modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
17// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits17// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
19import {itSub, usingPlaygrounds, expect} from './util';19import {itSub, usingPlaygrounds, expect} from './util';
20import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
2021
21const accountTokenOwnershipLimit = 0;22const accountTokenOwnershipLimit = 0;
22const sponsoredDataSize = 0;23const sponsoredDataSize = 0;
110 });111 });
111112
112 itSub('execute setCollectionLimits for not exists collection', async ({helper}) => {113 itSub('execute setCollectionLimits for not exists collection', async ({helper}) => {
113 const nonExistentCollectionId = (1 << 32) - 1;114 const nonExistentCollectionId = NON_EXISTENT_COLLECTION_ID;
114 await expect(helper.collection.setLimits(115 await expect(helper.collection.setLimits(
115 alice,116 alice,
116 nonExistentCollectionId,117 nonExistentCollectionId,
modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itSub, usingPlaygrounds, expect, Pallets} from './util';18import {itSub, usingPlaygrounds, expect, Pallets} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('integration test: ext. setCollectionSponsor():', () => {21describe('integration test: ext. setCollectionSponsor():', () => {
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
105 });106 });
106107
107 itSub('(!negative test!) Add sponsor to a collection that never existed', async ({helper}) => {108 itSub('(!negative test!) Add sponsor to a collection that never existed', async ({helper}) => {
108 const collectionId = (1 << 32) - 1;109 const collectionId = NON_EXISTENT_COLLECTION_ID;
109 await expect(helper.collection.setSponsor(alice, collectionId, bob.address))110 await expect(helper.collection.setSponsor(alice, collectionId, bob.address))
110 .to.be.rejectedWith(/common\.CollectionNotFound/);111 .to.be.rejectedWith(/common\.CollectionNotFound/);
111 });112 });
modifiedtests/src/setPermissions.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itSub, usingPlaygrounds, expect} from './util';18import {itSub, usingPlaygrounds, expect} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('Integration Test: Set Permissions', () => {21describe('Integration Test: Set Permissions', () => {
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
85 });86 });
8687
87 itSub('fails on not existing collection', async ({helper}) => {88 itSub('fails on not existing collection', async ({helper}) => {
88 const collectionId = (1 << 32) - 1;89 const collectionId = NON_EXISTENT_COLLECTION_ID;
89 await expect(helper.collection.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}))90 await expect(helper.collection.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}))
90 .to.be.rejectedWith(/common\.CollectionNotFound/);91 .to.be.rejectedWith(/common\.CollectionNotFound/);
91 });92 });
modifiedtests/src/sub/appPromotion/appPromotion.test.tsdiffbeforeafterboth
157 await helper.staking.stake(staker, 1000n * nominal);157 await helper.staking.stake(staker, 1000n * nominal);
158 await helper.staking.stake(staker, 199n * nominal);158 await helper.staking.stake(staker, 199n * nominal);
159 // check balances159 // check balances
160 expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'ormlvest', amount: 200n * nominal, reasons: 'All'}, {id: 'appstake', amount: 1199n * nominal, reasons: 'All'}]);160 expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'ormlvest', amount: 200n * nominal, reasons: 'All'}]);
161 expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([{id: 'appstakeappstake', amount: 1199n * nominal}]);
161 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 1199n * nominal});162 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 1199n * nominal});
162 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(1199n);163 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(1199n);
163 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(1199n * nominal);164 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(1199n * nominal);
453 const [_unstake1, unstake2] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});454 const [_unstake1, unstake2] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address});
454 await helper.wait.forParachainBlockNumber(unstake2.block);455 await helper.wait.forParachainBlockNumber(unstake2.block);
455456
456 expect(await helper.balance.getLocked(staker.address)).to.deep.eq([]);457 expect(await helper.balance.getFrozen(staker.address)).to.deep.eq([]);
457 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});458 expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, frozen: 0n});
458 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(999n);459 expect(await helper.balance.getSubstrate(staker.address) / nominal).to.eq(999n);
459 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);460 expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.eq(0n);
modifiedtests/src/sub/nesting/admin.test.tsdiffbeforeafterboth
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {expect, itSub, usingPlaygrounds} from '../../util';18import {expect, itSub, usingPlaygrounds} from '../../util';
1919
20describe('Collection admin', () => {20describe('Nesting by collection admin', () => {
21 let alice: IKeyringPair;21 let alice: IKeyringPair;
22 let bob: IKeyringPair;22 let bob: IKeyringPair;
23 let charlie: IKeyringPair;23 let charlie: IKeyringPair;
modifiedtests/src/sub/nesting/common.test.tsdiffbeforeafterboth
21let alice: IKeyringPair;21let alice: IKeyringPair;
22let bob: IKeyringPair;22let bob: IKeyringPair;
2323
24before(async () => {24describe('Common nesting tests', () => {
25 await usingPlaygrounds(async (helper, privateKey) => {25 before(async () => {
26 const donor = await privateKey({url: import.meta.url});26 await usingPlaygrounds(async (helper, privateKey) => {
27 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);27 const donor = await privateKey({url: import.meta.url});
28 });28 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
29});29 });
3030 });
31[31
32 {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},32 [
33 {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},33 {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
34 {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},34 {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
35 {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},35 {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
36].map(testCase => {36 {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
37 itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {37 ].map(testCase => {
38 // Only NFT can be target for nesting in38 itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
39 const targetNFTCollection = await helper.nft.mintCollection(alice);39 // Only NFT can be target for nesting in
40 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});40 const targetNFTCollection = await helper.nft.mintCollection(alice);
4141 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
42 const collectionForNesting = await helper[testCase.mode].mintCollection(bob);42
43 // permissions should be set:43 const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
44 await targetNFTCollection.setPermissions(alice, {44 // permissions should be set:
45 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},45 await targetNFTCollection.setPermissions(alice, {
46 });46 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
4747 });
48 // 1. Bob can immediately create nested token:48
49 const nestedToken1 = testCase.mode === 'nft'49 // 1. Bob can immediately create nested token:
50 ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())50 const nestedToken1 = testCase.mode === 'nft'
51 : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());51 ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
52 expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});52 : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
53 expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());53 expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
5454 expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
55 // 2. Bob can mint and nest token:55
56 const nestedToken2 = await collectionForNesting.mintToken(bob);56 // 2. Bob can mint and nest token:
57 await nestedToken2.nest(bob, targetTokenBob);57 const nestedToken2 = await collectionForNesting.mintToken(bob);
58 expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});58 await nestedToken2.nest(bob, targetTokenBob);
59 expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());59 expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
60 });60 expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
61});61 });
6262 });
6363
64[64
65 {restrictedMode: true},65 [
66 {restrictedMode: false},66 {restrictedMode: true},
67].map(testCase => {67 {restrictedMode: false},
68 itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {68 ].map(testCase => {
69 // Only NFT allows nesting, permissions should be set:69 itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
70 const targetNFTCollection = await helper.nft.mintCollection(alice);70 // Only NFT allows nesting, permissions should be set:
71 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});71 const targetNFTCollection = await helper.nft.mintCollection(alice);
7272 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
73 const collectionForNesting = await helper.ft.mintCollection(bob);73
74 // permissions should be set:74 const collectionForNesting = await helper.ft.mintCollection(bob);
75 await targetNFTCollection.setPermissions(alice, {75 // permissions should be set:
76 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},76 await targetNFTCollection.setPermissions(alice, {
77 });77 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
7878 });
79 // 1. Alice can immediately create nested tokens:79
80 await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());80 // 1. Alice can immediately create nested tokens:
81 expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);81 await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
82 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);82 expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);
8383 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
84 // 2. Alice can mint and nest token:84
85 await collectionForNesting.mint(bob, 100n);85 // 2. Alice can mint and nest token:
86 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);86 await collectionForNesting.mint(bob, 100n);
87 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);87 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
88 });88 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
89});89 expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);
90 });
91 });
92
93 [
94 {restrictedMode: true},
95 {restrictedMode: false},
96 ].map(testCase => {
97 itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
98 // Only NFT allows nesting, permissions should be set:
99 const targetNFTCollection = await helper.nft.mintCollection(alice);
100 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
101 expect(await targetTokenBob.getChildren()).to.be.empty;
102
103 const collectionForNesting = helper.ft.getCollectionObject(0);
104 // permissions should be set:
105 await targetNFTCollection.setPermissions(alice, {
106 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
107 });
108
109 // Bob can nest Native FT into their NFT:
110 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
111 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
112 // Native FT should't be visible in NFT children:
113 expect(await targetTokenBob.getChildren()).to.be.deep.equal([]);
114 });
115 });
90116
91117
92itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {118 itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
98 const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});124 const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
99 const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});125 const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
100 const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});126 const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
127 const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
101128
102 const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());129 const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
103 const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());130 const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
104 const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());131 const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
132 await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
105 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());133 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
106 expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());134 expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
107 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);135 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
136 expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
137
138 expect(await tokenA.getChildren()).to.be.length(3);
139 expect(await tokenB.getChildren()).to.be.length(0);
108140
109 // Transfer the nested token to another token141 // Transfer the nested token to another token
110 await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());142 await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
111 await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);143 await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
112 await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);144 await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
145 await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
113146
114 expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});147 expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
115 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());148 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());
120 expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);153 expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
121 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);154 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
155
156 expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
157 expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
158
159 // RFT, FT, and without native FT
160 expect(await tokenA.getChildren()).to.be.length(2);
161 // NFT, RFT, FT, and without native FT
162 expect(await tokenB.getChildren()).to.be.length(3);
122});163 });
164});
123165
modifiedtests/src/sub/nesting/e2e.test.tsdiffbeforeafterboth
32 const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});32 const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
33 const collectionB = await helper.ft.mintCollection(alice);33 const collectionB = await helper.ft.mintCollection(alice);
34 const collectionC = await helper.rft.mintCollection(alice);34 const collectionC = await helper.rft.mintCollection(alice);
35 const collectionNative = helper.ft.getCollectionObject(0);
3536
36 const targetToken = await collectionA.mintToken(alice);37 const targetToken = await collectionA.mintToken(alice);
37 expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation');38 expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation');
73 {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},74 {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
74 ]).and.has.length(3);75 ]).and.has.length(3);
76
77 // Nest native fungible token into another collection
78 await collectionNative.transfer(alice, targetToken.nestingAccount(), 2n);
79 expect(await targetToken.getChildren()).to.have.deep.members([
80 {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
81 {tokenId: 0, collectionId: collectionB.collectionId},
82 {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
83 ]).and.has.length(3);
7584
76 // Burn all nested pieces85 // Burn all nested pieces
77 await tokenC.burnFrom(alice, targetToken.nestingAccount(), 2n);86 await tokenC.burnFrom(alice, targetToken.nestingAccount(), 2n);
modifiedtests/src/sub/nesting/nesting.negative.test.tsdiffbeforeafterboth
23let bob: IKeyringPair;23let bob: IKeyringPair;
24let charlie: IKeyringPair;24let charlie: IKeyringPair;
2525
26describe('Negative Test: Nesting', () => {
26before(async () => {27 before(async () => {
27 await usingPlaygrounds(async (helper, privateKey) => {28 await usingPlaygrounds(async (helper, privateKey) => {
28 const donor = await privateKey({url: import.meta.url});29 const donor = await privateKey({url: import.meta.url});
53 });54 });
54});55 });
5556
57 [
58 {mode: 'ft'},
59 {mode: 'nativeFt'},
60 ].map(testCase => {
56itSub('Owner cannot nest FT if nesting is disabled', async ({helper}) => {61 itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled (except for native fungible collection)`, async ({helper}) => {
57 // Create default collection, permissions are not set:62 // Create default collection, permissions are not set:
58 const aliceNFTCollection = await helper.nft.mintCollection(alice);63 const aliceNFTCollection = await helper.nft.mintCollection(alice);
59 const targetToken = await aliceNFTCollection.mintToken(alice);64 const targetToken = await aliceNFTCollection.mintToken(alice);
6065
61 const collectionForNesting = await helper.ft.mintCollection(alice);66 const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);
6267
63 // 1. Alice cannot create immediately nested tokens:68 // Alice cannot create immediately nested tokens:
69 if (testCase.mode === 'ft') {
64 await expect(collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest');70 await expect(collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest');
71 } else {
72 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.not.rejected;
73 }
6574
66 // 2. Alice can mint and nest token:75 // Alice can't mint and nest tokens:
76 if (testCase.mode === 'ft') {
67 await collectionForNesting.mint(alice, 100n);77 await collectionForNesting.mint(alice, 100n);
78 }
79
80 if (testCase.mode === 'ft') {
68 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');81 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');
82 } else {
83 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.not.rejected;
84 }
69});85 });
86 });
7087
71[88 [
72 {mode: 'nft' as const},89 {mode: 'nft' as const},
73 {mode: 'rft' as const},90 {mode: 'rft' as const},
74 {mode: 'ft' as const},91 {mode: 'ft' as const},
92 {mode: 'native ft' as const},
75].map(testCase => {93 ].map(testCase => {
76 itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens`, async ({helper}) => {94 itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens (except for native fungible collection)`, async ({helper}) => {
77 const targetCollection = await helper.nft.mintCollection(alice, {permissions:95 const targetCollection = await helper.nft.mintCollection(alice, {permissions:
78 {nesting: {tokenOwner: true, collectionAdmin: true}},96 {nesting: {tokenOwner: true, collectionAdmin: true}},
79 });97 });
80 const targetToken = await targetCollection.mintToken(alice);98 const targetToken = await targetCollection.mintToken(alice);
8199
82 const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);100 const nestedCollectionBob = await (
101 testCase.mode === 'native ft'
102 ? helper.ft.getCollectionObject(0)
103 : helper[testCase.mode].mintCollection(bob)
104 );
83105
84 let nestedTokenBob: UniqueNFToken | UniqueRFToken;106 let nestedTokenBob: UniqueNFToken | UniqueRFToken;
85 switch (testCase.mode) {107 switch (testCase.mode) {
86 case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;108 case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;
87 case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;109 case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;
88 case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;110 case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;
111 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;
89 }112 }
90113
91 // Bob non-owner of targetToken and non admin of targetCollection, so114 // Bob non-owner of targetToken and non admin of targetCollection, so
94 case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;117 case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
95 case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;118 case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
96 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;119 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
120 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;
97 }121 }
98122
99 // 2. cannot nest existing token:123 // 2. cannot nest existing token:
100 switch (testCase.mode) {124 switch (testCase.mode) {
101 case 'nft':125 case 'nft':
102 case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;126 case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
103 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;127 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;
128 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.not.rejected; break;
104 }129 }
105 });130 });
106});131 });
125 });150 });
126});151 });
127152
128itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {153 itSub.ifWithPallets('Cannot nest in non existing token (except for native fungible collection)', [Pallets.ReFungible], async ({helper}) => {
129 const collection = await helper.nft.mintCollection(alice);154 const collection = await helper.nft.mintCollection(alice);
130 // To avoid UserIsNotAllowedToNest error155 // To avoid UserIsNotAllowedToNest error
131 await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});156 await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});
140 const nftCollectionForNesting = await helper.nft.mintCollection(alice);165 const nftCollectionForNesting = await helper.nft.mintCollection(alice);
141 const rftCollectionForNesting = await helper.rft.mintCollection(alice);166 const rftCollectionForNesting = await helper.rft.mintCollection(alice);
142 const ftCollectionForNesting = await helper.ft.mintCollection(alice);167 const ftCollectionForNesting = await helper.ft.mintCollection(alice);
168 const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);
143169
144 const testCases = [170 const testCases = [
145 {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},171 {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},
160 await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);186 await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
161 await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);187 await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);
162 await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);188 await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);
189 await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.not.rejected;
163 }190 }
164});191 });
165192
180 await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');207 await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');
181});208 });
182209
183itEth.ifWithPallets('Cannot nest in RFT or FT', [Pallets.ReFungible], async ({helper}) => {210 itEth.ifWithPallets('Cannot nest in RFT or FT (except for native fungible collection)', [Pallets.ReFungible], async ({helper}) => {
184 // Create default collection, permissions are not set:211 // Create default collection, permissions are not set:
185 const rftCollection = await helper.rft.mintCollection(alice);212 const rftCollection = await helper.rft.mintCollection(alice);
186 const ftCollection = await helper.ft.mintCollection(alice);213 const ftCollection = await helper.ft.mintCollection(alice);
214 const nativeFtCollection = helper.ft.getCollectionObject(0);
187215
188 const rftToken = await rftCollection.mintToken(alice);216 const rftToken = await rftCollection.mintToken(alice);
189 const _ftToken = await ftCollection.mint(alice, 100n);217 const _ftToken = await ftCollection.mint(alice, 100n);
193 // 1. Alice cannot create immediately nested tokens:221 // 1. Alice cannot create immediately nested tokens:
194 await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');222 await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');
195 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');223 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');
224 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');
196225
197 // 2. Alice cannot mint and nest token:226 // 2. Alice cannot mint and nest token:
198 const nestedToken2 = await collectionForNesting.mintToken(alice);227 const nestedToken2 = await collectionForNesting.mintToken(alice);
199 await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');228 await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');
200 await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');229 await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');
230 await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.not.rejected;
201});231 });
202232
203itSub('Cannot nest in restricted collection if collection is not in the list', async ({helper}) => {233 itSub('Cannot nest in restricted collection if collection is not in the list (except native fungible collection)', async ({helper}) => {
204 const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);234 const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);
205 const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);235 const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);
206 const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);236 const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);
207 const notAllowedCollectionFT = await helper.ft.mintCollection(alice);237 const notAllowedCollectionFT = await helper.ft.mintCollection(alice);
238 const allowedCollectionNativeFT = helper.ft.getCollectionObject(0);
208239
209 // Collection restricted to allowedCollectionId240 // Collection restricted to allowedCollectionId
210 const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:241 const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:
229 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);260 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
230 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);261 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
231 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);262 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);
263 await expect(allowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.not.rejected;
264 await expect(allowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.not.rejected;
232});265 });
233266
234itSub('Cannot create nesting chains greater than 5', async ({helper}) => {267 itSub('Cannot create nesting chains greater than 5', async ({helper}) => {
258 expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});291 expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
259 expect(await token.getChildren()).to.has.length(0);292 expect(await token.getChildren()).to.has.length(0);
260});293 });
294});
261295
modifiedtests/src/sub/nesting/refungible.test.tsdiffbeforeafterboth
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';
1919
20// ReFungible specific nesting tests20describe('ReFungible-specific nesting tests', () => {
21let alice: IKeyringPair;21 let alice: IKeyringPair;
2222
23before(async () => {23 before(async () => {
5858
59 expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});59 expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
60});60 });
61});
6162
modifiedtests/src/sub/nesting/unnesting.negative.test.tsdiffbeforeafterboth
52 });52 });
5353
54 [54 [
55 {restrictedMode: true},55 {mode: 'ft' as const},
56 {restrictedMode: false},56 {mode: 'native ft' as const},
57 ].map(testCase => {57 ].map(md => [
58 {mode: md.mode, restrictedMode: true},
59 {mode: md.mode, restrictedMode: false},
60 ].map(testCase => {
58 itSub(`Fungible: disallows a non-Owner to unnest someone else's token ${testCase.restrictedMode ? '(Restricted nesting)' : ''}`, async ({helper}) => {61 itSub(`Fungible: disallows a non-Owner to unnest someone else's token [${testCase.mode}${testCase.restrictedMode ? ' (Restricted nesting)' : ''}]`, async ({helper}) => {
59 const collectionNFT = await helper.nft.mintCollection(alice);62 const collectionNFT = await helper.nft.mintCollection(alice);
60 const collectionFT = await helper.ft.mintCollection(alice);63 const collectionFT = await (
64 testCase.mode === 'ft'
65 ? helper.ft.mintCollection(alice)
66 : helper.ft.getCollectionObject(0)
67 );
61 const targetToken = await collectionNFT.mintToken(alice, {Substrate: bob.address});68 const targetToken = await collectionNFT.mintToken(alice, {Substrate: bob.address});
6269
63 await collectionNFT.setPermissions(alice, {nesting: {70 await collectionNFT.setPermissions(alice, {nesting: {
64 collectionAdmin: true, tokenOwner: true, restricted: testCase.restrictedMode ? [collectionFT.collectionId] : null,71 collectionAdmin: true, tokenOwner: true, restricted: testCase.restrictedMode ? [collectionFT.collectionId] : null,
65 }});72 }});
6673
67 // Nest some tokens as Alice into Bob's token74 // Nest some tokens as Alice into Bob's token
68 await collectionFT.mint(alice, 5n, targetToken.nestingAccount());75 await (
76 testCase.mode === 'ft'
77 ? collectionFT.mint(alice, 5n, targetToken.nestingAccount())
78 : collectionFT.transfer(alice, targetToken.nestingAccount(), 5n)
79 );
6980
70 // Try to pull it out as Alice still81 // Try to pull it out as Alice still
71 await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: bob.address}, 1n))82 await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: bob.address}, 1n))
72 .to.be.rejectedWith(/common\.ApprovedValueTooLow/);83 .to.be.rejectedWith(/common\.ApprovedValueTooLow/);
73 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);84 expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(5n);
74 });85 });
75 });86 }));
76});87});
7788
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itEth, usingEthPlaygrounds} from './eth/util';18import {itEth, usingEthPlaygrounds} from './eth/util';
19import {itSub, Pallets, usingPlaygrounds, expect} from './util';19import {itSub, Pallets, usingPlaygrounds, expect} from './util';
20import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
2021
21describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {22describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
22 let donor: IKeyringPair;23 let donor: IKeyringPair;
124125
125126
126 itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {127 itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {
127 const collectionId = (1 << 32) - 1;
128 await expect(helper.nft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))128 await expect(helper.nft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))
129 .to.be.rejectedWith(/common\.CollectionNotFound/);129 .to.be.rejectedWith(/common\.CollectionNotFound/);
130 });130 });
131131
132 itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {132 itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {
133 const collectionId = (1 << 32) - 1;
134 await expect(helper.ft.transfer(alice, collectionId, {Substrate: bob.address}))133 await expect(helper.ft.transfer(alice, NON_EXISTENT_COLLECTION_ID, {Substrate: bob.address}))
135 .to.be.rejectedWith(/common\.CollectionNotFound/);134 .to.be.rejectedWith(/common\.CollectionNotFound/);
136 });135 });
137136
138 itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {137 itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {
139 const collectionId = (1 << 32) - 1;
140 await expect(helper.rft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))138 await expect(helper.rft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))
141 .to.be.rejectedWith(/common\.CollectionNotFound/);139 .to.be.rejectedWith(/common\.CollectionNotFound/);
142 });140 });
143141
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {itSub, Pallets, usingPlaygrounds, expect} from './util';18import {itSub, Pallets, usingPlaygrounds, expect} from './util';
19import {NON_EXISTENT_COLLECTION_ID} from './util/playgrounds/types';
1920
20describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {21describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
97 });98 });
9899
99 itSub('transferFrom for a collection that does not exist', async ({helper}) => {100 itSub('transferFrom for a collection that does not exist', async ({helper}) => {
100 const collectionId = (1 << 32) - 1;
101 await expect(helper.collection.approveToken(alice, collectionId, 0, {Substrate: bob.address}, 1n))101 await expect(helper.collection.approveToken(alice, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: bob.address}, 1n))
102 .to.be.rejectedWith(/common\.CollectionNotFound/);102 .to.be.rejectedWith(/common\.CollectionNotFound/);
103 await expect(helper.collection.transferTokenFrom(bob, collectionId, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))103 await expect(helper.collection.transferTokenFrom(bob, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))
104 .to.be.rejectedWith(/common\.CollectionNotFound/);104 .to.be.rejectedWith(/common\.CollectionNotFound/);
105 });105 });
106106
modifiedtests/src/util/playgrounds/types.tsdiffbeforeafterboth
33
4import {IKeyringPair} from '@polkadot/types/types';4import {IKeyringPair} from '@polkadot/types/types';
5
6export const NON_EXISTENT_COLLECTION_ID = 4_294_967_295;
57
6export interface IEvent {8export interface IEvent {
7 section: string;9 section: string;
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
77
8import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';8import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';
9import {SignerOptions} from '@polkadot/api/types/submittable';9import {SignerOptions} from '@polkadot/api/types/submittable';
10import '../../interfaces/augment-api-tx';10import '../../interfaces/augment-api';
11import {AugmentedSubmittables} from '@polkadot/api-base/types/submittable';11import {AugmentedSubmittables} from '@polkadot/api-base/types/submittable';
12import {RpcInterface} from '@polkadot/rpc-core/types';
13import {QueryableStorage} from '@polkadot/api-base/types/storage';
14import {DecoratedRpc} from '@polkadot/api-base/types/rpc';
15import {ApiInterfaceEvents} from '@polkadot/api/types';12import {ApiInterfaceEvents} from '@polkadot/api/types';
16import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';13import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';
17import {IKeyringPair} from '@polkadot/types/types';14import {IKeyringPair} from '@polkadot/types/types';
50} from './types';47} from './types';
51import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';48import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';
52import type {Vec} from '@polkadot/types-codec';49import type {Vec} from '@polkadot/types-codec';
53import {FrameSystemEventRecord} from '@polkadot/types/lookup';50import {FrameSystemEventRecord, PalletBalancesIdAmount} from '@polkadot/types/lookup';
5451
55export class CrossAccountId {52export class CrossAccountId {
56 Substrate!: TSubstrateAccount;53 Substrate!: TSubstrateAccount;
379type Get2<T, P extends string, E> =376type Get2<T, P extends string, E> =
380 P extends `${infer Key}.${infer Key2}` ? Key extends keyof T ? Key2 extends keyof T[Key] ? T[Key][Key2] : E : E : E;377 P extends `${infer Key}.${infer Key2}` ? Key extends keyof T ? Key2 extends keyof T[Key] ? T[Key][Key2] : E : E : E;
381type ForceFunction<T> = T extends (...args: any) => any ? T : (...args: any) => Invalid<'not a function'>;378type ForceFunction<T> = T extends (...args: any) => any ? T : (...args: any) => Invalid<'not a function'>;
382type ReturnTypeWithArgs<T extends (...args: any[]) => any, ARGS_T> =
383 Extract<
384 T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4; } ? [A1, R1] | [A2, R2] | [A3, R3] | [A4, R4] :
385 T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; } ? [A1, R1] | [A2, R2] | [A3, R3] :
386 T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; } ? [A1, R1] | [A2, R2] :
387 T extends { (...args: infer A1): infer R1; } ? [A1, R1] :
388 never,
389 [ARGS_T, any]
390 >[1]
391379
392export class ChainHelperBase {380export class ChainHelperBase {
393 helperBase: any;381 helperBase: any;
498486
499 if (xcmChains.indexOf(spec.specName) > -1) return spec.specName;487 if (xcmChains.indexOf(spec.specName) > -1) return spec.specName;
500488
501 if (['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;489 if (['quartz', 'unique', 'sapphire'].indexOf(spec.specName) > -1) return spec.specName;
502 return 'opal';490 return 'opal';
503 }491 }
504492
1756 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1744 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);
1757 }1745 }
17581746
1759 return children.toJSON().map((x: any) => {1747 return children.toJSON().map((x: any) => ({collectionId: x.collection, tokenId: x.token}));
1760 return {collectionId: x.collection, tokenId: x.token};
1761 });
1762 }1748 }
17631749
2400 return {free: accountInfo.free.toBigInt(), frozen: accountInfo.frozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2386 return {free: accountInfo.free.toBigInt(), frozen: accountInfo.frozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};
2401 }2387 }
2388
2389 /**
2390 * Get total issuance
2391 * @returns
2392 */
2393 async getTotalIssuance(): Promise<bigint> {
2394 const total = (await this.helper.callRpc('api.query.balances.totalIssuance', []));
2395 return total.toBigInt();
2396 }
24022397
2403 async getLocked(address: TSubstrateAccount): Promise<[{ id: string, amount: bigint, reason: string }]> {2398 async getLocked(address: TSubstrateAccount): Promise<[{ id: string, amount: bigint, reason: string }]> {
2404 const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();2399 const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();
2405 return locks.map((lock: any) => { return {id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons}; });2400 return locks.map((lock: any) => ({id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons}));
2406 }2401 }
2407
2408 async getFrozen(address: TSubstrateAccount): Promise<[{ id: string, amount: bigint}]> {2402 async getFrozen(address: TSubstrateAccount): Promise<{ id: string, amount: bigint }[]> {
2409 const locks = (await this.helper.callRpc('api.query.balances.freezes', [address])).toHuman();2403 const locks = await this.helper.api!.query.balances.freezes(address);
2410 return locks.map((lock: any) => { return {id: lock.id, amount: BigInt(lock.amount.replace(/,/g, ''))}; });2404 return locks.map(lock => ({id: lock.id.toString(), amount: lock.amount.toBigInt()}));
2411 }2405 }
2412}2406}
24132407
2492 return this.subBalanceGroup.getSubstrateFull(address);2486 return this.subBalanceGroup.getSubstrateFull(address);
2493 }2487 }
2488
2489 /**
2490 * Get total issuance
2491 * @returns
2492 */
2493 getTotalIssuance(): Promise<bigint> {
2494 return this.subBalanceGroup.getTotalIssuance();
2495 }
24942496
2495 /**2497 /**
2496 * Get locked balances2498 * Get locked balances
2497 * @param address substrate address2499 * @param address substrate address
2498 * @returns locked balances with reason via api.query.balances.locks2500 * @returns locked balances with reason via api.query.balances.locks
2499 */2501 * @deprecated all the methods should switch to getFrozen
2502 */
2500 getLocked(address: TSubstrateAccount) {2503 getLocked(address: TSubstrateAccount) {
2501 return this.subBalanceGroup.getLocked(address);2504 return this.subBalanceGroup.getLocked(address);
2502 }2505 }
modifiedtests/src/vesting.test.tsdiffbeforeafterboth
103 expect(balanceSender.reserved).to.eq(0n);103 expect(balanceSender.reserved).to.eq(0n);
104 });104 });
105105
106 itSub.only('cannot send more tokens than have', async ({helper}) => {106 itSub('cannot send more tokens than have', async ({helper}) => {
107 const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor);107 const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor);
108 const schedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 100n * nominal};108 const schedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 100n * nominal};
109 const manyPeriodsSchedule = {start: 0n, period: 1n, periodCount: 100n, perPeriod: 10n * nominal};109 const manyPeriodsSchedule = {start: 0n, period: 1n, periodCount: 100n, perPeriod: 10n * nominal};