git.delta.rocks / unique-network / refs/commits / 1c0b76dadcbc

difftreelog

Merge branch 'develop' into chore/fix-warnings

Fahrrader2022-12-23parents: #8371463 #cf483e2.patch.diff
in: master

76 files changed

modified.docker/Dockerfile-try-runtimediffbeforeafterboth
46 echo "Fork from: $REPLICA_FROM\n" && \46 echo "Fork from: $REPLICA_FROM\n" && \
47 cargo build --features=try-runtime,${NETWORK}-runtime --release47 cargo build --features=try-runtime,${NETWORK}-runtime --release
4848
49CMD cargo run --features=try-runtime,${NETWORK}-runtime --release -- try-runtime -ltry-runtime::cli=debug --no-spec-check-panic on-runtime-upgrade live --uri $REPLICA_FROM49CMD cargo run --release --features ${NETWORK}-runtime,try-runtime -- try-runtime --runtime target/release/wbuild/${NETWORK}-runtime/${NETWORK}_runtime.compact.compressed.wasm -lruntime=debug -ltry-runtime::cli=debug on-runtime-upgrade --checks live --uri $REPLICA_FROM
5050
modified.envdiffbeforeafterboth
5STATEMINT_BUILD_BRANCH=release-parachains-v93205STATEMINT_BUILD_BRANCH=release-parachains-v9320
6ACALA_BUILD_BRANCH=2.11.06ACALA_BUILD_BRANCH=2.11.0
7MOONBEAM_BUILD_BRANCH=runtime-19017MOONBEAM_BUILD_BRANCH=runtime-1901
8UNIQUE_MAINNET_BRANCH=release-v9300338UNIQUE_MAINNET_BRANCH=release-v930033-fix-gas-price
9UNIQUE_REPLICA_FROM=wss://eu-ws.unique.network:4439UNIQUE_REPLICA_FROM=wss://eu-ws.unique.network:443
1010
11KUSAMA_MAINNET_BRANCH=release-v0.9.3511KUSAMA_MAINNET_BRANCH=release-v0.9.35
12STATEMINE_BUILD_BRANCH=release-parachains-v933012STATEMINE_BUILD_BRANCH=release-parachains-v9330
13KARURA_BUILD_BRANCH=release-karura-2.11.013KARURA_BUILD_BRANCH=release-karura-2.11.0
14MOONRIVER_BUILD_BRANCH=runtime-200014MOONRIVER_BUILD_BRANCH=runtime-2000
15QUARTZ_MAINNET_BRANCH=release-v93003415QUARTZ_MAINNET_BRANCH=release-v930034-fix-gas-price
16QUARTZ_REPLICA_FROM=wss://eu-ws-quartz.unique.network:44316QUARTZ_REPLICA_FROM=wss://eu-ws-quartz.unique.network:443
1717
18UNQWND_MAINNET_BRANCH=release-v0.9.3018UNQWND_MAINNET_BRANCH=release-v0.9.30
19WESTMINT_BUILD_BRANCH=parachains-v933019WESTMINT_BUILD_BRANCH=parachains-v9330
20OPAL_MAINNET_BRANCH=release-v93003420OPAL_MAINNET_BRANCH=release-v930034-fix-gas-price
21OPAL_REPLICA_FROM=wss://eu-ws-opal.unique.network:44321OPAL_REPLICA_FROM=wss://eu-ws-opal.unique.network:443
2222
23POLKADOT_LAUNCH_BRANCH=unique-network23POLKADOT_LAUNCH_BRANCH=unique-network
modified.github/workflows/ci-master.ymldiffbeforeafterboth
43 codestyle:43 codestyle:
44 uses: ./.github/workflows/codestyle.yml44 uses: ./.github/workflows/codestyle.yml
4545
46 polkadot-types:
47 uses: ./.github/workflows/polkadot-types.yml
added.github/workflows/polkadot-types.ymldiffbeforeafterboth

no changes

modified.github/workflows/schedule-trigger-for-develop-build.ymldiffbeforeafterboth
1name: schedule-trigger-for-develop-build1name: schedule-trigger-for-develop-build
2on:2on:
3 # update the branch ci/develop-scheduler every night3 # update the branch ci/develop-scheduler every night
4 schedule:4 # schedule:
5 - cron: '0 1 * * *'5 # - cron: '0 1 * * *'
6 # or update the branch manually6 # or update the branch manually
7 workflow_dispatch:7 workflow_dispatch:
8 # pull_request:8 # pull_request:
9 # branches: [ 'develop' ]9 # branches: [ 'develop' ]
modifiedCargo.lockdiffbeforeafterboth
2467[[package]]2467[[package]]
2468name = "fc-consensus"2468name = "fc-consensus"
2469version = "2.0.0-dev"2469version = "2.0.0-dev"
2470source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2470source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2471dependencies = [2471dependencies = [
2472 "async-trait",2472 "async-trait",
2473 "fc-db",2473 "fc-db",
2486[[package]]2486[[package]]
2487name = "fc-db"2487name = "fc-db"
2488version = "2.0.0-dev"2488version = "2.0.0-dev"
2489source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2489source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2490dependencies = [2490dependencies = [
2491 "fp-storage",2491 "fp-storage",
2492 "kvdb-rocksdb",2492 "kvdb-rocksdb",
2505[[package]]2505[[package]]
2506name = "fc-mapping-sync"2506name = "fc-mapping-sync"
2507version = "2.0.0-dev"2507version = "2.0.0-dev"
2508source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2508source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2509dependencies = [2509dependencies = [
2510 "fc-db",2510 "fc-db",
2511 "fp-consensus",2511 "fp-consensus",
2522[[package]]2522[[package]]
2523name = "fc-rpc"2523name = "fc-rpc"
2524version = "2.0.0-dev"2524version = "2.0.0-dev"
2525source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2525source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2526dependencies = [2526dependencies = [
2527 "ethereum 0.14.0",2527 "ethereum 0.14.0",
2528 "ethereum-types 0.14.1",2528 "ethereum-types 0.14.1",
2565[[package]]2565[[package]]
2566name = "fc-rpc-core"2566name = "fc-rpc-core"
2567version = "1.1.0-dev"2567version = "1.1.0-dev"
2568source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2568source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2569dependencies = [2569dependencies = [
2570 "ethereum 0.14.0",2570 "ethereum 0.14.0",
2571 "ethereum-types 0.14.1",2571 "ethereum-types 0.14.1",
2730[[package]]2730[[package]]
2731name = "fp-consensus"2731name = "fp-consensus"
2732version = "2.0.0-dev"2732version = "2.0.0-dev"
2733source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2733source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2734dependencies = [2734dependencies = [
2735 "ethereum 0.14.0",2735 "ethereum 0.14.0",
2736 "parity-scale-codec 3.2.1",2736 "parity-scale-codec 3.2.1",
2742[[package]]2742[[package]]
2743name = "fp-ethereum"2743name = "fp-ethereum"
2744version = "1.0.0-dev"2744version = "1.0.0-dev"
2745source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2745source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2746dependencies = [2746dependencies = [
2747 "ethereum 0.14.0",2747 "ethereum 0.14.0",
2748 "ethereum-types 0.14.1",2748 "ethereum-types 0.14.1",
2757[[package]]2757[[package]]
2758name = "fp-evm"2758name = "fp-evm"
2759version = "3.0.0-dev"2759version = "3.0.0-dev"
2760source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2760source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2761dependencies = [2761dependencies = [
2762 "evm",2762 "evm",
2763 "frame-support",2763 "frame-support",
2771[[package]]2771[[package]]
2772name = "fp-evm-mapping"2772name = "fp-evm-mapping"
2773version = "0.1.0"2773version = "0.1.0"
2774source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2774source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2775dependencies = [2775dependencies = [
2776 "frame-support",2776 "frame-support",
2777 "sp-core",2777 "sp-core",
2780[[package]]2780[[package]]
2781name = "fp-rpc"2781name = "fp-rpc"
2782version = "3.0.0-dev"2782version = "3.0.0-dev"
2783source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2783source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2784dependencies = [2784dependencies = [
2785 "ethereum 0.14.0",2785 "ethereum 0.14.0",
2786 "ethereum-types 0.14.1",2786 "ethereum-types 0.14.1",
2797[[package]]2797[[package]]
2798name = "fp-self-contained"2798name = "fp-self-contained"
2799version = "1.0.0-dev"2799version = "1.0.0-dev"
2800source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2800source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2801dependencies = [2801dependencies = [
2802 "ethereum 0.14.0",2802 "ethereum 0.14.0",
2803 "frame-support",2803 "frame-support",
2810[[package]]2810[[package]]
2811name = "fp-storage"2811name = "fp-storage"
2812version = "2.0.0"2812version = "2.0.0"
2813source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"2813source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
2814dependencies = [2814dependencies = [
2815 "parity-scale-codec 3.2.1",2815 "parity-scale-codec 3.2.1",
2816 "serde",2816 "serde",
5682[[package]]5682[[package]]
5683name = "pallet-base-fee"5683name = "pallet-base-fee"
5684version = "1.0.0"5684version = "1.0.0"
5685source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"5685source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
5686dependencies = [5686dependencies = [
5687 "fp-evm",5687 "fp-evm",
5688 "frame-support",5688 "frame-support",
5918[[package]]5918[[package]]
5919name = "pallet-ethereum"5919name = "pallet-ethereum"
5920version = "4.0.0-dev"5920version = "4.0.0-dev"
5921source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"5921source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
5922dependencies = [5922dependencies = [
5923 "ethereum 0.14.0",5923 "ethereum 0.14.0",
5924 "ethereum-types 0.14.1",5924 "ethereum-types 0.14.1",
5946[[package]]5946[[package]]
5947name = "pallet-evm"5947name = "pallet-evm"
5948version = "6.0.0-dev"5948version = "6.0.0-dev"
5949source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"5949source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
5950dependencies = [5950dependencies = [
5951 "environmental",5951 "environmental",
5952 "evm",5952 "evm",
6032[[package]]6032[[package]]
6033name = "pallet-evm-precompile-simple"6033name = "pallet-evm-precompile-simple"
6034version = "2.0.0-dev"6034version = "2.0.0-dev"
6035source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#db60b911813df1d82e60e0de7f3dfa290e60d2f0"6035source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14"
6036dependencies = [6036dependencies = [
6037 "fp-evm",6037 "fp-evm",
6038 "ripemd",6038 "ripemd",
12965 "sp-core",12965 "sp-core",
12966 "sp-finality-grandpa",12966 "sp-finality-grandpa",
12967 "sp-inherents",12967 "sp-inherents",
12968 "sp-io",
12968 "sp-keystore",12969 "sp-keystore",
12969 "sp-offchain",12970 "sp-offchain",
12970 "sp-runtime",12971 "sp-runtime",
modifiedcrates/evm-coder/procedural/src/abi_derive/derive_enum.rsdiffbeforeafterboth
143 )143 )
144}144}
145145
146pub fn check_and_count_options(de: &syn::DataEnum) -> syn::Result<usize> {146pub fn check_enum_fields(de: &syn::DataEnum) -> syn::Result<()> {
147 let mut count = 0;
148 for v in de.variants.iter() {147 for v in de.variants.iter() {
149 if !v.fields.is_empty() {148 if !v.fields.is_empty() {
150 return Err(syn::Error::new(149 return Err(syn::Error::new(
156 v.ident.span(),155 v.ident.span(),
157 "Enumeration options should not have an explicit specified value",156 "Enumeration options should not have an explicit specified value",
158 ));157 ));
159 } else {158 }
160 count += 1;
161 }
162 }159 }
163160
164 Ok(count)161 Ok(())
165}162}
166163
167pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> {164pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> {
modifiedcrates/evm-coder/procedural/src/abi_derive/mod.rsdiffbeforeafterboth
70) -> syn::Result<proc_macro2::TokenStream> {70) -> syn::Result<proc_macro2::TokenStream> {
71 let name = &ast.ident;71 let name = &ast.ident;
72 check_repr_u8(name, &ast.attrs)?;72 check_repr_u8(name, &ast.attrs)?;
73 check_enum_fields(de)?;
73 let docs = extract_docs(&ast.attrs)?;74 let docs = extract_docs(&ast.attrs)?;
74 let enum_options = de.variants.iter();75 let enum_options = de.variants.iter();
7576
modifiednode/cli/Cargo.tomldiffbeforeafterboth
122git = "https://github.com/paritytech/substrate"122git = "https://github.com/paritytech/substrate"
123branch = "polkadot-v0.9.36"123branch = "polkadot-v0.9.36"
124
125[dependencies.sp-io]
126git = "https://github.com/paritytech/substrate"
127branch = "polkadot-v0.9.36"
124128
125[dependencies.sp-finality-grandpa]129[dependencies.sp-finality-grandpa]
126git = "https://github.com/paritytech/substrate"130git = "https://github.com/paritytech/substrate"
modifiednode/cli/src/command.rsdiffbeforeafterboth
412 #[cfg(feature = "try-runtime")]412 #[cfg(feature = "try-runtime")]
413 Some(Subcommand::TryRuntime(cmd)) => {413 Some(Subcommand::TryRuntime(cmd)) => {
414 use std::{future::Future, pin::Pin};414 use std::{future::Future, pin::Pin};
415 use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch};
415416
416 let runner = cli.create_runner(cmd)?;417 let runner = cli.create_runner(cmd)?;
417418
429 Ok((430 Ok((
430 match config.chain_spec.runtime_id() {431 match config.chain_spec.runtime_id() {
431 #[cfg(feature = "unique-runtime")]432 #[cfg(feature = "unique-runtime")]
432 RuntimeId::Unique => Box::pin(cmd.run::<Block, UniqueRuntimeExecutor>(config)),433 RuntimeId::Unique => Box::pin(cmd.run::<Block, ExtendedHostFunctions<
434 sp_io::SubstrateHostFunctions,
435 <UniqueRuntimeExecutor as NativeExecutionDispatch>::ExtendHostFunctions,
436 >>()),
433437
434 #[cfg(feature = "quartz-runtime")]438 #[cfg(feature = "quartz-runtime")]
435 RuntimeId::Quartz => Box::pin(cmd.run::<Block, QuartzRuntimeExecutor>(config)),439 RuntimeId::Quartz => Box::pin(cmd.run::<Block, ExtendedHostFunctions<
440 sp_io::SubstrateHostFunctions,
441 <QuartzRuntimeExecutor as NativeExecutionDispatch>::ExtendHostFunctions,
442 >>()),
436443
437 RuntimeId::Opal => Box::pin(cmd.run::<Block, OpalRuntimeExecutor>(config)),444 RuntimeId::Opal => Box::pin(cmd.run::<Block, ExtendedHostFunctions<
445 sp_io::SubstrateHostFunctions,
446 <OpalRuntimeExecutor as NativeExecutionDispatch>::ExtendHostFunctions,
447 >>()),
438 RuntimeId::Unknown(chain) => return Err(no_runtime_err!(chain).into()),448 RuntimeId::Unknown(chain) => return Err(no_runtime_err!(chain).into()),
439 },449 },
440 task_manager,450 task_manager,
modifiednode/cli/src/service.rsdiffbeforeafterboth
106106
107#[cfg(feature = "unique-runtime")]107#[cfg(feature = "unique-runtime")]
108impl NativeExecutionDispatch for UniqueRuntimeExecutor {108impl NativeExecutionDispatch for UniqueRuntimeExecutor {
109 /// Only enable the benchmarking host functions when we actually want to benchmark.
110 #[cfg(feature = "runtime-benchmarks")]
109 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;111 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
112 /// Otherwise we only use the default Substrate host functions.
113 #[cfg(not(feature = "runtime-benchmarks"))]
114 type ExtendHostFunctions = ();
110115
111 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {116 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
112 unique_runtime::api::dispatch(method, data)117 unique_runtime::api::dispatch(method, data)
119124
120#[cfg(feature = "quartz-runtime")]125#[cfg(feature = "quartz-runtime")]
121impl NativeExecutionDispatch for QuartzRuntimeExecutor {126impl NativeExecutionDispatch for QuartzRuntimeExecutor {
127 /// Only enable the benchmarking host functions when we actually want to benchmark.
128 #[cfg(feature = "runtime-benchmarks")]
122 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;129 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
130 /// Otherwise we only use the default Substrate host functions.
131 #[cfg(not(feature = "runtime-benchmarks"))]
132 type ExtendHostFunctions = ();
123133
124 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {134 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
125 quartz_runtime::api::dispatch(method, data)135 quartz_runtime::api::dispatch(method, data)
131}141}
132142
133impl NativeExecutionDispatch for OpalRuntimeExecutor {143impl NativeExecutionDispatch for OpalRuntimeExecutor {
144 /// Only enable the benchmarking host functions when we actually want to benchmark.
145 #[cfg(feature = "runtime-benchmarks")]
134 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;146 type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
147 /// Otherwise we only use the default Substrate host functions.
148 #[cfg(not(feature = "runtime-benchmarks"))]
149 type ExtendHostFunctions = ();
135150
136 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {151 fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
137 opal_runtime::api::dispatch(method, data)152 opal_runtime::api::dispatch(method, data)
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
127pub struct OptionCrossAddress {127pub struct OptionCrossAddress {
128 /// Whether or not this CrossAdress is valid and has meaning.128 /// Whether or not this CrossAdress is valid and has meaning.
129 pub status: bool,129 pub status: bool,
130 /// The underlying CrossAddress. If the status is false, can be set to whatever.130 /// The underlying CrossAddress value. If the status is false, can be set to whatever.
131 pub value: CrossAddress,131 pub value: CrossAddress,
132}132}
133133
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
283283
284/// Ethereum representation of Optional value with CrossAddress.284/// Ethereum representation of Optional value with CrossAddress.
285struct OptionCrossAddress {285struct OptionCrossAddress {
286 /// TODO: field description
286 bool status;287 bool status;
288 /// TODO: field description
287 CrossAddress value;289 CrossAddress value;
288}290}
289291
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
228 owner: sub; collection: collection(owner); owner: cross_from_sub;228 owner: sub; collection: collection(owner); owner: cross_from_sub;
229 operator: cross_sub;229 operator: cross_sub;
230 };230 };
231 }: {<Pallet<T>>::set_allowance_for_all(&collection, &owner, &operator, true)}231 }: {<Pallet<T>>::set_allowance_for_all(&collection, &owner, &operator, true)?}
232232
233 allowance_for_all {233 allowance_for_all {
234 bench_init!{234 bench_init!{
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
22use frame_benchmarking::{benchmarks, account};22use frame_benchmarking::{benchmarks, account};
23use pallet_common::{23use pallet_common::{
24 bench_init,24 bench_init,
25 benchmarking::{create_collection_raw, property_key, property_value, create_data},25 benchmarking::{create_collection_raw, property_key, property_value},
26};26};
27use sp_core::H160;
28use sp_std::prelude::*;27use sp_std::prelude::*;
29use up_data_structs::{28use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, budget::Unlimited};
30 CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, CUSTOM_DATA_LIMIT,
31 budget::Unlimited,
32};
3329
34const SEED: u32 = 1;30const SEED: u32 = 1;
3531
36fn create_max_item_data<CrossAccountId: Ord>(32fn create_max_item_data<T: Config>(
37 users: impl IntoIterator<Item = (CrossAccountId, u128)>,33 users: impl IntoIterator<Item = (T::CrossAccountId, u128)>,
38) -> CreateItemData<CrossAccountId> {34) -> CreateItemData<T> {
39 CreateItemData {35 CreateItemData::<T> {
40 users: users36 users: users
41 .into_iter()37 .into_iter()
42 .collect::<BTreeMap<_, _>>()38 .collect::<BTreeMap<_, _>>()
51 sender: &T::CrossAccountId,47 sender: &T::CrossAccountId,
52 users: impl IntoIterator<Item = (T::CrossAccountId, u128)>,48 users: impl IntoIterator<Item = (T::CrossAccountId, u128)>,
53) -> Result<TokenId, DispatchError> {49) -> Result<TokenId, DispatchError> {
54 let data: CreateItemData<T::CrossAccountId> = create_max_item_data(users);50 let data: CreateItemData<T> = create_max_item_data::<T>(users);
55 <Pallet<T>>::create_item(&collection, sender, data, &Unlimited)?;51 <Pallet<T>>::create_item(&collection, sender, data, &Unlimited)?;
56 Ok(TokenId(<TokensMinted<T>>::get(&collection.id)))52 Ok(TokenId(<TokensMinted<T>>::get(&collection.id)))
57}53}
83 owner: sub; collection: collection(owner);79 owner: sub; collection: collection(owner);
84 sender: cross_from_sub(owner); to: cross_sub;80 sender: cross_from_sub(owner); to: cross_sub;
85 };81 };
86 let data = (0..b).map(|_| create_max_item_data([(to.clone(), 200)])).collect();82 let data = (0..b).map(|_| create_max_item_data::<T>([(to.clone(), 200)])).collect();
87 }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}83 }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
8884
89 create_multiple_items_ex_multiple_items {85 create_multiple_items_ex_multiple_items {
94 };90 };
95 let data = (0..b).map(|t| {91 let data = (0..b).map(|t| {
96 bench_init!(to: cross_sub(t););92 bench_init!(to: cross_sub(t););
97 create_max_item_data([(to, 200)])93 create_max_item_data::<T>([(to, 200)])
98 }).collect();94 }).collect();
99 }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}95 }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
10096
104 owner: sub; collection: collection(owner);100 owner: sub; collection: collection(owner);
105 sender: cross_from_sub(owner);101 sender: cross_from_sub(owner);
106 };102 };
107 let data = vec![create_max_item_data((0..b).map(|u| {103 let data = vec![create_max_item_data::<T>((0..b).map(|u| {
108 bench_init!(to: cross_sub(u););104 bench_init!(to: cross_sub(u););
109 (to, 200)105 (to, 200)
110 }))].try_into().unwrap();106 }))].try_into().unwrap();
296 owner: sub; collection: collection(owner); owner: cross_from_sub;292 owner: sub; collection: collection(owner); owner: cross_from_sub;
297 operator: cross_sub;293 operator: cross_sub;
298 };294 };
299 }: {<Pallet<T>>::set_allowance_for_all(&collection, &owner, &operator, true)}295 }: {<Pallet<T>>::set_allowance_for_all(&collection, &owner, &operator, true)?}
300296
301 allowance_for_all {297 allowance_for_all {
302 bench_init!{298 bench_init!{
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
43 TotalSupply, weights::WeightInfo,43 TotalSupply, weights::WeightInfo,
44};44};
4545
46/// Refungible token handle contains information about token's collection and id
47///
48/// RefungibleTokenHandle doesn't check token's existance upon creation
46pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);49pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
4750
48#[solidity_interface(name = ERC1633)]51#[solidity_interface(name = ERC1633)]
modifiedruntime/common/ethereum/sponsoring.rsdiffbeforeafterboth
32 Config as FungibleConfig,32 Config as FungibleConfig,
33 erc::{UniqueFungibleCall, ERC20Call},33 erc::{UniqueFungibleCall, ERC20Call},
34};34};
35use pallet_refungible::Config as RefungibleConfig;35use pallet_refungible::{
36 Config as RefungibleConfig,
37 erc::UniqueRefungibleCall,
38 erc_token::{RefungibleTokenHandle, UniqueRefungibleTokenCall},
39 RefungibleHandle,
40};
36use pallet_unique::Config as UniqueConfig;41use pallet_unique::Config as UniqueConfig;
37use sp_std::prelude::*;42use sp_std::prelude::*;
38use up_data_structs::{CollectionMode, CreateItemData, CreateNftData, TokenId};43use up_data_structs::{
44 CollectionMode, CreateItemData, CreateNftData, mapping::TokenAddressMapping, TokenId,
45};
39use up_sponsorship::SponsorshipHandler;46use up_sponsorship::SponsorshipHandler;
40
41use crate::{Runtime, runtime_common::sponsoring::*};47use crate::{Runtime, runtime_common::sponsoring::*};
48
49mod refungible;
4250
43pub type EvmSponsorshipHandler = (51pub type EvmSponsorshipHandler = (
44 UniqueEthSponsorshipHandler<Runtime>,52 UniqueEthSponsorshipHandler<Runtime>,
53 who: &T::CrossAccountId,61 who: &T::CrossAccountId,
54 call_context: &CallContext,62 call_context: &CallContext,
55 ) -> Option<T::CrossAccountId> {63 ) -> Option<T::CrossAccountId> {
56 let collection_id = map_eth_to_id(&call_context.contract_address)?;64 if let Some(collection_id) = map_eth_to_id(&call_context.contract_address) {
57 let collection = <CollectionHandle<T>>::new(collection_id)?;65 let collection = <CollectionHandle<T>>::new(collection_id)?;
58 let sponsor = collection.sponsorship.sponsor()?.clone();66 let sponsor = collection.sponsorship.sponsor()?.clone();
59 let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;67 let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;
106 _ => None,116 _ => None,
107 }117 }
108 }118 }
119 CollectionMode::ReFungible => {
120 let call = <UniqueRefungibleCall<T>>::parse(method_id, &mut reader).ok()??;
121 refungible::call_sponsor(call, collection, who).map(|()| sponsor)
122 }
109 CollectionMode::Fungible(_) => {123 CollectionMode::Fungible(_) => {
110 let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;124 let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;
111 #[allow(clippy::single_match)]
112 match call {125 match call {
113 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {126 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
114 withdraw_transfer::<T>(&collection, who, &TokenId::default())127 withdraw_transfer::<T>(&collection, who, &TokenId::default())
126 _ => None,139 _ => None,
127 }140 }
128 }141 }
129 _ => None,
130 }?))142 }?))
143 } else {
144 let (collection_id, token_id) =
145 T::EvmTokenAddressMapping::address_to_token(&call_context.contract_address)?;
146 let collection = <CollectionHandle<T>>::new(collection_id)?;
147 if collection.mode != CollectionMode::ReFungible {
148 return None;
149 }
150 let sponsor = collection.sponsorship.sponsor()?.clone();
151 let rft_collection = RefungibleHandle::cast(collection);
152 // Token existance isn't checked at this point and should be checked in `withdraw` method.
153 let token = RefungibleTokenHandle(rft_collection, token_id);
154
155 let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?;
156 let call = <UniqueRefungibleTokenCall<T>>::parse(method_id, &mut reader).ok()??;
157 Some(T::CrossAccountId::from_sub(
158 refungible::token_call_sponsor(call, token, who).map(|()| sponsor)?,
159 ))
160 }
131 }161 }
132}162}
163
164mod common {
165 use super::*;
166
167 use pallet_common::erc::{CollectionCall};
168
169 pub fn collection_call_sponsor<T>(
170 call: CollectionCall<T>,
171 _collection: CollectionHandle<T>,
172 _who: &T::CrossAccountId,
173 ) -> Option<()>
174 where
175 T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,
176 {
177 use CollectionCall::*;
178
179 match call {
180 // Readonly
181 ERC165Call(_, _)
182 | CollectionProperty { .. }
183 | CollectionProperties { .. }
184 | HasCollectionPendingSponsor
185 | CollectionSponsor
186 | ContractAddress
187 | AllowlistedCross { .. }
188 | IsOwnerOrAdminEth { .. }
189 | IsOwnerOrAdminCross { .. }
190 | CollectionOwner
191 | CollectionAdmins
192 | CollectionLimits
193 | CollectionNestingRestrictedIds
194 | CollectionNestingPermissions
195 | UniqueCollectionType => None,
196
197 // Not sponsored
198 AddToCollectionAllowList { .. }
199 | AddToCollectionAllowListCross { .. }
200 | RemoveFromCollectionAllowList { .. }
201 | RemoveFromCollectionAllowListCross { .. }
202 | AddCollectionAdminCross { .. }
203 | RemoveCollectionAdminCross { .. }
204 | AddCollectionAdmin { .. }
205 | RemoveCollectionAdmin { .. }
206 | SetNestingBool { .. }
207 | SetNesting { .. }
208 | SetCollectionAccess { .. }
209 | SetCollectionMintMode { .. }
210 | SetOwner { .. }
211 | ChangeCollectionOwnerCross { .. }
212 | SetCollectionProperty { .. }
213 | SetCollectionProperties { .. }
214 | DeleteCollectionProperty { .. }
215 | DeleteCollectionProperties { .. }
216 | SetCollectionSponsor { .. }
217 | SetCollectionSponsorCross { .. }
218 | SetCollectionLimit { .. }
219 | ConfirmCollectionSponsorship
220 | RemoveCollectionSponsor => None,
221 }
222 }
223}
133224
addedruntime/common/ethereum/sponsoring/refungible.rsdiffbeforeafterboth

no changes

modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
780780
781 #[cfg(feature = "try-runtime")]781 #[cfg(feature = "try-runtime")]
782 impl frame_try_runtime::TryRuntime<Block> for Runtime {782 impl frame_try_runtime::TryRuntime<Block> for Runtime {
783 fn on_runtime_upgrade() -> (frame_support::pallet_prelude::Weight, frame_support::pallet_prelude::Weight) {783 fn on_runtime_upgrade(checks: bool) -> (frame_support::pallet_prelude::Weight, frame_support::pallet_prelude::Weight) {
784 log::info!("try-runtime::on_runtime_upgrade unique-chain.");784 log::info!("try-runtime::on_runtime_upgrade unique-chain.");
785 let weight = Executive::try_runtime_upgrade().unwrap();785 let weight = Executive::try_runtime_upgrade(checks).unwrap();
786 (weight, crate::config::substrate::RuntimeBlockWeights::get().max_block)786 (weight, crate::config::substrate::RuntimeBlockWeights::get().max_block)
787 }787 }
788788
789 fn execute_block(789 fn execute_block(
790 block: Block,790 block: Block,
791 state_root_check: bool,791 state_root_check: bool,
792 signature_check: bool,
792 select: frame_try_runtime::TryStateSelect793 select: frame_try_runtime::TryStateSelect
793 ) -> frame_support::pallet_prelude::Weight {794 ) -> frame_support::pallet_prelude::Weight {
794 log::info!(795 log::info!(
799 select,800 select,
800 );801 );
801802
802 Executive::try_execute_block(block, state_root_check, select).unwrap()803 Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
803 }804 }
804 }805 }
805 }806 }
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
91 'pallet-unique-scheduler-v2/try-runtime',91 'pallet-unique-scheduler-v2/try-runtime',
92 'pallet-maintenance/try-runtime',92 'pallet-maintenance/try-runtime',
93 'pallet-test-utils?/try-runtime',93 'pallet-test-utils?/try-runtime',
94 'fp-self-contained/try-runtime',
94]95]
95std = [96std = [
96 'codec/std',97 'codec/std',
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
86 'pallet-evm-transaction-payment/try-runtime',86 'pallet-evm-transaction-payment/try-runtime',
87 'pallet-evm-migration/try-runtime',87 'pallet-evm-migration/try-runtime',
88 'pallet-maintenance/try-runtime',88 'pallet-maintenance/try-runtime',
89 'fp-self-contained/try-runtime',
89]90]
90std = [91std = [
91 'codec/std',92 'codec/std',
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
87 'pallet-evm-transaction-payment/try-runtime',87 'pallet-evm-transaction-payment/try-runtime',
88 'pallet-evm-migration/try-runtime',88 'pallet-evm-migration/try-runtime',
89 'pallet-maintenance/try-runtime',89 'pallet-maintenance/try-runtime',
90 'fp-self-contained/try-runtime',
90]91]
91std = [92std = [
92 'codec/std',93 'codec/std',
modifiedtests/.eslintrc.jsondiffbeforeafterboth
18 "mocha"18 "mocha"
19 ],19 ],
20 "rules": {20 "rules": {
21 "@typescript-eslint/no-floating-promises": [
22 "error"
23 ],
21 "indent": [24 "indent": [
22 "error",25 "error",
23 2,26 2,
modifiedtests/package.jsondiffbeforeafterboth
11 "@types/chai-subset": "^1.3.3",11 "@types/chai-subset": "^1.3.3",
12 "@types/mocha": "^10.0.0",12 "@types/mocha": "^10.0.0",
13 "@types/node": "^18.11.2",13 "@types/node": "^18.11.2",
14 "@typescript-eslint/eslint-plugin": "^5.40.1",14 "@typescript-eslint/eslint-plugin": "^5.47.0",
15 "@typescript-eslint/parser": "^5.40.1",15 "@typescript-eslint/parser": "^5.47.0",
16 "chai": "^4.3.6",16 "chai": "^4.3.6",
17 "chai-subset": "^1.6.0",17 "chai-subset": "^1.6.0",
18 "eslint": "^8.25.0",18 "eslint": "^8.25.0",
modifiedtests/src/apiConsts.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/app-promotion.seqtest.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/approve.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/burnItem.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/calibrate.tsdiffbeforeafterboth
295 }295 }
296}296}
297297
298// eslint-disable-next-line @typescript-eslint/no-floating-promises
298(async () => {299(async () => {
299 await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {300 await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => {
300 // Subsequent runs reduce error, as price line is not actually straight, this is a curve301 // Subsequent runs reduce error, as price line is not actually straight, this is a curve
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/eth/abi/reFungibleDeprecated.jsondiffbeforeafterboth
98 "outputs": [],98 "outputs": [],
99 "stateMutability": "nonpayable",99 "stateMutability": "nonpayable",
100 "type": "function"100 "type": "function"
101 }101 },
102 {
103 "inputs": [
104 { "internalType": "address", "name": "to", "type": "address" },
105 { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
106 ],
107 "name": "mintBulk",
108 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
109 "stateMutability": "nonpayable",
110 "type": "function"
111 },
112 {
113 "inputs": [
114 { "internalType": "address", "name": "to", "type": "address" },
115 {
116 "components": [
117 { "internalType": "uint256", "name": "field_0", "type": "uint256" },
118 { "internalType": "string", "name": "field_1", "type": "string" }
119 ],
120 "internalType": "struct Tuple0[]",
121 "name": "tokens",
122 "type": "tuple[]"
123 }
124 ],
125 "name": "mintBulkWithTokenURI",
126 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
127 "stateMutability": "nonpayable",
128 "type": "function"
129 }
102]130]
103131
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
183183
184/// Ethereum representation of Optional value with CrossAddress.184/// Ethereum representation of Optional value with CrossAddress.
185struct OptionCrossAddress {185struct OptionCrossAddress {
186 /// TODO: field description
186 bool status;187 bool status;
188 /// TODO: field description
187 CrossAddress value;189 CrossAddress value;
188}190}
189191
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
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
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {usingPlaygrounds} from '../util/index';18import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index';
19import {itEth, expect} from './util';19import {itEth, expect} from './util';
2020
21describe('evm 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;
101 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;101 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
102102
103 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});103 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
104 let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
105 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
104 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;106 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
105107
106 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});108 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
107109
108 const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});110 sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
109 expect(sponsorTuple.eth).to.be.eq('0x0000000000000000000000000000000000000000');111 expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
110 }));112 }));
111113
112 [114 [
142 expect(nextTokenId).to.be.equal('1');144 expect(nextTokenId).to.be.equal('1');
143145
144 // Set collection permissions:146 // Set collection permissions:
145 const oldPermissions = (await collectionSub.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();147 const oldPermissions = (await collectionSub.getData())!.raw.permissions;
146 expect(oldPermissions.mintMode).to.be.false;148 expect(oldPermissions.mintMode).to.be.false;
147 expect(oldPermissions.access).to.be.equal('Normal');149 expect(oldPermissions.access).to.be.equal('Normal');
148150
149 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});151 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
150 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});152 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
151 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});153 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
152154
153 const newPermissions = (await collectionSub.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();155 const newPermissions = (await collectionSub.getData())!.raw.permissions;
154 expect(newPermissions.mintMode).to.be.true;156 expect(newPermissions.mintMode).to.be.true;
155 expect(newPermissions.access).to.be.equal('AllowList');157 expect(newPermissions.access).to.be.equal('AllowList');
156158
157 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));159 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
158 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));160 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
161 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
159162
160 // User can mint token without balance:163 // User can mint token without balance:
161 {164 {
179182
180 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');183 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
181 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);184 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
182 expect(userBalanceAfter).to.be.eq(0n);185 expect(userBalanceAfter).to.be.eq(userBalanceBefore);
183 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;186 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
184 }187 }
185 }));188 }));
316 });319 });
317});320});
321
322describe('evm RFT collection sponsoring', () => {
323 let donor: IKeyringPair;
324 let alice: IKeyringPair;
325 let nominal: bigint;
326
327 before(async function() {
328 await usingPlaygrounds(async (helper, privateKey) => {
329 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
330 donor = await privateKey({filename: __filename});
331 [alice] = await helper.arrange.createAccounts([100n], donor);
332 nominal = helper.balance.getOneTokenNominal();
333 });
334 });
335
336 [
337 'mintCross',
338 'mintWithTokenURI',
339 ].map(testCase =>
340 itEth(`[${testCase}] sponsors mint transactions`, async ({helper}) => {
341 const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}, tokenPropertyPermissions: [
342 {key: 'URI', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
343 ]});
344
345 const owner = await helper.eth.createAccountWithBalance(donor);
346 await collection.setSponsor(alice, alice.address);
347 await collection.confirmSponsorship(alice);
348
349 const minter = helper.eth.createAccount();
350 const minterCross = helper.ethCrossAccount.fromAddress(minter);
351 expect(await helper.balance.getEthereum(minter)).to.equal(0n);
352
353 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
354 const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);
355
356 await collection.addToAllowList(alice, {Ethereum: minter});
357 await collection.addAdmin(alice, {Ethereum: owner});
358 const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
359 await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/')
360 .send();
361
362 let mintingResult;
363 let tokenId;
364 switch (testCase) {
365 case 'mintCross':
366 mintingResult = await contract.methods.mintCross(minterCross, []).send();
367 break;
368 case 'mintWithTokenURI':
369 mintingResult = await contract.methods.mintWithTokenURI(minter, 'Test URI').send();
370 tokenId = mintingResult.events.Transfer.returnValues.tokenId;
371 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
372 break;
373 }
374
375 const events = helper.eth.normalizeEvents(mintingResult.events);
376 expect(events).to.deep.include({
377 address: collectionAddress,
378 event: 'Transfer',
379 args: {
380 from: '0x0000000000000000000000000000000000000000',
381 to: minter,
382 tokenId: '1',
383 },
384 });
385 }));
386
387 [
388 'setCollectionSponsorCross',
389 'setCollectionSponsor', // Soft-deprecated
390 ].map(testCase =>
391 itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
392 const owner = await helper.eth.createAccountWithBalance(donor);
393 const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
394
395 let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
396 const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
397 const sponsor = await helper.eth.createAccountWithBalance(donor);
398 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
399 const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, testCase === 'setCollectionSponsor');
400
401 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
402 result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});
403 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
404
405 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
406 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
407
408 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
409
410 const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
411 expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
412 }));
413
414 [
415 'setCollectionSponsorCross',
416 'setCollectionSponsor', // Soft-deprecated
417 ].map(testCase =>
418 itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {
419 const owner = await helper.eth.createAccountWithBalance(donor);
420 const sponsorEth = await helper.eth.createAccountWithBalance(donor);
421 const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
422
423 const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');
424
425 const collectionSub = helper.rft.getCollectionObject(collectionId);
426 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
427
428 // Set collection sponsor:
429 await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});
430 let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
431 expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
432 // Account cannot confirm sponsorship if it is not set as a sponsor
433 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
434
435 // Sponsor can confirm sponsorship:
436 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
437 sponsorship = (await collectionSub.getData())!.raw.sponsorship;
438 expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
439
440 // Create user with no balance:
441 const user = helper.eth.createAccount();
442 const userCross = helper.ethCrossAccount.fromAddress(user);
443 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
444 expect(nextTokenId).to.be.equal('1');
445
446 // Set collection permissions:
447 const oldPermissions = (await collectionSub.getData())!.raw.permissions;
448 expect(oldPermissions.mintMode).to.be.false;
449 expect(oldPermissions.access).to.be.equal('Normal');
450
451 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
452 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
453 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
454
455 const newPermissions = (await collectionSub.getData())!.raw.permissions;
456 expect(newPermissions.mintMode).to.be.true;
457 expect(newPermissions.access).to.be.equal('AllowList');
458
459 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
460 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
461 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
462
463 // User can mint token without balance:
464 {
465 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
466 const events = helper.eth.normalizeEvents(result.events);
467
468 expect(events).to.deep.include({
469 address: collectionAddress,
470 event: 'Transfer',
471 args: {
472 from: '0x0000000000000000000000000000000000000000',
473 to: user,
474 tokenId: '1',
475 },
476 });
477
478 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
479 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
480 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
481
482 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
483 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
484 expect(userBalanceAfter).to.be.eq(userBalanceBefore);
485 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
486 }
487 }));
488
489 [
490 'setCollectionSponsorCross',
491 'setCollectionSponsor', // Soft-deprecated
492 ].map(testCase =>
493 itEth(`[${testCase}] Check that collection admin EVM transaction spend money from sponsor eth address`, async ({helper}) => {
494 const owner = await helper.eth.createAccountWithBalance(donor);
495 const sponsor = await helper.eth.createAccountWithBalance(donor);
496 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
497
498 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
499
500 const collectionSub = helper.rft.getCollectionObject(collectionId);
501 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
502 // Set collection sponsor:
503 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
504 await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
505 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
506 let collectionData = (await collectionSub.getData())!;
507 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
508 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
509 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
510
511 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
512 collectionData = (await collectionSub.getData())!;
513 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
514 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
515 const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
516 const sponsorSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.ethToSubstrate(sponsor));
517 const actualSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub)));
518 expect(actualSubAddress).to.be.equal(sponsorSubAddress);
519
520 const user = helper.eth.createAccount();
521 const userCross = helper.ethCrossAccount.fromAddress(user);
522 await collectionEvm.methods.addCollectionAdminCross(userCross).send();
523
524 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
525 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
526
527 const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
528 const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
529
530 const events = helper.eth.normalizeEvents(mintingResult.events);
531 const address = helper.ethAddress.fromCollectionId(collectionId);
532
533 expect(events).to.deep.include({
534 address,
535 event: 'Transfer',
536 args: {
537 from: '0x0000000000000000000000000000000000000000',
538 to: user,
539 tokenId: '1',
540 },
541 });
542 expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
543
544 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
545 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
546 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
547 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
548 }));
549
550 itEth('Check that collection admin EVM transaction spend money from sponsor sub address', async ({helper}) => {
551 const owner = await helper.eth.createAccountWithBalance(donor);
552 const sponsor = alice;
553 const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
554
555 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
556
557 const collectionSub = helper.rft.getCollectionObject(collectionId);
558 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
559 // Set collection sponsor:
560 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
561 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
562 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
563 let collectionData = (await collectionSub.getData())!;
564 expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(sponsor.address);
565 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
566
567 await collectionSub.confirmSponsorship(sponsor);
568 collectionData = (await collectionSub.getData())!;
569 expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(sponsor.address);
570 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
571 const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
572 expect(BigInt(sponsorStruct.sub)).to.be.equal(BigInt('0x' + Buffer.from(sponsor.addressRaw).toString('hex')));
573
574 const user = helper.eth.createAccount();
575 const userCross = helper.ethCrossAccount.fromAddress(user);
576 await collectionEvm.methods.addCollectionAdminCross(userCross).send();
577
578 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
579 const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
580
581 const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
582 const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
583
584 const events = helper.eth.normalizeEvents(mintingResult.events);
585
586 expect(events).to.deep.include({
587 address: collectionAddress,
588 event: 'Transfer',
589 args: {
590 from: '0x0000000000000000000000000000000000000000',
591 to: user,
592 tokenId: '1',
593 },
594 });
595 expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
596
597 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
598 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
599 const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
600 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
601 });
602
603 itEth('Sponsoring collection from substrate address via access list', async ({helper}) => {
604 const owner = await helper.eth.createAccountWithBalance(donor);
605 const user = helper.eth.createAccount();
606 const userCross = helper.ethCrossAccount.fromAddress(user);
607 const sponsor = alice;
608 const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
609
610 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
611 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
612
613 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});
614
615 const collectionSub = helper.rft.getCollectionObject(collectionId);
616 await collectionSub.confirmSponsorship(sponsor);
617
618 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
619 expect(nextTokenId).to.be.equal('1');
620
621 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
622
623 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
624 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
625
626 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
627 const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
628 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
629
630 {
631 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
632 expect(nextTokenId).to.be.equal('1');
633 const mintingResult = await collectionEvm.methods.mintWithTokenURI(
634 user,
635 'Test URI',
636 ).send({from: user});
637
638 const events = helper.eth.normalizeEvents(mintingResult.events);
639
640
641 expect(events).to.deep.include({
642 address: collectionAddress,
643 event: 'Transfer',
644 args: {
645 from: '0x0000000000000000000000000000000000000000',
646 to: user,
647 tokenId: nextTokenId,
648 },
649 });
650
651 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
652 const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
653 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
654
655 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
656 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
657 expect(userBalanceAfter).to.be.eq(userBalanceBefore);
658 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
659 }
660 });
661
662 itEth('Can reassign collection sponsor', async ({helper}) => {
663 const owner = await helper.eth.createAccountWithBalance(donor);
664 const sponsorEth = await helper.eth.createAccountWithBalance(donor);
665 const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
666 const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
667 const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
668
669 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
670 const collectionSub = helper.rft.getCollectionObject(collectionId);
671 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
672
673 // Set and confirm sponsor:
674 await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
675 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
676
677 // Can reassign sponsor:
678 await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
679 const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
680 expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
681 });
682
683 [
684 'transfer',
685 'transferCross',
686 'transferFrom',
687 'transferFromCross',
688 ].map(testCase =>
689 itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
690 const owner = await helper.eth.createAccountWithBalance(donor);
691
692 const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
693 const sponsor = await helper.eth.createAccountWithBalance(donor);
694 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
695 const receiver = await helper.eth.createAccountWithBalance(donor);
696 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
697
698 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
699 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
700
701 const user = await helper.eth.createAccountWithBalance(donor);
702 const userCross = helper.ethCrossAccount.fromAddress(user);
703 await collectionEvm.methods.addCollectionAdminCross(userCross).send();
704
705 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
706 const tokenId = result.events.Transfer.returnValues.tokenId;
707
708 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
709 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
710 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
711
712 switch (testCase) {
713 case 'transfer':
714 await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});
715 break;
716 case 'transferCross':
717 await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
718 break;
719 case 'transferFrom':
720 await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});
721 break;
722 case 'transferFromCross':
723 await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
724 break;
725 }
726
727 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
728 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
729 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
730 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
731 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
732 expect(userBalanceAfter).to.be.eq(userBalanceBefore);
733 }));
734});
735
736describe('evm RFT token sponsoring', () => {
737 let donor: IKeyringPair;
738
739 before(async function() {
740 await usingPlaygrounds(async (helper, privateKey) => {
741 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
742 donor = await privateKey({filename: __filename});
743 });
744 });
745
746 [
747 'transfer',
748 'transferCross',
749 'transferFrom',
750 'transferFromCross',
751 ].map(testCase =>
752 itEth(`[${testCase}] Check that token piece transfer via EVM spend money from sponsor address`, async ({helper}) => {
753 const owner = await helper.eth.createAccountWithBalance(donor);
754
755 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
756 const sponsor = await helper.eth.createAccountWithBalance(donor);
757 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
758 const receiver = await helper.eth.createAccountWithBalance(donor);
759 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
760
761 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
762 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
763
764 const user = await helper.eth.createAccountWithBalance(donor);
765 const userCross = helper.ethCrossAccount.fromAddress(user);
766 await collectionEvm.methods.addCollectionAdminCross(userCross).send();
767
768 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
769 const tokenId = result.events.Transfer.returnValues.tokenId;
770
771 const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);
772 await tokenContract.methods.repartition(2).send();
773
774 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
775 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
776 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
777
778 switch (testCase) {
779 case 'transfer':
780 await tokenContract.methods.transfer(receiver, 1).send();
781 break;
782 case 'transferCross':
783 await tokenContract.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
784 break;
785 case 'transferFrom':
786 await tokenContract.methods.transferFrom(user, receiver, 1).send();
787 break;
788 case 'transferFromCross':
789 await tokenContract.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), 1).send();
790 break;
791 }
792
793 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
794 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
795 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
796 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
797 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
798 expect(userBalanceAfter).to.be.eq(userBalanceBefore);
799 }));
800
801 [
802 'approve',
803 'approveCross',
804 ].map(testCase =>
805 itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => {
806 const owner = await helper.eth.createAccountWithBalance(donor);
807
808 const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
809 const sponsor = await helper.eth.createAccountWithBalance(donor);
810 const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
811 const receiver = await helper.eth.createAccountWithBalance(donor);
812 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
813
814 await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
815 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
816
817 const user = await helper.eth.createAccountWithBalance(donor);
818 const userCross = helper.ethCrossAccount.fromAddress(user);
819 await collectionEvm.methods.addCollectionAdminCross(userCross).send();
820
821 const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
822 const tokenId = result.events.Transfer.returnValues.tokenId;
823
824 const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);
825 await tokenContract.methods.repartition(2).send();
826
827 const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
828 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
829 const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
830
831 switch (testCase) {
832 case 'approve':
833 await tokenContract.methods.approve(receiver, 1).send();
834 break;
835 case 'approveCross':
836 await tokenContract.methods.approveCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
837 break;
838 }
839
840 const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
841 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
842 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
843 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
844 const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
845 expect(userBalanceAfter).to.be.eq(userBalanceBefore);
846 }));
847});
318848
849
modifiedtests/src/eth/createFTCollection.test.tsdiffbeforeafterboth
32 });32 });
33 });33 });
3434
35 // TODO move sponsorship tests to another file:
35 // Soft-deprecated36 // Soft-deprecated
36 itEth('[eth] Set sponsorship', async ({helper}) => {37 itEth('[eth] Set sponsorship', async ({helper}) => {
37 const owner = await helper.eth.createAccountWithBalance(donor);38 const owner = await helper.eth.createAccountWithBalance(donor);
94 .methods.isCollectionExist(collectionAddress).call())95 .methods.isCollectionExist(collectionAddress).call())
95 .to.be.true;96 .to.be.true;
97
98 // check collectionOwner:
99 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
100 const collectionOwner = await collectionEvm.methods.collectionOwner().call();
101 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
96 });102 });
97103
98 itEth('destroyCollection', async ({helper}) => {104 itEth('destroyCollection', async ({helper}) => {
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
135 .methods.isCollectionExist(collectionAddress).call())135 .methods.isCollectionExist(collectionAddress).call())
136 .to.be.true;136 .to.be.true;
137
138 // check collectionOwner:
139 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
140 const collectionOwner = await collectionEvm.methods.collectionOwner().call();
141 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
137 });142 });
138});143});
139144
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
88 ]);88 ]);
89 });89 });
90
91 // this test will occasionally fail when in async environment.
92 itEth.skip('Check collection address exist', async ({helper}) => {
93 const owner = await helper.eth.createAccountWithBalance(donor);
94
95 const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;
96 const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);
97 const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
98
99 expect(await collectionHelpers.methods
100 .isCollectionExist(expectedCollectionAddress)
101 .call()).to.be.false;
102
103 await collectionHelpers.methods
104 .createRFTCollection('A', 'A', 'A')
105 .send({value: Number(2n * helper.balance.getOneTokenNominal())});
106
107 expect(await collectionHelpers.methods
108 .isCollectionExist(expectedCollectionAddress)
109 .call()).to.be.true;
110 });
11190
112 // Soft-deprecated91 // Soft-deprecated
113 itEth('[eth] Set sponsorship', async ({helper}) => {92 itEth('[eth] Set sponsorship', async ({helper}) => {
167 .methods.isCollectionExist(collectionAddress).call())146 .methods.isCollectionExist(collectionAddress).call())
168 .to.be.true;147 .to.be.true;
148
149 // check collectionOwner:
150 const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true);
151 const collectionOwner = await collectionEvm.methods.collectionOwner().call();
152 expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true));
169 });153 });
170});154});
171155
modifiedtests/src/eth/evmCoder.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
167 expect(event.returnValues.to).to.be.equal(receiver);167 expect(event.returnValues.to).to.be.equal(receiver);
168168
169 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');169 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
170 console.log(await contract.methods.crossOwnerOf(tokenId).call());
171 expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']);170 expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']);
172 // TODO: this wont work right now, need release 919000 first171 // TODO: this wont work right now, need release 919000 first
173 // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();172 // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();
modifiedtests/src/eth/proxyContract.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/eth/scheduling.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/eth/util/index.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/fungible.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/inflation.seqtest.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/limits.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/collectionProperties.seqtest.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/collectionProperties.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/graphs.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/propertyPermissions.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/tokenProperties.seqtest.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/tokenProperties.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/nextSponsoring.test.tsdiffbeforeafterboth
52 await token.transfer(alice, {Substrate: bob.address});52 await token.transfer(alice, {Substrate: bob.address});
53 expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);53 expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
5454
55 // Non-existing token 55 // Non-existing token
56 expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;56 expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
57 });57 });
5858
91 await token.transfer(alice, {Substrate: bob.address});91 await token.transfer(alice, {Substrate: bob.address});
92 expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);92 expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT);
9393
94 // Non-existing token 94 // Non-existing token
95 expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;95 expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null;
96 });96 });
97});97});
modifiedtests/src/refungible.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/rpc.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/scheduler.seqtest.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/setPermissions.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/transfer.nload.tsdiffbeforeafterboth
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
17/* eslint-disable @typescript-eslint/no-floating-promises */
17import os from 'os';18import os from 'os';
18import {IKeyringPair} from '@polkadot/types/types';19import {IKeyringPair} from '@polkadot/types/types';
19import {usingPlaygrounds} from './util';20import {usingPlaygrounds} from './util';
modifiedtests/src/transfer.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/util/globalSetup.tsdiffbeforeafterboth
17 // 2. Create donors for test files17 // 2. Create donors for test files
18 await fundFilenamesWithRetries(3)18 await fundFilenamesWithRetries(3)
19 .then((result) => {19 .then((result) => {
20 if (!result) Promise.reject();20 if (!result) throw Error('Some problems with fundFilenamesWithRetries');
21 });21 });
2222
23 // 3. Configure App Promotion 23 // 3. Configure App Promotion
24 const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]);24 const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]);
25 if (missingPallets.length === 0) {25 if (missingPallets.length === 0) {
26 const superuser = await privateKey('//Alice');26 const superuser = await privateKey('//Alice');
38 }38 }
39 } catch (error) {39 } catch (error) {
40 console.error(error);40 console.error(error);
41 Promise.reject();41 throw Error('Error during globalSetup');
42 }42 }
43 });43 });
44};44};
modifiedtests/src/util/index.tsdiffbeforeafterboth
41 else {41 else {
42 const actualSeed = getTestSeed(seed.filename);42 const actualSeed = getTestSeed(seed.filename);
43 let account = helper.util.fromSeed(actualSeed, ss58Format);43 let account = helper.util.fromSeed(actualSeed, ss58Format);
44 // here's to hoping that no 44 // here's to hoping that no
45 if (!seed.ignoreFundsPresence && ((helper as any)['balance'] == undefined || await (helper as any).balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND)) {45 if (!seed.ignoreFundsPresence && ((helper as any)['balance'] == undefined || await (helper as any).balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND)) {
46 console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);46 console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
47 account = helper.util.fromSeed('//Alice', ss58Format);47 account = helper.util.fromSeed('//Alice', ss58Format);
modifiedtests/src/util/playgrounds/types.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
187 this.helper = helper;187 this.helper = helper;
188 }188 }
189189
190 /**190 /**
191 * Generates accounts with the specified UNQ token balance 191 * Generates accounts with the specified UNQ token balance
192 * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.192 * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.
193 * @param donor donor account for balances193 * @param donor donor account for balances
194 * @returns array of newly created accounts194 * @returns array of newly created accounts
195 * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); 195 * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor);
196 */196 */
197 createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {197 createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {
198 let nonce = await this.helper.chain.getNonce(donor.address);198 let nonce = await this.helper.chain.getNonce(donor.address);
199 const wait = new WaitGroup(this.helper);199 const wait = new WaitGroup(this.helper);
250 const tokenNominal = this.helper.balance.getOneTokenNominal();250 const tokenNominal = this.helper.balance.getOneTokenNominal();
251 for (let i = 0; i < accountsToCreate; i++) {251 for (let i = 0; i < accountsToCreate; i++) {
252 if (i === 500) { // if there are too many accounts to create252 if (i === 500) { // if there are too many accounts to create
253 await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled 253 await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled
254 transactions = []; //254 transactions = []; //
255 nonce = await this.helper.chain.getNonce(donor.address); // update nonce 255 nonce = await this.helper.chain.getNonce(donor.address); // update nonce
256 }256 }
257 const recepient = this.helper.util.fromSeed(mnemonicGenerate());257 const recepient = this.helper.util.fromSeed(mnemonicGenerate());
258 accounts.push(recepient);258 accounts.push(recepient);
421 return promise;421 return promise;
422 }422 }
423423
424 /**424 /**
425 * Wait for specified number of blocks425 * Wait for specified number of blocks
426 * @param blocksCount number of blocks to wait426 * @param blocksCount number of blocks to wait
427 * @returns 427 * @returns
428 */428 */
429 async newBlocks(blocksCount = 1, timeout?: number): Promise<void> {429 async newBlocks(blocksCount = 1, timeout?: number): Promise<void> {
430 timeout = timeout ?? blocksCount * 60_000;430 timeout = timeout ?? blocksCount * 60_000;
431 // eslint-disable-next-line no-async-promise-executor431 // eslint-disable-next-line no-async-promise-executor
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
2420 if (!event) throw Error('Cannot find transfer in events');2420 if (!event) throw Error('Cannot find transfer in events');
2421 }2421 }
24222422
2423 /**2423 /**
2424 * Get schedule for recepient of vested transfer2424 * Get schedule for recepient of vested transfer
2425 * @param address Substrate address of recipient2425 * @param address Substrate address of recipient
2426 * @returns 2426 * @returns
2427 */2427 */
2428 async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> {2428 async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> {
2429 const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2429 const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();
2430 return schedule.map((schedule: any) => {2430 return schedule.map((schedule: any) => {
modifiedtests/src/vesting.test.tsdiffbeforeafterboth

no syntactic changes

modifiedtests/src/xcm/xcmOpal.test.tsdiffbeforeafterboth
287 await helper.wait.newBlocks(3);287 await helper.wait.newBlocks(3);
288 288
289 // The USDT token never paid fees. Its amount not changed from begin value.289 // The USDT token never paid fees. Its amount not changed from begin value.
290 // Also check that xcm transfer has been succeeded 290 // Also check that xcm transfer has been succeeded
291 expect((await helper.assets.account(ASSET_ID, alice.address))! == ASSET_AMOUNT).to.be.true;291 expect((await helper.assets.account(ASSET_ID, alice.address))! == ASSET_AMOUNT).to.be.true;
292 });292 });
293 });293 });
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
321 await helper.wait.newBlocks(3);321 await helper.wait.newBlocks(3);
322 322
323 // The USDT token never paid fees. Its amount not changed from begin value.323 // The USDT token never paid fees. Its amount not changed from begin value.
324 // Also check that xcm transfer has been succeeded 324 // Also check that xcm transfer has been succeeded
325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
326 });326 });
327 });327 });
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
321 await helper.wait.newBlocks(3);321 await helper.wait.newBlocks(3);
322 322
323 // The USDT token never paid fees. Its amount not changed from begin value.323 // The USDT token never paid fees. Its amount not changed from begin value.
324 // Also check that xcm transfer has been succeeded 324 // Also check that xcm transfer has been succeeded
325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;325 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;
326 });326 });
327 });327 });
modifiedtests/yarn.lockdiffbeforeafterboth
1065 dependencies:1065 dependencies:
1066 "@types/node" "*"1066 "@types/node" "*"
10671067
1068"@typescript-eslint/eslint-plugin@^5.40.1":1068"@typescript-eslint/eslint-plugin@^5.47.0":
1069 version "5.47.0"1069 version "5.47.0"
1070 resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz#dadb79df3b0499699b155839fd6792f16897d910"1070 resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz#dadb79df3b0499699b155839fd6792f16897d910"
1071 integrity sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==1071 integrity sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==
1080 semver "^7.3.7"1080 semver "^7.3.7"
1081 tsutils "^3.21.0"1081 tsutils "^3.21.0"
10821082
1083"@typescript-eslint/parser@^5.40.1":1083"@typescript-eslint/parser@^5.47.0":
1084 version "5.47.0"1084 version "5.47.0"
1085 resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.47.0.tgz#62e83de93499bf4b500528f74bf2e0554e3a6c8d"1085 resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.47.0.tgz#62e83de93499bf4b500528f74bf2e0554e3a6c8d"
1086 integrity sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==1086 integrity sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==