difftreelog
feat benchmark property calls
in: master
30 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5913,6 +5913,7 @@
dependencies = [
"evm-coder",
"fp-evm-mapping",
+ "frame-benchmarking",
"frame-support",
"frame-system",
"pallet-evm",
@@ -6649,6 +6650,7 @@
"frame-support",
"frame-system",
"pallet-common",
+ "pallet-evm",
"parity-scale-codec 3.1.2",
"scale-info",
"sp-std",
Makefilediffbeforeafterboth--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,10 @@
bench-evm-migration:
make _bench PALLET=evm-migration
+.PHONY: bench-common
+bench-common:
+ make _bench PALLET=common
+
.PHONY: bench-unique
bench-unique:
make _bench PALLET=unique
pallets/common/Cargo.tomldiffbeforeafterboth--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -25,6 +25,7 @@
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
+frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
[features]
default = ["std"]
@@ -37,4 +38,6 @@
"up-data-structs/std",
"pallet-evm/std",
]
-runtime-benchmarks = []
+runtime-benchmarks = [
+ "frame-benchmarking"
+]
pallets/common/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/common/src/benchmarking.rs
+++ b/pallets/common/src/benchmarking.rs
@@ -15,11 +15,13 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
use sp_std::vec::Vec;
-use crate::{Config, CollectionHandle};
+use crate::{Config, CollectionHandle, Pallet};
+use pallet_evm::account::CrossAccountId;
+use frame_benchmarking::{benchmarks, account};
use up_data_structs::{
- CollectionMode, CreateCollectionData, CollectionId, MAX_COLLECTION_NAME_LENGTH,
- MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, OFFCHAIN_SCHEMA_LIMIT,
- CONST_ON_CHAIN_SCHEMA_LIMIT,
+ CollectionMode, CreateCollectionData, CollectionId, Property, PropertyKey, PropertyValue,
+ MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
+ OFFCHAIN_SCHEMA_LIMIT, CONST_ON_CHAIN_SCHEMA_LIMIT, MAX_PROPERTIES_PER_ITEM,
};
use frame_support::{
traits::{Currency, Get},
@@ -29,6 +31,8 @@
use core::convert::TryInto;
use sp_runtime::DispatchError;
+const SEED: u32 = 1;
+
pub fn create_data<const S: u32>() -> BoundedVec<u8, ConstU32<S>> {
create_var_data::<S>(S)
}
@@ -52,6 +56,22 @@
.try_into()
.unwrap()
}
+pub fn property_key(id: usize) -> PropertyKey {
+ #[cfg(not(feature = "std"))]
+ use alloc::string::ToString;
+ let mut data = create_data();
+ // No DerefMut available for .fill
+ for i in 0..data.len() {
+ data[i] = b'0';
+ }
+ let bytes = id.to_string();
+ let len = data.len();
+ data[len - bytes.len()..].copy_from_slice(&bytes.as_bytes());
+ data
+}
+pub fn property_value() -> PropertyValue {
+ create_data()
+}
pub fn create_collection_raw<T: Config, R>(
owner: T::AccountId,
@@ -83,6 +103,14 @@
.and_then(CollectionHandle::try_get)
.map(cast)
}
+fn create_collection<T: Config>(owner: T::AccountId) -> Result<CollectionHandle<T>, DispatchError> {
+ create_collection_raw(
+ owner,
+ CollectionMode::NFT,
+ |owner, data| <Pallet<T>>::init_collection(owner, data),
+ |h| h,
+ )
+}
/// Helper macros, which handles all benchmarking preparation in semi-declarative way
///
@@ -125,3 +153,31 @@
};
() => {}
}
+
+benchmarks! {
+ set_collection_properties {
+ let b in 0..MAX_PROPERTIES_PER_ITEM;
+ bench_init!{
+ owner: sub; collection: collection(owner);
+ owner: cross_from_sub;
+ };
+ let props = (0..b).map(|p| Property {
+ key: property_key(p as usize),
+ value: property_value(),
+ }).collect::<Vec<_>>();
+ }: {<Pallet<T>>::set_collection_properties(&collection, &owner, props)?}
+
+ delete_collection_properties {
+ let b in 0..MAX_PROPERTIES_PER_ITEM;
+ bench_init!{
+ owner: sub; collection: collection(owner);
+ owner: cross_from_sub;
+ };
+ let props = (0..b).map(|p| Property {
+ key: property_key(p as usize),
+ value: property_value(),
+ }).collect::<Vec<_>>();
+ <Pallet<T>>::set_collection_properties(&collection, &owner, props)?;
+ let to_delete = (0..b).map(|p| property_key(p as usize)).collect::<Vec<_>>();
+ }: {<Pallet<T>>::delete_collection_properties(&collection, &owner, to_delete)?}
+}
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -16,6 +16,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
+extern crate alloc;
+
use core::ops::{Deref, DerefMut};
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_std::vec::Vec;
@@ -85,6 +87,9 @@
pub mod dispatch;
pub mod erc;
pub mod eth;
+pub mod weights;
+
+pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]
pub struct CollectionHandle<T: Config> {
@@ -186,11 +191,13 @@
use frame_support::traits::Currency;
use up_data_structs::{TokenId, mapping::TokenAddressMapping};
use scale_info::TypeInfo;
+ use weights::WeightInfo;
#[pallet::config]
pub trait Config:
frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config
{
+ type WeightInfo: WeightInfo;
type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
type Currency: Currency<Self::AccountId>;
@@ -804,7 +811,7 @@
pub fn set_scoped_collection_properties(
collection: &CollectionHandle<T>,
scope: PropertyScope,
- properties: impl Iterator<Item=Property>,
+ properties: impl Iterator<Item = Property>,
) -> DispatchResult {
CollectionProperties::<T>::try_mutate(collection.id, |stored_properties| {
stored_properties.try_scoped_set_from_iter(scope, properties)
@@ -903,10 +910,11 @@
Ok(())
}
- pub fn get_collection_property(collection_id: CollectionId, key: &PropertyKey) -> Option<PropertyValue> {
- Self::collection_properties(collection_id)
- .get(key)
- .cloned()
+ pub fn get_collection_property(
+ collection_id: CollectionId,
+ key: &PropertyKey,
+ ) -> Option<PropertyValue> {
+ Self::collection_properties(collection_id).get(key).cloned()
}
pub fn bytes_keys_to_property_keys(
@@ -1131,7 +1139,7 @@
/// Worst cases
pub trait CommonWeightInfo<CrossAccountId> {
fn create_item() -> Weight;
- fn create_multiple_items(amount: u32) -> Weight;
+ fn create_multiple_items(amount: &[CreateItemData]) -> Weight;
fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;
fn burn_item() -> Weight;
fn set_collection_properties(amount: u32) -> Weight;
pallets/common/src/weights.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/common/src/weights.rs
@@ -0,0 +1,79 @@
+// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs
+
+//! Autogenerated weights for pallet_common
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
+
+// Executed Command:
+// target/release/unique-collator
+// benchmark
+// pallet
+// --pallet
+// pallet-common
+// --wasm-execution
+// compiled
+// --extrinsic
+// *
+// --template
+// .maintain/frame-weight-template.hbs
+// --steps=50
+// --repeat=1
+// --heap-pages=4096
+// --output=./pallets/common/src/weights.rs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+#![allow(clippy::unnecessary_cast)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use sp_std::marker::PhantomData;
+
+/// Weight functions needed for pallet_common.
+pub trait WeightInfo {
+ fn set_collection_properties(b: u32, ) -> Weight;
+ fn delete_collection_properties(b: u32, ) -> Weight;
+}
+
+/// Weights for pallet_common using the Substrate node and recommended hardware.
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+ // Storage: Common CollectionProperties (r:1 w:1)
+ fn set_collection_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 142_818_000
+ .saturating_add((2_786_252_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(1 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: Common CollectionProperties (r:1 w:1)
+ fn delete_collection_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 101_087_000
+ .saturating_add((2_739_521_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(1 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+}
+
+// For backwards compatibility and tests
+impl WeightInfo for () {
+ // Storage: Common CollectionProperties (r:1 w:1)
+ fn set_collection_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 142_818_000
+ .saturating_add((2_786_252_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(1 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: Common CollectionProperties (r:1 w:1)
+ fn delete_collection_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 101_087_000
+ .saturating_add((2_739_521_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(1 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+}
pallets/fungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/fungible/src/benchmarking.rs
+++ b/pallets/fungible/src/benchmarking.rs
@@ -40,7 +40,7 @@
owner: sub; collection: collection(owner);
sender: cross_from_sub(owner); to: cross_sub;
};
- }: {<Pallet<T>>::create_item(&collection, &sender, (to, 200))?}
+ }: {<Pallet<T>>::create_item(&collection, &sender, (to, 200), &Unlimited)?}
create_multiple_items_ex {
let b in 0..MAX_ITEMS_PER_BATCH;
@@ -52,14 +52,14 @@
bench_init!(to: cross_sub(i););
(to, 200)
}).collect::<BTreeMap<_, _>>().try_into().unwrap();
- }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data)?}
+ }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
burn_item {
bench_init!{
owner: sub; collection: collection(owner);
owner: cross_from_sub; burner: cross_sub;
};
- <Pallet<T>>::create_item(&collection, &owner, (burner.clone(), 200))?;
+ <Pallet<T>>::create_item(&collection, &owner, (burner.clone(), 200), &Unlimited)?;
}: {<Pallet<T>>::burn(&collection, &burner, 100)?}
transfer {
@@ -67,15 +67,15 @@
owner: sub; collection: collection(owner);
owner: cross_from_sub; sender: cross_sub; to: cross_sub;
};
- <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200))?;
- }: {<Pallet<T>>::transfer(&collection, &sender, &to, 200)?}
+ <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200), &Unlimited)?;
+ }: {<Pallet<T>>::transfer(&collection, &sender, &to, 200, &Unlimited)?}
approve {
bench_init!{
owner: sub; collection: collection(owner);
owner: cross_from_sub; sender: cross_sub; spender: cross_sub;
};
- <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200))?;
+ <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200), &Unlimited)?;
}: {<Pallet<T>>::set_allowance(&collection, &sender, &spender, 100)?}
transfer_from {
@@ -83,7 +83,7 @@
owner: sub; collection: collection(owner);
owner: cross_from_sub; sender: cross_sub; spender: cross_sub; receiver: cross_sub;
};
- <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200))?;
+ <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200), &Unlimited)?;
<Pallet<T>>::set_allowance(&collection, &sender, &spender, 200)?;
}: {<Pallet<T>>::transfer_from(&collection, &spender, &sender, &receiver, 100, &Unlimited)?}
@@ -92,7 +92,7 @@
owner: sub; collection: collection(owner);
owner: cross_from_sub; sender: cross_sub; burner: cross_sub;
};
- <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200))?;
+ <Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200), &Unlimited)?;
<Pallet<T>>::set_allowance(&collection, &sender, &burner, 200)?;
}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, 100, &Unlimited)?}
}
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -17,7 +17,7 @@
use core::marker::PhantomData;
use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
-use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget};
+use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget, CreateItemData};
use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
use sp_runtime::ArithmeticError;
use sp_std::{vec::Vec, vec};
@@ -33,7 +33,8 @@
<SelfWeightOf<T>>::create_item()
}
- fn create_multiple_items(_amount: u32) -> Weight {
+ fn create_multiple_items(_data: &[CreateItemData]) -> Weight {
+ // All items minted for the same user, so it works same as create_item
Self::create_item()
}
@@ -51,23 +52,28 @@
}
fn set_collection_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::set_collection_properties(amount)
+ // Error
+ 0
}
fn delete_collection_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::delete_collection_properties(amount)
+ // Error
+ 0
}
fn set_token_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::set_token_properties(amount)
+ // Error
+ 0
}
fn delete_token_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::delete_token_properties(amount)
+ // Error
+ 0
}
fn set_property_permissions(amount: u32) -> Weight {
- <SelfWeightOf<T>>::set_property_permissions(amount)
+ // Error
+ 0
}
fn transfer() -> Weight {
pallets/fungible/src/weights.rsdiffbeforeafterboth--- a/pallets/fungible/src/weights.rs
+++ b/pallets/fungible/src/weights.rs
@@ -35,11 +35,6 @@
fn create_item() -> Weight;
fn create_multiple_items_ex(b: u32, ) -> Weight;
fn burn_item() -> Weight;
- fn set_collection_properties(amount: u32) -> Weight;
- fn delete_collection_properties(amount: u32) -> Weight;
- fn set_token_properties(amount: u32) -> Weight;
- fn delete_token_properties(amount: u32) -> Weight;
- fn set_property_permissions(amount: u32) -> Weight;
fn transfer() -> Weight;
fn approve() -> Weight;
fn transfer_from() -> Weight;
@@ -73,33 +68,8 @@
(15_565_000 as Weight)
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
- }
-
- fn set_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn delete_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn set_token_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn delete_token_properties(_amount: u32) -> Weight {
- // Error
- 0
}
- fn set_property_permissions(_amount: u32) -> Weight {
- // Error
- 0
- }
-
// Storage: Fungible Balance (r:2 w:2)
fn transfer() -> Weight {
(17_713_000 as Weight)
@@ -156,31 +126,6 @@
(15_565_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
- }
-
- fn set_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn delete_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn set_token_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn delete_token_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn set_property_permissions(_amount: u32) -> Weight {
- // Error
- 0
}
// Storage: Fungible Balance (r:2 w:2)
pallets/nonfungible/Cargo.tomldiffbeforeafterboth--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -49,4 +49,5 @@
'frame-benchmarking',
'frame-support/runtime-benchmarks',
'frame-system/runtime-benchmarks',
+ 'up-data-structs/runtime-benchmarks',
]
pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -18,24 +18,35 @@
use crate::{Pallet, Config, NonfungibleHandle};
use sp_std::prelude::*;
-use pallet_common::benchmarking::{create_collection_raw, create_data, create_var_data};
+use pallet_common::benchmarking::{create_collection_raw, create_data, property_key, property_value};
use frame_benchmarking::{benchmarks, account};
-use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, CUSTOM_DATA_LIMIT, budget::Unlimited};
+use up_data_structs::{
+ CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, CUSTOM_DATA_LIMIT,
+ budget::Unlimited,
+};
use pallet_common::bench_init;
-use core::convert::TryInto;
const SEED: u32 = 1;
fn create_max_item_data<T: Config>(owner: T::CrossAccountId) -> CreateItemData<T> {
let const_data = create_data::<CUSTOM_DATA_LIMIT>();
- CreateItemData::<T> { const_data, owner }
+ CreateItemData::<T> {
+ const_data,
+ owner,
+ properties: Default::default(),
+ }
}
fn create_max_item<T: Config>(
collection: &NonfungibleHandle<T>,
sender: &T::CrossAccountId,
owner: T::CrossAccountId,
) -> Result<TokenId, DispatchError> {
- <Pallet<T>>::create_item(&collection, sender, create_max_item_data::<T>(owner))?;
+ <Pallet<T>>::create_item(
+ &collection,
+ sender,
+ create_max_item_data::<T>(owner),
+ &Unlimited,
+ )?;
Ok(TokenId(<TokensMinted<T>>::get(&collection.id)))
}
@@ -65,7 +76,7 @@
sender: cross_from_sub(owner); to: cross_sub;
};
let data = (0..b).map(|_| create_max_item_data::<T>(to.clone())).collect();
- }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data)?}
+ }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
create_multiple_items_ex {
let b in 0..MAX_ITEMS_PER_BATCH;
@@ -77,7 +88,7 @@
bench_init!(to: cross_sub(i););
create_max_item_data::<T>(to)
}).collect();
- }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data)?}
+ }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
burn_item {
bench_init!{
@@ -93,7 +104,7 @@
owner: cross_from_sub; sender: cross_sub; receiver: cross_sub;
};
let item = create_max_item(&collection, &owner, sender.clone())?;
- }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item)?}
+ }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, &Unlimited)?}
approve {
bench_init!{
@@ -120,4 +131,66 @@
let item = create_max_item(&collection, &owner, sender.clone())?;
<Pallet<T>>::set_allowance(&collection, &sender, item, Some(&burner))?;
}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, &Unlimited)?}
+
+ set_property_permissions {
+ let b in 0..MAX_PROPERTIES_PER_ITEM;
+ bench_init!{
+ owner: sub; collection: collection(owner);
+ owner: cross_from_sub;
+ };
+ let perms = (0..b).map(|k| PropertyKeyPermission {
+ key: property_key(k as usize),
+ permission: PropertyPermission {
+ mutable: false,
+ collection_admin: false,
+ token_owner: false,
+ },
+ }).collect::<Vec<_>>();
+ }: {<Pallet<T>>::set_property_permissions(&collection, &owner, perms)?}
+
+ set_token_properties {
+ let b in 0..MAX_PROPERTIES_PER_ITEM;
+ bench_init!{
+ owner: sub; collection: collection(owner);
+ owner: cross_from_sub;
+ };
+ let perms = (0..b).map(|k| PropertyKeyPermission {
+ key: property_key(k as usize),
+ permission: PropertyPermission {
+ mutable: false,
+ collection_admin: true,
+ token_owner: true,
+ },
+ }).collect::<Vec<_>>();
+ <Pallet<T>>::set_property_permissions(&collection, &owner, perms)?;
+ let props = (0..b).map(|k| Property {
+ key: property_key(k as usize),
+ value: property_value(),
+ }).collect::<Vec<_>>();
+ let item = create_max_item(&collection, &owner, owner.clone())?;
+ }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props)?}
+
+ delete_token_properties {
+ let b in 0..MAX_PROPERTIES_PER_ITEM;
+ bench_init!{
+ owner: sub; collection: collection(owner);
+ owner: cross_from_sub;
+ };
+ let perms = (0..b).map(|k| PropertyKeyPermission {
+ key: property_key(k as usize),
+ permission: PropertyPermission {
+ mutable: true,
+ collection_admin: true,
+ token_owner: true,
+ },
+ }).collect::<Vec<_>>();
+ <Pallet<T>>::set_property_permissions(&collection, &owner, perms)?;
+ let props = (0..b).map(|k| Property {
+ key: property_key(k as usize),
+ value: property_value(),
+ }).collect::<Vec<_>>();
+ let item = create_max_item(&collection, &owner, owner.clone())?;
+ <Pallet<T>>::set_token_properties(&collection, &owner, item, props)?;
+ let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
+ }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete)?}
}
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -21,7 +21,9 @@
TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,
PropertyKeyPermission, PropertyValue,
};
-use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
+use pallet_common::{
+ CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _,
+};
use sp_runtime::DispatchError;
use sp_std::vec::Vec;
@@ -38,13 +40,33 @@
fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
match data {
- CreateItemExData::NFT(t) => <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32),
+ CreateItemExData::NFT(t) => {
+ <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)
+ + t.iter()
+ .map(|t| {
+ if t.properties.len() > 0 {
+ Self::set_token_properties(t.properties.len() as u32)
+ } else {
+ 0
+ }
+ })
+ .sum::<u64>()
+ }
_ => 0,
}
}
- fn create_multiple_items(amount: u32) -> Weight {
- <SelfWeightOf<T>>::create_multiple_items(amount)
+ fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {
+ <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)
+ + data
+ .iter()
+ .filter_map(|t| match t {
+ up_data_structs::CreateItemData::NFT(n) if n.properties.len() > 0 => {
+ Some(Self::set_token_properties(n.properties.len() as u32))
+ }
+ _ => None,
+ })
+ .sum::<u64>()
}
fn burn_item() -> Weight {
@@ -52,11 +74,11 @@
}
fn set_collection_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::set_collection_properties(amount)
+ <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)
}
fn delete_collection_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::delete_collection_properties(amount)
+ <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)
}
fn set_token_properties(amount: u32) -> Weight {
@@ -128,15 +150,15 @@
data: Vec<up_data_structs::CreateItemData>,
nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
+ let weight = <CommonWeights<T>>::create_multiple_items(&data);
let data = data
.into_iter()
.map(|d| map_create_data::<T>(d, &to))
.collect::<Result<Vec<_>, DispatchError>>()?;
- let amount = data.len();
with_weight(
<Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),
- <CommonWeights<T>>::create_multiple_items(amount as u32),
+ weight,
)
}
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -18,7 +18,7 @@
use erc::ERC721Events;
use evm_coder::ToLog;
-use frame_support::{BoundedVec, ensure, fail, transactional};
+use frame_support::{BoundedVec, ensure, fail, transactional, storage::with_transaction};
use up_data_structs::{
AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,
mapping::TokenAddressMapping, NestingRule, budget::Budget, Property, PropertyPermission,
@@ -32,7 +32,7 @@
use pallet_structure::Pallet as PalletStructure;
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_core::H160;
-use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
+use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
use sp_std::{vec::Vec, vec};
use core::ops::Deref;
use sp_std::collections::btree_map::BTreeMap;
@@ -600,28 +600,37 @@
// =========
+ with_transaction(|| {
+ for (i, data) in data.iter().enumerate() {
+ let token = first_token + i as u32 + 1;
+
+ <TokenData<T>>::insert(
+ (collection.id, token),
+ ItemData {
+ const_data: data.const_data.clone(),
+ owner: data.owner.clone(),
+ },
+ );
+
+ if let Err(e) = Self::set_token_properties(
+ collection,
+ sender,
+ TokenId(token),
+ data.properties.clone().into_inner(),
+ ) {
+ return TransactionOutcome::Rollback(Err(e));
+ }
+ }
+ TransactionOutcome::Commit(Ok(()))
+ })?;
+
<TokensMinted<T>>::insert(collection.id, tokens_minted);
for (account, balance) in balances {
<AccountBalance<T>>::insert((collection.id, account), balance);
}
for (i, data) in data.into_iter().enumerate() {
let token = first_token + i as u32 + 1;
-
- <TokenData<T>>::insert(
- (collection.id, token),
- ItemData {
- const_data: data.const_data,
- owner: data.owner.clone(),
- },
- );
<Owned<T>>::insert((collection.id, &data.owner, token), true);
-
- Self::set_token_properties(
- collection,
- sender,
- TokenId(token),
- data.properties.into_inner(),
- )?;
<PalletEvm<T>>::deposit_log(
ERC721Events::Transfer {
pallets/nonfungible/src/weights.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/weights.rs
+++ b/pallets/nonfungible/src/weights.rs
@@ -151,10 +151,35 @@
// Storage: Nonfungible AccountBalance (r:1 w:1)
// Storage: Nonfungible Owned (r:0 w:1)
fn burn_from() -> Weight {
- (27_580_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(4 as Weight))
- .saturating_add(T::DbWeight::get().writes(5 as Weight))
}
+ // Storage: Common CollectionPropertyPermissions (r:1 w:1)
+ fn set_property_permissions(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 3_432_000
+ .saturating_add((126_888_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(1 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: Common CollectionPropertyPermissions (r:1 w:0)
+ // Storage: Nonfungible TokenData (r:1 w:0)
+ // Storage: Nonfungible TokenProperties (r:1 w:1)
+ fn set_token_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 158_583_000
+ .saturating_add((4_707_700_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(3 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
+ // Storage: Common CollectionPropertyPermissions (r:1 w:0)
+ // Storage: Nonfungible TokenData (r:1 w:0)
+ // Storage: Nonfungible TokenProperties (r:1 w:1)
+ fn delete_token_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 169_018_000
+ .saturating_add((4_783_967_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(T::DbWeight::get().reads(3 as Weight))
+ .saturating_add(T::DbWeight::get().writes(1 as Weight))
+ }
}
// For backwards compatibility and tests
@@ -260,8 +285,33 @@
// Storage: Nonfungible AccountBalance (r:1 w:1)
// Storage: Nonfungible Owned (r:0 w:1)
fn burn_from() -> Weight {
- (27_580_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(4 as Weight))
- .saturating_add(RocksDbWeight::get().writes(5 as Weight))
}
+ // Storage: Common CollectionPropertyPermissions (r:1 w:1)
+ fn set_property_permissions(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 3_432_000
+ .saturating_add((126_888_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(1 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: Common CollectionPropertyPermissions (r:1 w:0)
+ // Storage: Nonfungible TokenData (r:1 w:0)
+ // Storage: Nonfungible TokenProperties (r:1 w:1)
+ fn set_token_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 158_583_000
+ .saturating_add((4_707_700_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(3 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
+ // Storage: Common CollectionPropertyPermissions (r:1 w:0)
+ // Storage: Nonfungible TokenData (r:1 w:0)
+ // Storage: Nonfungible TokenProperties (r:1 w:1)
+ fn delete_token_properties(b: u32, ) -> Weight {
+ (0 as Weight)
+ // Standard Error: 169_018_000
+ .saturating_add((4_783_967_000 as Weight).saturating_mul(b as Weight))
+ .saturating_add(RocksDbWeight::get().reads(3 as Weight))
+ .saturating_add(RocksDbWeight::get().writes(1 as Weight))
+ }
}
pallets/refungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -18,7 +18,7 @@
use crate::{Pallet, Config, RefungibleHandle};
use sp_std::prelude::*;
-use pallet_common::benchmarking::{create_collection_raw, create_data, create_var_data};
+use pallet_common::benchmarking::{create_collection_raw, create_data};
use frame_benchmarking::{benchmarks, account};
use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, CUSTOM_DATA_LIMIT, budget::Unlimited};
use pallet_common::bench_init;
@@ -46,7 +46,7 @@
users: impl IntoIterator<Item = (T::CrossAccountId, u128)>,
) -> Result<TokenId, DispatchError> {
let data: CreateRefungibleExData<T::CrossAccountId> = create_max_item_data(users);
- <Pallet<T>>::create_item(&collection, sender, data)?;
+ <Pallet<T>>::create_item(&collection, sender, data, &Unlimited)?;
Ok(TokenId(<TokensMinted<T>>::get(&collection.id)))
}
@@ -73,7 +73,7 @@
sender: cross_from_sub(owner); to: cross_sub;
};
let data = (0..b).map(|_| create_max_item_data([(to.clone(), 200)])).collect();
- }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data)?}
+ }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
create_multiple_items_ex_multiple_items {
let b in 0..MAX_ITEMS_PER_BATCH;
@@ -85,7 +85,7 @@
bench_init!(to: cross_sub(t););
create_max_item_data([(to, 200)])
}).collect();
- }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data)?}
+ }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
create_multiple_items_ex_multiple_owners {
let b in 0..MAX_ITEMS_PER_BATCH;
@@ -97,7 +97,7 @@
bench_init!(to: cross_sub(u););
(to, 200)
}))].try_into().unwrap();
- }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data)?}
+ }: {<Pallet<T>>::create_multiple_items(&collection, &sender, data, &Unlimited)?}
// Other user left, token data is kept
burn_item_partial {
@@ -122,7 +122,7 @@
sender: cross_from_sub(owner); receiver: cross_sub;
};
let item = create_max_item(&collection, &sender, [(sender.clone(), 200), (receiver.clone(), 200)])?;
- }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 100)?}
+ }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 100, &Unlimited)?}
// Target account is created
transfer_creating {
bench_init!{
@@ -130,7 +130,7 @@
sender: cross_from_sub(owner); receiver: cross_sub;
};
let item = create_max_item(&collection, &sender, [(sender.clone(), 200)])?;
- }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 100)?}
+ }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 100, &Unlimited)?}
// Source account is destroyed
transfer_removing {
bench_init!{
@@ -138,7 +138,7 @@
sender: cross_from_sub(owner); receiver: cross_sub;
};
let item = create_max_item(&collection, &sender, [(sender.clone(), 200), (receiver.clone(), 200)])?;
- }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 200)?}
+ }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 200, &Unlimited)?}
// Source account destroyed, target created
transfer_creating_removing {
bench_init!{
@@ -146,7 +146,7 @@
sender: cross_from_sub(owner); receiver: cross_sub;
};
let item = create_max_item(&collection, &sender, [(sender.clone(), 200)])?;
- }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 200)?}
+ }: {<Pallet<T>>::transfer(&collection, &sender, &receiver, item, 200, &Unlimited)?}
approve {
bench_init!{
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -20,7 +20,7 @@
use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight};
use up_data_structs::{
CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,
- PropertyKey, PropertyValue, PropertyKeyPermission,
+ PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData,
};
use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
use sp_runtime::DispatchError;
@@ -46,8 +46,8 @@
<SelfWeightOf<T>>::create_item()
}
- fn create_multiple_items(amount: u32) -> Weight {
- <SelfWeightOf<T>>::create_multiple_items(amount)
+ fn create_multiple_items(data: &[CreateItemData]) -> Weight {
+ <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)
}
fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {
@@ -66,12 +66,14 @@
max_weight_of!(burn_item_partial(), burn_item_fully())
}
- fn set_collection_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::set_collection_properties(amount)
+ fn set_collection_properties(_amount: u32) -> Weight {
+ // Error
+ 0
}
- fn delete_collection_properties(amount: u32) -> Weight {
- <SelfWeightOf<T>>::delete_collection_properties(amount)
+ fn delete_collection_properties(_amount: u32) -> Weight {
+ // Error
+ 0
}
fn set_token_properties(amount: u32) -> Weight {
@@ -156,15 +158,15 @@
data: Vec<up_data_structs::CreateItemData>,
nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
+ let weight = <CommonWeights<T>>::create_multiple_items(&data);
let data = data
.into_iter()
.map(|d| map_create_data::<T>(d, &to))
.collect::<Result<Vec<_>, DispatchError>>()?;
- let amount = data.len();
with_weight(
<Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),
- <CommonWeights<T>>::create_multiple_items(amount as u32),
+ weight,
)
}
pallets/refungible/src/weights.rsdiffbeforeafterboth--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -38,8 +38,6 @@
fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight;
fn burn_item_partial() -> Weight;
fn burn_item_fully() -> Weight;
- fn set_collection_properties(amount: u32) -> Weight;
- fn delete_collection_properties(amount: u32) -> Weight;
fn set_token_properties(amount: u32) -> Weight;
fn delete_token_properties(amount: u32) -> Weight;
fn set_property_permissions(amount: u32) -> Weight;
@@ -132,16 +130,6 @@
(32_489_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
- }
-
- fn set_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn delete_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
}
fn set_token_properties(_amount: u32) -> Weight {
@@ -320,16 +308,6 @@
(32_489_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(6 as Weight))
- }
-
- fn set_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
- }
-
- fn delete_collection_properties(_amount: u32) -> Weight {
- // Error
- 0
}
fn set_token_properties(_amount: u32) -> Weight {
pallets/structure/Cargo.tomldiffbeforeafterboth--- a/pallets/structure/Cargo.toml
+++ b/pallets/structure/Cargo.toml
@@ -16,6 +16,7 @@
"derive",
] }
up-data-structs = { path = "../../primitives/data-structs", default-features = false }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" }
[features]
default = ["std"]
@@ -28,5 +29,6 @@
"scale-info/std",
"parity-scale-codec/std",
"up-data-structs/std",
+ "pallet-evm/std",
]
runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks']
pallets/structure/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/structure/src/benchmarking.rs
+++ b/pallets/structure/src/benchmarking.rs
@@ -2,8 +2,10 @@
use frame_benchmarking::{benchmarks, account};
use frame_support::traits::{Currency, Get};
-use up_data_structs::{CreateCollectionData, CollectionMode, CreateItemData, CreateNftData};
-use pallet_common::CrossAccountId;
+use up_data_structs::{
+ CreateCollectionData, CollectionMode, CreateItemData, CreateNftData, budget::Unlimited,
+};
+use pallet_evm::account::CrossAccountId;
const SEED: u32 = 1;
@@ -20,9 +22,9 @@
let dispatch = T::CollectionDispatch::dispatch(CollectionHandle::try_get(CollectionId(1))?);
let dispatch = dispatch.as_dyn();
- dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()))?;
+ dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()), &Unlimited)?;
}: {
let parent = <Pallet<T>>::find_parent(CollectionId(1), TokenId(1))?;
- assert!(matches!(parent, Parent::Normal(_)))
+ assert!(matches!(parent, Parent::User(_)))
}
}
pallets/unique/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20 clippy::too_many_arguments,21 clippy::unnecessary_mut_passed,22 clippy::unused_unit23)]2425use frame_support::{26 decl_module, decl_storage, decl_error, decl_event,27 dispatch::DispatchResult,28 ensure,29 weights::{Weight},30 transactional,31 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32 BoundedVec,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38 CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT, MAX_COLLECTION_NAME_LENGTH,39 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,40 CollectionLimits, CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState,41 CreateCollectionData, CreateItemExData, budget, CollectionField, Property, PropertyKey,42 PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,47 dispatch::CollectionDispatch,48};4950#[cfg(feature = "runtime-benchmarks")]51mod benchmarking;52pub mod weights;53use weights::WeightInfo;5455decl_error! {56 /// Error for non-fungible-token module.57 pub enum Error for Module<T: Config> {58 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.59 CollectionDecimalPointLimitExceeded,60 /// This address is not set as sponsor, use setCollectionSponsor first.61 ConfirmUnsetSponsorFail,62 /// Length of items properties must be greater than 0.63 EmptyArgument,64 }65}6667pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {68 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;6970 /// Weight information for extrinsics in this pallet.71 type WeightInfo: WeightInfo;72 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;73}7475decl_event! {76 pub enum Event<T>77 where78 <T as frame_system::Config>::AccountId,79 <T as pallet_evm::account::Config>::CrossAccountId,80 {81 /// Collection sponsor was removed82 ///83 /// # Arguments84 ///85 /// * collection_id: Globally unique collection identifier.86 CollectionSponsorRemoved(CollectionId),8788 /// Collection admin was added89 ///90 /// # Arguments91 ///92 /// * collection_id: Globally unique collection identifier.93 ///94 /// * admin: Admin address.95 CollectionAdminAdded(CollectionId, CrossAccountId),9697 /// Collection owned was change98 ///99 /// # Arguments100 ///101 /// * collection_id: Globally unique collection identifier.102 ///103 /// * owner: New owner address.104 CollectionOwnedChanged(CollectionId, AccountId),105106 /// Collection sponsor was set107 ///108 /// # Arguments109 ///110 /// * collection_id: Globally unique collection identifier.111 ///112 /// * owner: New sponsor address.113 CollectionSponsorSet(CollectionId, AccountId),114115 /// const on chain schema was set116 ///117 /// # Arguments118 ///119 /// * collection_id: Globally unique collection identifier.120 ConstOnChainSchemaSet(CollectionId),121122 /// New sponsor was confirm123 ///124 /// # Arguments125 ///126 /// * collection_id: Globally unique collection identifier.127 ///128 /// * sponsor: New sponsor address.129 SponsorshipConfirmed(CollectionId, AccountId),130131 /// Collection admin was removed132 ///133 /// # Arguments134 ///135 /// * collection_id: Globally unique collection identifier.136 ///137 /// * admin: Admin address.138 CollectionAdminRemoved(CollectionId, CrossAccountId),139140 /// Address was remove from allow list141 ///142 /// # Arguments143 ///144 /// * collection_id: Globally unique collection identifier.145 ///146 /// * user: Address.147 AllowListAddressRemoved(CollectionId, CrossAccountId),148149 /// Address was add to allow list150 ///151 /// # Arguments152 ///153 /// * collection_id: Globally unique collection identifier.154 ///155 /// * user: Address.156 AllowListAddressAdded(CollectionId, CrossAccountId),157158 /// Collection limits was set159 ///160 /// # Arguments161 ///162 /// * collection_id: Globally unique collection identifier.163 CollectionLimitSet(CollectionId),164165 /// Mint permission was set166 ///167 /// # Arguments168 ///169 /// * collection_id: Globally unique collection identifier.170 MintPermissionSet(CollectionId),171172 /// Offchain schema was set173 ///174 /// # Arguments175 ///176 /// * collection_id: Globally unique collection identifier.177 OffchainSchemaSet(CollectionId),178179 /// Public access mode was set180 ///181 /// # Arguments182 ///183 /// * collection_id: Globally unique collection identifier.184 ///185 /// * mode: New access state.186 PublicAccessModeSet(CollectionId, AccessMode),187188 /// Schema version was set189 ///190 /// # Arguments191 ///192 /// * collection_id: Globally unique collection identifier.193 SchemaVersionSet(CollectionId),194 }195}196197type SelfWeightOf<T> = <T as Config>::WeightInfo;198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204// i.e autoincrementing index205// can use non-cryptographic hash206// real - key is controlled by user207// but it is hard to generate enough colliding values, i.e owner of signed txs208// can use non-cryptographic hash209// controlled - key is completly controlled by users210// i.e maps with mutable keys211// should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216// collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218// same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220// no confirmation required, so addresses can be easily generated221decl_storage! {222 trait Store for Module<T: Config> as Unique {223224 //#region Private members225 /// Used for migrations226 ChainVersion: u64;227 //#endregion228229 //#region Tokens transfer rate limit baskets230 /// (Collection id (controlled?2), who created (real))231 /// TODO: Off chain worker should remove from this map when collection gets removed232 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;233 /// Collection id (controlled?2), token id (controlled?2)234 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;235 /// Collection id (controlled?2), owning user (real)236 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;237 /// Collection id (controlled?2), token id (controlled?2)238 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239 //#endregion240241 /// Variable metadata sponsoring242 /// Collection id (controlled?2), token id (controlled?2)243 #[deprecated]244 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;245 pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;246247 /// Approval sponsoring248 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;249 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;250 pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;251 }252}253254decl_module! {255 pub struct Module<T: Config> for enum Call256 where257 origin: T::Origin258 {259 type Error = Error<T>;260261 fn deposit_event() = default;262263 fn on_initialize(_now: T::BlockNumber) -> Weight {264 0265 }266267 fn on_runtime_upgrade() -> Weight {268 let limit = None;269270 <VariableMetaDataBasket<T>>::remove_all(limit);271272 0273 }274275 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.276 ///277 /// # Permissions278 ///279 /// * Anyone.280 ///281 /// # Arguments282 ///283 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.284 ///285 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.286 ///287 /// * token_prefix: UTF-8 string with token prefix.288 ///289 /// * mode: [CollectionMode] collection type and type dependent data.290 // returns collection ID291 #[weight = <SelfWeightOf<T>>::create_collection()]292 #[transactional]293 #[deprecated]294 pub fn create_collection(origin,295 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,296 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,297 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,298 mode: CollectionMode) -> DispatchResult {299 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {300 name: collection_name,301 description: collection_description,302 token_prefix,303 mode,304 ..Default::default()305 };306 Self::create_collection_ex(origin, data)307 }308309 /// This method creates a collection310 ///311 /// Prefer it to deprecated [`created_collection`] method312 #[weight = <SelfWeightOf<T>>::create_collection()]313 #[transactional]314 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {315 let sender = ensure_signed(origin)?;316317 // =========318319 T::CollectionDispatch::create(sender, data)?;320321 Ok(())322 }323324 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.325 ///326 /// # Permissions327 ///328 /// * Collection Owner.329 ///330 /// # Arguments331 ///332 /// * collection_id: collection to destroy.333 #[weight = <SelfWeightOf<T>>::destroy_collection()]334 #[transactional]335 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {336 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);337 let collection = <CollectionHandle<T>>::try_get(collection_id)?;338339 // =========340341 T::CollectionDispatch::destroy(sender, collection)?;342343 <NftTransferBasket<T>>::remove_prefix(collection_id, None);344 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);345 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);346347 <NftApproveBasket<T>>::remove_prefix(collection_id, None);348 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);349 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);350351 Ok(())352 }353354 /// Add an address to allow list.355 ///356 /// # Permissions357 ///358 /// * Collection Owner359 /// * Collection Admin360 ///361 /// # Arguments362 ///363 /// * collection_id.364 ///365 /// * address.366 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]367 #[transactional]368 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{369370 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);371 let collection = <CollectionHandle<T>>::try_get(collection_id)?;372373 <PalletCommon<T>>::toggle_allowlist(374 &collection,375 &sender,376 &address,377 true,378 )?;379380 Self::deposit_event(Event::<T>::AllowListAddressAdded(381 collection_id,382 address383 ));384385 Ok(())386 }387388 /// Remove an address from allow list.389 ///390 /// # Permissions391 ///392 /// * Collection Owner393 /// * Collection Admin394 ///395 /// # Arguments396 ///397 /// * collection_id.398 ///399 /// * address.400 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]401 #[transactional]402 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{403404 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);405 let collection = <CollectionHandle<T>>::try_get(collection_id)?;406407 <PalletCommon<T>>::toggle_allowlist(408 &collection,409 &sender,410 &address,411 false,412 )?;413414 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(415 collection_id,416 address417 ));418419 Ok(())420 }421422 /// Toggle between normal and allow list access for the methods with access for `Anyone`.423 ///424 /// # Permissions425 ///426 /// * Collection Owner.427 ///428 /// # Arguments429 ///430 /// * collection_id.431 ///432 /// * mode: [AccessMode]433 #[weight = <SelfWeightOf<T>>::set_public_access_mode()]434 #[transactional]435 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult436 {437 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);438439 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;440 target_collection.check_is_owner(&sender)?;441442 target_collection.access = mode.clone();443444 <Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(445 collection_id,446 mode447 ));448449 target_collection.save()450 }451452 /// Allows Anyone to create tokens if:453 /// * Allow List is enabled, and454 /// * Address is added to allow list, and455 /// * This method was called with True parameter456 ///457 /// # Permissions458 /// * Collection Owner459 ///460 /// # Arguments461 ///462 /// * collection_id.463 ///464 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.465 #[weight = <SelfWeightOf<T>>::set_mint_permission()]466 #[transactional]467 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult468 {469 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);470471 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;472 target_collection.check_is_owner(&sender)?;473474 target_collection.mint_mode = mint_permission;475476 <Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(477 collection_id478 ));479480 target_collection.save()481 }482483 /// Change the owner of the collection.484 ///485 /// # Permissions486 ///487 /// * Collection Owner.488 ///489 /// # Arguments490 ///491 /// * collection_id.492 ///493 /// * new_owner.494 #[weight = <SelfWeightOf<T>>::change_collection_owner()]495 #[transactional]496 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {497498 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);499500 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;501 target_collection.check_is_owner(&sender)?;502503 target_collection.owner = new_owner.clone();504 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(505 collection_id,506 new_owner507 ));508509 target_collection.save()510 }511512 /// Adds an admin of the Collection.513 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.514 ///515 /// # Permissions516 ///517 /// * Collection Owner.518 /// * Collection Admin.519 ///520 /// # Arguments521 ///522 /// * collection_id: ID of the Collection to add admin for.523 ///524 /// * new_admin_id: Address of new admin to add.525 #[weight = <SelfWeightOf<T>>::add_collection_admin()]526 #[transactional]527 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {528 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);529 let collection = <CollectionHandle<T>>::try_get(collection_id)?;530531 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(532 collection_id,533 new_admin_id.clone()534 ));535536 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)537 }538539 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.540 ///541 /// # Permissions542 ///543 /// * Collection Owner.544 /// * Collection Admin.545 ///546 /// # Arguments547 ///548 /// * collection_id: ID of the Collection to remove admin for.549 ///550 /// * account_id: Address of admin to remove.551 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]552 #[transactional]553 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {554 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);555 let collection = <CollectionHandle<T>>::try_get(collection_id)?;556557 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(558 collection_id,559 account_id.clone()560 ));561562 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)563 }564565 /// # Permissions566 ///567 /// * Collection Owner568 ///569 /// # Arguments570 ///571 /// * collection_id.572 ///573 /// * new_sponsor.574 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]575 #[transactional]576 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {577 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);578579 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;580 target_collection.check_is_owner(&sender)?;581582 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());583584 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(585 collection_id,586 new_sponsor587 ));588589 target_collection.save()590 }591592 /// # Permissions593 ///594 /// * Sponsor.595 ///596 /// # Arguments597 ///598 /// * collection_id.599 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]600 #[transactional]601 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {602 let sender = ensure_signed(origin)?;603604 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;605 ensure!(606 target_collection.sponsorship.pending_sponsor() == Some(&sender),607 Error::<T>::ConfirmUnsetSponsorFail608 );609610 target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());611612 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(613 collection_id,614 sender615 ));616617 target_collection.save()618 }619620 /// Switch back to pay-per-own-transaction model.621 ///622 /// # Permissions623 ///624 /// * Collection owner.625 ///626 /// # Arguments627 ///628 /// * collection_id.629 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]630 #[transactional]631 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {632 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);633634 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;635 target_collection.check_is_owner(&sender)?;636637 target_collection.sponsorship = SponsorshipState::Disabled;638639 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(640 collection_id641 ));642 target_collection.save()643 }644645 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.646 ///647 /// # Permissions648 ///649 /// * Collection Owner.650 /// * Collection Admin.651 /// * Anyone if652 /// * Allow List is enabled, and653 /// * Address is added to allow list, and654 /// * MintPermission is enabled (see SetMintPermission method)655 ///656 /// # Arguments657 ///658 /// * collection_id: ID of the collection.659 ///660 /// * owner: Address, initial owner of the NFT.661 ///662 /// * data: Token data to store on chain.663 #[weight = T::CommonWeightInfo::create_item()]664 #[transactional]665 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {666 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);667 let budget = budget::Value::new(2);668669 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))670 }671672 /// This method creates multiple items in a collection created with CreateCollection method.673 ///674 /// # Permissions675 ///676 /// * Collection Owner.677 /// * Collection Admin.678 /// * Anyone if679 /// * Allow List is enabled, and680 /// * Address is added to allow list, and681 /// * MintPermission is enabled (see SetMintPermission method)682 ///683 /// # Arguments684 ///685 /// * collection_id: ID of the collection.686 ///687 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].688 ///689 /// * owner: Address, initial owner of the NFT.690 #[weight = T::CommonWeightInfo::create_multiple_items(items_data.len() as u32)]691 #[transactional]692 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {693 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);694 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);695 let budget = budget::Value::new(2);696697 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))698 }699700 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]701 #[transactional]702 pub fn set_collection_properties(703 origin,704 collection_id: CollectionId,705 properties: Vec<Property>706 ) -> DispatchResultWithPostInfo {707 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);708709 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);710711 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))712 }713714 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]715 #[transactional]716 pub fn delete_collection_properties(717 origin,718 collection_id: CollectionId,719 property_keys: Vec<PropertyKey>,720 ) -> DispatchResultWithPostInfo {721 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);722723 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);724725 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))726 }727728 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]729 #[transactional]730 pub fn set_token_properties(731 origin,732 collection_id: CollectionId,733 token_id: TokenId,734 properties: Vec<Property>735 ) -> DispatchResultWithPostInfo {736 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);737738 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);739740 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))741 }742743 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]744 #[transactional]745 pub fn delete_token_properties(746 origin,747 collection_id: CollectionId,748 token_id: TokenId,749 property_keys: Vec<PropertyKey>750 ) -> DispatchResultWithPostInfo {751 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);752753 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);754755 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))756 }757758 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]759 #[transactional]760 pub fn set_property_permissions(761 origin,762 collection_id: CollectionId,763 property_permissions: Vec<PropertyKeyPermission>,764 ) -> DispatchResultWithPostInfo {765 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);766767 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);768769 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))770 }771772 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]773 #[transactional]774 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {775 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);776 let budget = budget::Value::new(2);777778 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))779 }780781 // TODO! transaction weight782783 /// Set transfers_enabled value for particular collection784 ///785 /// # Permissions786 ///787 /// * Collection Owner.788 ///789 /// # Arguments790 ///791 /// * collection_id: ID of the collection.792 ///793 /// * value: New flag value.794 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]795 #[transactional]796 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {797 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);798 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;799 target_collection.check_is_owner(&sender)?;800801 // =========802803 target_collection.limits.transfers_enabled = Some(value);804 target_collection.save()805 }806807 /// Destroys a concrete instance of NFT.808 ///809 /// # Permissions810 ///811 /// * Collection Owner.812 /// * Collection Admin.813 /// * Current NFT Owner.814 ///815 /// # Arguments816 ///817 /// * collection_id: ID of the collection.818 ///819 /// * item_id: ID of NFT to burn.820 #[weight = T::CommonWeightInfo::burn_item()]821 #[transactional]822 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {823 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);824825 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;826 if value == 1 {827 <NftTransferBasket<T>>::remove(collection_id, item_id);828 <NftApproveBasket<T>>::remove(collection_id, item_id);829 }830 // Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?831 // <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());832 // <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));833 Ok(post_info)834 }835836 /// Destroys a concrete instance of NFT on behalf of the owner837 /// See also: [`approve`]838 ///839 /// # Permissions840 ///841 /// * Collection Owner.842 /// * Collection Admin.843 /// * Current NFT Owner.844 ///845 /// # Arguments846 ///847 /// * collection_id: ID of the collection.848 ///849 /// * item_id: ID of NFT to burn.850 ///851 /// * from: owner of item852 #[weight = T::CommonWeightInfo::burn_from()]853 #[transactional]854 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {855 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);856 let budget = budget::Value::new(2);857858 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))859 }860861 /// Change ownership of the token.862 ///863 /// # Permissions864 ///865 /// * Collection Owner866 /// * Collection Admin867 /// * Current NFT owner868 ///869 /// # Arguments870 ///871 /// * recipient: Address of token recipient.872 ///873 /// * collection_id.874 ///875 /// * item_id: ID of the item876 /// * Non-Fungible Mode: Required.877 /// * Fungible Mode: Ignored.878 /// * Re-Fungible Mode: Required.879 ///880 /// * value: Amount to transfer.881 /// * Non-Fungible Mode: Ignored882 /// * Fungible Mode: Must specify transferred amount883 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)884 #[weight = T::CommonWeightInfo::transfer()]885 #[transactional]886 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {887 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);888 let budget = budget::Value::new(2);889890 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))891 }892893 /// Set, change, or remove approved address to transfer the ownership of the NFT.894 ///895 /// # Permissions896 ///897 /// * Collection Owner898 /// * Collection Admin899 /// * Current NFT owner900 ///901 /// # Arguments902 ///903 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).904 ///905 /// * collection_id.906 ///907 /// * item_id: ID of the item.908 #[weight = T::CommonWeightInfo::approve()]909 #[transactional]910 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {911 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);912913 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))914 }915916 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.917 ///918 /// # Permissions919 /// * Collection Owner920 /// * Collection Admin921 /// * Current NFT owner922 /// * Address approved by current NFT owner923 ///924 /// # Arguments925 ///926 /// * from: Address that owns token.927 ///928 /// * recipient: Address of token recipient.929 ///930 /// * collection_id.931 ///932 /// * item_id: ID of the item.933 ///934 /// * value: Amount to transfer.935 #[weight = T::CommonWeightInfo::transfer_from()]936 #[transactional]937 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {938 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);939 let budget = budget::Value::new(2);940941 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))942 }943944 /// Set schema standard945 /// ImageURL946 /// Unique947 ///948 /// # Permissions949 ///950 /// * Collection Owner951 /// * Collection Admin952 ///953 /// # Arguments954 ///955 /// * collection_id.956 ///957 /// * schema: SchemaVersion: enum958 #[weight = <SelfWeightOf<T>>::set_schema_version()]959 #[transactional]960 pub fn set_schema_version(961 origin,962 collection_id: CollectionId,963 version: SchemaVersion964 ) -> DispatchResult {965 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);966 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;967 target_collection.check_is_owner_or_admin(&sender)?;968 target_collection.schema_version = version;969970 <Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(971 collection_id972 ));973974 target_collection.save()975 }976977 /// Set off-chain data schema.978 ///979 /// # Permissions980 ///981 /// * Collection Owner982 /// * Collection Admin983 ///984 /// # Arguments985 ///986 /// * collection_id.987 ///988 /// * schema: String representing the offchain data schema.989 #[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]990 #[transactional]991 pub fn set_offchain_schema(992 origin,993 collection_id: CollectionId,994 schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,995 ) -> DispatchResult {996 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);997 let collection = <CollectionHandle<T>>::try_get(collection_id)?;998999 // =========10001001 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;10021003 <Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1004 collection_id1005 ));1006 Ok(())1007 }10081009 /// Set const on-chain data schema.1010 ///1011 /// # Permissions1012 ///1013 /// * Collection Owner1014 /// * Collection Admin1015 ///1016 /// # Arguments1017 ///1018 /// * collection_id.1019 ///1020 /// * schema: String representing the const on-chain data schema.1021 #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1022 #[transactional]1023 pub fn set_const_on_chain_schema (1024 origin,1025 collection_id: CollectionId,1026 schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1027 ) -> DispatchResult {1028 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1029 let collection = <CollectionHandle<T>>::try_get(collection_id)?;10301031 // =========10321033 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;10341035 <Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1036 collection_id1037 ));1038 Ok(())1039 }10401041 #[weight = <SelfWeightOf<T>>::set_collection_limits()]1042 #[transactional]1043 pub fn set_collection_limits(1044 origin,1045 collection_id: CollectionId,1046 new_limit: CollectionLimits,1047 ) -> DispatchResult {1048 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1049 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1050 target_collection.check_is_owner(&sender)?;1051 let old_limit = &target_collection.limits;10521053 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10541055 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1056 collection_id1057 ));10581059 target_collection.save()1060 }1061 }1062}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20 clippy::too_many_arguments,21 clippy::unnecessary_mut_passed,22 clippy::unused_unit23)]2425use frame_support::{26 decl_module, decl_storage, decl_error, decl_event,27 dispatch::DispatchResult,28 ensure,29 weights::{Weight},30 transactional,31 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32 BoundedVec,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38 CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT, MAX_COLLECTION_NAME_LENGTH,39 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,40 CollectionLimits, CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState,41 CreateCollectionData, CreateItemExData, budget, CollectionField, Property, PropertyKey,42 PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,47 dispatch::CollectionDispatch,48};4950#[cfg(feature = "runtime-benchmarks")]51mod benchmarking;52pub mod weights;53use weights::WeightInfo;5455decl_error! {56 /// Error for non-fungible-token module.57 pub enum Error for Module<T: Config> {58 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.59 CollectionDecimalPointLimitExceeded,60 /// This address is not set as sponsor, use setCollectionSponsor first.61 ConfirmUnsetSponsorFail,62 /// Length of items properties must be greater than 0.63 EmptyArgument,64 }65}6667pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {68 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;6970 /// Weight information for extrinsics in this pallet.71 type WeightInfo: WeightInfo;72 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;73}7475decl_event! {76 pub enum Event<T>77 where78 <T as frame_system::Config>::AccountId,79 <T as pallet_evm::account::Config>::CrossAccountId,80 {81 /// Collection sponsor was removed82 ///83 /// # Arguments84 ///85 /// * collection_id: Globally unique collection identifier.86 CollectionSponsorRemoved(CollectionId),8788 /// Collection admin was added89 ///90 /// # Arguments91 ///92 /// * collection_id: Globally unique collection identifier.93 ///94 /// * admin: Admin address.95 CollectionAdminAdded(CollectionId, CrossAccountId),9697 /// Collection owned was change98 ///99 /// # Arguments100 ///101 /// * collection_id: Globally unique collection identifier.102 ///103 /// * owner: New owner address.104 CollectionOwnedChanged(CollectionId, AccountId),105106 /// Collection sponsor was set107 ///108 /// # Arguments109 ///110 /// * collection_id: Globally unique collection identifier.111 ///112 /// * owner: New sponsor address.113 CollectionSponsorSet(CollectionId, AccountId),114115 /// const on chain schema was set116 ///117 /// # Arguments118 ///119 /// * collection_id: Globally unique collection identifier.120 ConstOnChainSchemaSet(CollectionId),121122 /// New sponsor was confirm123 ///124 /// # Arguments125 ///126 /// * collection_id: Globally unique collection identifier.127 ///128 /// * sponsor: New sponsor address.129 SponsorshipConfirmed(CollectionId, AccountId),130131 /// Collection admin was removed132 ///133 /// # Arguments134 ///135 /// * collection_id: Globally unique collection identifier.136 ///137 /// * admin: Admin address.138 CollectionAdminRemoved(CollectionId, CrossAccountId),139140 /// Address was remove from allow list141 ///142 /// # Arguments143 ///144 /// * collection_id: Globally unique collection identifier.145 ///146 /// * user: Address.147 AllowListAddressRemoved(CollectionId, CrossAccountId),148149 /// Address was add to allow list150 ///151 /// # Arguments152 ///153 /// * collection_id: Globally unique collection identifier.154 ///155 /// * user: Address.156 AllowListAddressAdded(CollectionId, CrossAccountId),157158 /// Collection limits was set159 ///160 /// # Arguments161 ///162 /// * collection_id: Globally unique collection identifier.163 CollectionLimitSet(CollectionId),164165 /// Mint permission was set166 ///167 /// # Arguments168 ///169 /// * collection_id: Globally unique collection identifier.170 MintPermissionSet(CollectionId),171172 /// Offchain schema was set173 ///174 /// # Arguments175 ///176 /// * collection_id: Globally unique collection identifier.177 OffchainSchemaSet(CollectionId),178179 /// Public access mode was set180 ///181 /// # Arguments182 ///183 /// * collection_id: Globally unique collection identifier.184 ///185 /// * mode: New access state.186 PublicAccessModeSet(CollectionId, AccessMode),187188 /// Schema version was set189 ///190 /// # Arguments191 ///192 /// * collection_id: Globally unique collection identifier.193 SchemaVersionSet(CollectionId),194 }195}196197type SelfWeightOf<T> = <T as Config>::WeightInfo;198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204// i.e autoincrementing index205// can use non-cryptographic hash206// real - key is controlled by user207// but it is hard to generate enough colliding values, i.e owner of signed txs208// can use non-cryptographic hash209// controlled - key is completly controlled by users210// i.e maps with mutable keys211// should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216// collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218// same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220// no confirmation required, so addresses can be easily generated221decl_storage! {222 trait Store for Module<T: Config> as Unique {223224 //#region Private members225 /// Used for migrations226 ChainVersion: u64;227 //#endregion228229 //#region Tokens transfer rate limit baskets230 /// (Collection id (controlled?2), who created (real))231 /// TODO: Off chain worker should remove from this map when collection gets removed232 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;233 /// Collection id (controlled?2), token id (controlled?2)234 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;235 /// Collection id (controlled?2), owning user (real)236 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;237 /// Collection id (controlled?2), token id (controlled?2)238 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239 //#endregion240241 /// Variable metadata sponsoring242 /// Collection id (controlled?2), token id (controlled?2)243 #[deprecated]244 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;245 pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;246247 /// Approval sponsoring248 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;249 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;250 pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;251 }252}253254decl_module! {255 pub struct Module<T: Config> for enum Call256 where257 origin: T::Origin258 {259 type Error = Error<T>;260261 fn deposit_event() = default;262263 fn on_initialize(_now: T::BlockNumber) -> Weight {264 0265 }266267 fn on_runtime_upgrade() -> Weight {268 let limit = None;269270 <VariableMetaDataBasket<T>>::remove_all(limit);271272 0273 }274275 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.276 ///277 /// # Permissions278 ///279 /// * Anyone.280 ///281 /// # Arguments282 ///283 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.284 ///285 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.286 ///287 /// * token_prefix: UTF-8 string with token prefix.288 ///289 /// * mode: [CollectionMode] collection type and type dependent data.290 // returns collection ID291 #[weight = <SelfWeightOf<T>>::create_collection()]292 #[transactional]293 #[deprecated]294 pub fn create_collection(origin,295 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,296 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,297 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,298 mode: CollectionMode) -> DispatchResult {299 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {300 name: collection_name,301 description: collection_description,302 token_prefix,303 mode,304 ..Default::default()305 };306 Self::create_collection_ex(origin, data)307 }308309 /// This method creates a collection310 ///311 /// Prefer it to deprecated [`created_collection`] method312 #[weight = <SelfWeightOf<T>>::create_collection()]313 #[transactional]314 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {315 let sender = ensure_signed(origin)?;316317 // =========318319 T::CollectionDispatch::create(sender, data)?;320321 Ok(())322 }323324 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.325 ///326 /// # Permissions327 ///328 /// * Collection Owner.329 ///330 /// # Arguments331 ///332 /// * collection_id: collection to destroy.333 #[weight = <SelfWeightOf<T>>::destroy_collection()]334 #[transactional]335 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {336 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);337 let collection = <CollectionHandle<T>>::try_get(collection_id)?;338339 // =========340341 T::CollectionDispatch::destroy(sender, collection)?;342343 <NftTransferBasket<T>>::remove_prefix(collection_id, None);344 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);345 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);346347 <NftApproveBasket<T>>::remove_prefix(collection_id, None);348 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);349 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);350351 Ok(())352 }353354 /// Add an address to allow list.355 ///356 /// # Permissions357 ///358 /// * Collection Owner359 /// * Collection Admin360 ///361 /// # Arguments362 ///363 /// * collection_id.364 ///365 /// * address.366 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]367 #[transactional]368 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{369370 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);371 let collection = <CollectionHandle<T>>::try_get(collection_id)?;372373 <PalletCommon<T>>::toggle_allowlist(374 &collection,375 &sender,376 &address,377 true,378 )?;379380 Self::deposit_event(Event::<T>::AllowListAddressAdded(381 collection_id,382 address383 ));384385 Ok(())386 }387388 /// Remove an address from allow list.389 ///390 /// # Permissions391 ///392 /// * Collection Owner393 /// * Collection Admin394 ///395 /// # Arguments396 ///397 /// * collection_id.398 ///399 /// * address.400 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]401 #[transactional]402 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{403404 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);405 let collection = <CollectionHandle<T>>::try_get(collection_id)?;406407 <PalletCommon<T>>::toggle_allowlist(408 &collection,409 &sender,410 &address,411 false,412 )?;413414 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(415 collection_id,416 address417 ));418419 Ok(())420 }421422 /// Toggle between normal and allow list access for the methods with access for `Anyone`.423 ///424 /// # Permissions425 ///426 /// * Collection Owner.427 ///428 /// # Arguments429 ///430 /// * collection_id.431 ///432 /// * mode: [AccessMode]433 #[weight = <SelfWeightOf<T>>::set_public_access_mode()]434 #[transactional]435 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult436 {437 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);438439 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;440 target_collection.check_is_owner(&sender)?;441442 target_collection.access = mode.clone();443444 <Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(445 collection_id,446 mode447 ));448449 target_collection.save()450 }451452 /// Allows Anyone to create tokens if:453 /// * Allow List is enabled, and454 /// * Address is added to allow list, and455 /// * This method was called with True parameter456 ///457 /// # Permissions458 /// * Collection Owner459 ///460 /// # Arguments461 ///462 /// * collection_id.463 ///464 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.465 #[weight = <SelfWeightOf<T>>::set_mint_permission()]466 #[transactional]467 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult468 {469 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);470471 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;472 target_collection.check_is_owner(&sender)?;473474 target_collection.mint_mode = mint_permission;475476 <Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(477 collection_id478 ));479480 target_collection.save()481 }482483 /// Change the owner of the collection.484 ///485 /// # Permissions486 ///487 /// * Collection Owner.488 ///489 /// # Arguments490 ///491 /// * collection_id.492 ///493 /// * new_owner.494 #[weight = <SelfWeightOf<T>>::change_collection_owner()]495 #[transactional]496 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {497498 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);499500 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;501 target_collection.check_is_owner(&sender)?;502503 target_collection.owner = new_owner.clone();504 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(505 collection_id,506 new_owner507 ));508509 target_collection.save()510 }511512 /// Adds an admin of the Collection.513 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.514 ///515 /// # Permissions516 ///517 /// * Collection Owner.518 /// * Collection Admin.519 ///520 /// # Arguments521 ///522 /// * collection_id: ID of the Collection to add admin for.523 ///524 /// * new_admin_id: Address of new admin to add.525 #[weight = <SelfWeightOf<T>>::add_collection_admin()]526 #[transactional]527 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {528 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);529 let collection = <CollectionHandle<T>>::try_get(collection_id)?;530531 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(532 collection_id,533 new_admin_id.clone()534 ));535536 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)537 }538539 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.540 ///541 /// # Permissions542 ///543 /// * Collection Owner.544 /// * Collection Admin.545 ///546 /// # Arguments547 ///548 /// * collection_id: ID of the Collection to remove admin for.549 ///550 /// * account_id: Address of admin to remove.551 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]552 #[transactional]553 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {554 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);555 let collection = <CollectionHandle<T>>::try_get(collection_id)?;556557 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(558 collection_id,559 account_id.clone()560 ));561562 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)563 }564565 /// # Permissions566 ///567 /// * Collection Owner568 ///569 /// # Arguments570 ///571 /// * collection_id.572 ///573 /// * new_sponsor.574 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]575 #[transactional]576 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {577 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);578579 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;580 target_collection.check_is_owner(&sender)?;581582 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());583584 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(585 collection_id,586 new_sponsor587 ));588589 target_collection.save()590 }591592 /// # Permissions593 ///594 /// * Sponsor.595 ///596 /// # Arguments597 ///598 /// * collection_id.599 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]600 #[transactional]601 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {602 let sender = ensure_signed(origin)?;603604 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;605 ensure!(606 target_collection.sponsorship.pending_sponsor() == Some(&sender),607 Error::<T>::ConfirmUnsetSponsorFail608 );609610 target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());611612 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(613 collection_id,614 sender615 ));616617 target_collection.save()618 }619620 /// Switch back to pay-per-own-transaction model.621 ///622 /// # Permissions623 ///624 /// * Collection owner.625 ///626 /// # Arguments627 ///628 /// * collection_id.629 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]630 #[transactional]631 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {632 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);633634 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;635 target_collection.check_is_owner(&sender)?;636637 target_collection.sponsorship = SponsorshipState::Disabled;638639 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(640 collection_id641 ));642 target_collection.save()643 }644645 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.646 ///647 /// # Permissions648 ///649 /// * Collection Owner.650 /// * Collection Admin.651 /// * Anyone if652 /// * Allow List is enabled, and653 /// * Address is added to allow list, and654 /// * MintPermission is enabled (see SetMintPermission method)655 ///656 /// # Arguments657 ///658 /// * collection_id: ID of the collection.659 ///660 /// * owner: Address, initial owner of the NFT.661 ///662 /// * data: Token data to store on chain.663 #[weight = T::CommonWeightInfo::create_item()]664 #[transactional]665 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {666 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);667 let budget = budget::Value::new(2);668669 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))670 }671672 /// This method creates multiple items in a collection created with CreateCollection method.673 ///674 /// # Permissions675 ///676 /// * Collection Owner.677 /// * Collection Admin.678 /// * Anyone if679 /// * Allow List is enabled, and680 /// * Address is added to allow list, and681 /// * MintPermission is enabled (see SetMintPermission method)682 ///683 /// # Arguments684 ///685 /// * collection_id: ID of the collection.686 ///687 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].688 ///689 /// * owner: Address, initial owner of the NFT.690 #[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]691 #[transactional]692 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {693 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);694 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);695 let budget = budget::Value::new(2);696697 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))698 }699700 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]701 #[transactional]702 pub fn set_collection_properties(703 origin,704 collection_id: CollectionId,705 properties: Vec<Property>706 ) -> DispatchResultWithPostInfo {707 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);708709 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);710711 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))712 }713714 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]715 #[transactional]716 pub fn delete_collection_properties(717 origin,718 collection_id: CollectionId,719 property_keys: Vec<PropertyKey>,720 ) -> DispatchResultWithPostInfo {721 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);722723 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);724725 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))726 }727728 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]729 #[transactional]730 pub fn set_token_properties(731 origin,732 collection_id: CollectionId,733 token_id: TokenId,734 properties: Vec<Property>735 ) -> DispatchResultWithPostInfo {736 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);737738 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);739740 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))741 }742743 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]744 #[transactional]745 pub fn delete_token_properties(746 origin,747 collection_id: CollectionId,748 token_id: TokenId,749 property_keys: Vec<PropertyKey>750 ) -> DispatchResultWithPostInfo {751 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);752753 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);754755 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))756 }757758 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]759 #[transactional]760 pub fn set_property_permissions(761 origin,762 collection_id: CollectionId,763 property_permissions: Vec<PropertyKeyPermission>,764 ) -> DispatchResultWithPostInfo {765 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);766767 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);768769 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))770 }771772 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]773 #[transactional]774 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {775 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);776 let budget = budget::Value::new(2);777778 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))779 }780781 // TODO! transaction weight782783 /// Set transfers_enabled value for particular collection784 ///785 /// # Permissions786 ///787 /// * Collection Owner.788 ///789 /// # Arguments790 ///791 /// * collection_id: ID of the collection.792 ///793 /// * value: New flag value.794 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]795 #[transactional]796 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {797 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);798 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;799 target_collection.check_is_owner(&sender)?;800801 // =========802803 target_collection.limits.transfers_enabled = Some(value);804 target_collection.save()805 }806807 /// Destroys a concrete instance of NFT.808 ///809 /// # Permissions810 ///811 /// * Collection Owner.812 /// * Collection Admin.813 /// * Current NFT Owner.814 ///815 /// # Arguments816 ///817 /// * collection_id: ID of the collection.818 ///819 /// * item_id: ID of NFT to burn.820 #[weight = T::CommonWeightInfo::burn_item()]821 #[transactional]822 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {823 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);824825 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;826 if value == 1 {827 <NftTransferBasket<T>>::remove(collection_id, item_id);828 <NftApproveBasket<T>>::remove(collection_id, item_id);829 }830 // Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?831 // <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());832 // <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));833 Ok(post_info)834 }835836 /// Destroys a concrete instance of NFT on behalf of the owner837 /// See also: [`approve`]838 ///839 /// # Permissions840 ///841 /// * Collection Owner.842 /// * Collection Admin.843 /// * Current NFT Owner.844 ///845 /// # Arguments846 ///847 /// * collection_id: ID of the collection.848 ///849 /// * item_id: ID of NFT to burn.850 ///851 /// * from: owner of item852 #[weight = T::CommonWeightInfo::burn_from()]853 #[transactional]854 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {855 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);856 let budget = budget::Value::new(2);857858 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))859 }860861 /// Change ownership of the token.862 ///863 /// # Permissions864 ///865 /// * Collection Owner866 /// * Collection Admin867 /// * Current NFT owner868 ///869 /// # Arguments870 ///871 /// * recipient: Address of token recipient.872 ///873 /// * collection_id.874 ///875 /// * item_id: ID of the item876 /// * Non-Fungible Mode: Required.877 /// * Fungible Mode: Ignored.878 /// * Re-Fungible Mode: Required.879 ///880 /// * value: Amount to transfer.881 /// * Non-Fungible Mode: Ignored882 /// * Fungible Mode: Must specify transferred amount883 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)884 #[weight = T::CommonWeightInfo::transfer()]885 #[transactional]886 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {887 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);888 let budget = budget::Value::new(2);889890 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))891 }892893 /// Set, change, or remove approved address to transfer the ownership of the NFT.894 ///895 /// # Permissions896 ///897 /// * Collection Owner898 /// * Collection Admin899 /// * Current NFT owner900 ///901 /// # Arguments902 ///903 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).904 ///905 /// * collection_id.906 ///907 /// * item_id: ID of the item.908 #[weight = T::CommonWeightInfo::approve()]909 #[transactional]910 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {911 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);912913 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))914 }915916 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.917 ///918 /// # Permissions919 /// * Collection Owner920 /// * Collection Admin921 /// * Current NFT owner922 /// * Address approved by current NFT owner923 ///924 /// # Arguments925 ///926 /// * from: Address that owns token.927 ///928 /// * recipient: Address of token recipient.929 ///930 /// * collection_id.931 ///932 /// * item_id: ID of the item.933 ///934 /// * value: Amount to transfer.935 #[weight = T::CommonWeightInfo::transfer_from()]936 #[transactional]937 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {938 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);939 let budget = budget::Value::new(2);940941 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))942 }943944 /// Set schema standard945 /// ImageURL946 /// Unique947 ///948 /// # Permissions949 ///950 /// * Collection Owner951 /// * Collection Admin952 ///953 /// # Arguments954 ///955 /// * collection_id.956 ///957 /// * schema: SchemaVersion: enum958 #[weight = <SelfWeightOf<T>>::set_schema_version()]959 #[transactional]960 pub fn set_schema_version(961 origin,962 collection_id: CollectionId,963 version: SchemaVersion964 ) -> DispatchResult {965 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);966 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;967 target_collection.check_is_owner_or_admin(&sender)?;968 target_collection.schema_version = version;969970 <Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(971 collection_id972 ));973974 target_collection.save()975 }976977 /// Set off-chain data schema.978 ///979 /// # Permissions980 ///981 /// * Collection Owner982 /// * Collection Admin983 ///984 /// # Arguments985 ///986 /// * collection_id.987 ///988 /// * schema: String representing the offchain data schema.989 #[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]990 #[transactional]991 pub fn set_offchain_schema(992 origin,993 collection_id: CollectionId,994 schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,995 ) -> DispatchResult {996 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);997 let collection = <CollectionHandle<T>>::try_get(collection_id)?;998999 // =========10001001 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;10021003 <Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1004 collection_id1005 ));1006 Ok(())1007 }10081009 /// Set const on-chain data schema.1010 ///1011 /// # Permissions1012 ///1013 /// * Collection Owner1014 /// * Collection Admin1015 ///1016 /// # Arguments1017 ///1018 /// * collection_id.1019 ///1020 /// * schema: String representing the const on-chain data schema.1021 #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1022 #[transactional]1023 pub fn set_const_on_chain_schema (1024 origin,1025 collection_id: CollectionId,1026 schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1027 ) -> DispatchResult {1028 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1029 let collection = <CollectionHandle<T>>::try_get(collection_id)?;10301031 // =========10321033 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;10341035 <Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1036 collection_id1037 ));1038 Ok(())1039 }10401041 #[weight = <SelfWeightOf<T>>::set_collection_limits()]1042 #[transactional]1043 pub fn set_collection_limits(1044 origin,1045 collection_id: CollectionId,1046 new_limit: CollectionLimits,1047 ) -> DispatchResult {1048 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1049 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1050 target_collection.check_is_owner(&sender)?;1051 let old_limit = &target_collection.limits;10521053 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10541055 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1056 collection_id1057 ));10581059 target_collection.save()1060 }1061 }1062}primitives/data-structs/Cargo.tomldiffbeforeafterboth--- a/primitives/data-structs/Cargo.toml
+++ b/primitives/data-structs/Cargo.toml
@@ -42,3 +42,4 @@
]
serde1 = ["serde"]
limit-testing = []
+runtime-benchmarks = []
\ No newline at end of file
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -861,7 +861,9 @@
) -> Result<(), PropertiesError> {
let value_len = value.len();
- if self.consumed_space as usize + value_len > self.space_limit as usize {
+ if self.consumed_space as usize + value_len > self.space_limit as usize
+ && !cfg!(feature = "runtime-benchmarks")
+ {
return Err(PropertiesError::NoSpaceForProperty);
}
runtime/common/src/eth_sponsoring.rsdiffbeforeafterboth--- a/runtime/common/src/eth_sponsoring.rs
+++ b/runtime/common/src/eth_sponsoring.rs
@@ -50,16 +50,20 @@
CollectionMode::NFT => {
let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
match call {
- UniqueNFTCall::TokenProperties(
- TokenPropertiesCall::SetProperty { token_id, key, value, .. },
- ) => {
+ UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty {
+ token_id,
+ key,
+ value,
+ ..
+ }) => {
let token_id: TokenId = token_id.try_into().ok()?;
withdraw_set_token_property::<T>(
&collection,
&who,
&token_id,
key.len() + value.len(),
- ).map(|()| sponsor)
+ )
+ .map(|()| sponsor)
}
UniqueNFTCall::ERC721UniqueExtensions(
ERC721UniqueExtensionsCall::Transfer { token_id, .. },
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -776,6 +776,7 @@
let mut list = Vec::<BenchmarkList>::new();
list_benchmark!(list, extra, pallet_evm_migration, EvmMigration);
+ list_benchmark!(list, extra, pallet_common, Common);
list_benchmark!(list, extra, pallet_unique, Unique);
list_benchmark!(list, extra, pallet_structure, Structure);
list_benchmark!(list, extra, pallet_inflation, Inflation);
@@ -814,6 +815,7 @@
let params = (&config, &allowlist);
add_benchmark!(params, batches, pallet_evm_migration, EvmMigration);
+ add_benchmark!(params, batches, pallet_common, Common);
add_benchmark!(params, batches, pallet_unique, Unique);
add_benchmark!(params, batches, pallet_structure, Structure);
add_benchmark!(params, batches, pallet_inflation, Inflation);
runtime/common/src/sponsoring.rsdiffbeforeafterboth--- a/runtime/common/src/sponsoring.rs
+++ b/runtime/common/src/sponsoring.rs
@@ -29,8 +29,8 @@
use pallet_evm::account::CrossAccountId;
use pallet_unique::{
Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
- NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket,
- FungibleTransferBasket, NftTransferBasket, TokenPropertyBasket,
+ NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,
+ NftTransferBasket, TokenPropertyBasket,
};
use pallet_fungible::Config as FungibleConfig;
use pallet_nonfungible::Config as NonfungibleConfig;
@@ -247,7 +247,7 @@
&T::CrossAccountId::from_sub(who.clone()),
&token_id,
// No overflow may happen, as data larger than usize can't reach here
- properties.iter().map(|p| p.key.len() + p.value.len()).sum()
+ properties.iter().map(|p| p.key.len() + p.value.len()).sum(),
)
.map(|()| sponsor)
}
runtime/common/src/weights.rsdiffbeforeafterboth--- a/runtime/common/src/weights.rs
+++ b/runtime/common/src/weights.rs
@@ -21,7 +21,7 @@
use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};
use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};
use pallet_refungible::{Config as RefungibleConfig, common::CommonWeights as RefungibleWeights};
-use up_data_structs::CreateItemExData;
+use up_data_structs::{CreateItemExData, CreateItemData};
macro_rules! max_weight_of {
($method:ident ( $($args:tt)* )) => {
@@ -42,8 +42,8 @@
dispatch_weight::<T>() + max_weight_of!(create_item())
}
- fn create_multiple_items(amount: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(create_multiple_items(amount))
+ fn create_multiple_items(data: &[CreateItemData]) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(create_multiple_items(data))
}
fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
runtime/opal/src/lib.rsdiffbeforeafterboth--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -875,6 +875,7 @@
}
impl pallet_common::Config for Runtime {
+ type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
type Event = Event;
type Currency = Balances;
type CollectionCreationPrice = CollectionCreationPrice;
runtime/tests/src/lib.rsdiffbeforeafterboth--- a/runtime/tests/src/lib.rs
+++ b/runtime/tests/src/lib.rs
@@ -212,6 +212,7 @@
}
impl pallet_common::Config for Test {
+ type WeightInfo = ();
type Event = ();
type Currency = Balances;
type CollectionCreationPrice = CollectionCreationPrice;
runtime/unique/Cargo.tomldiffbeforeafterboth--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -39,6 +39,7 @@
'pallet-xcm/runtime-benchmarks',
'sp-runtime/runtime-benchmarks',
'xcm-builder/runtime-benchmarks',
+ 'up-data-structs/runtime-benchmarks',
]
try-runtime = [
'frame-try-runtime',
runtime/unique/src/lib.rsdiffbeforeafterboth--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -66,7 +66,12 @@
WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
},
};
-use unique_runtime_common::dispatch::{CollectionDispatchT, CollectionDispatch};
+use unique_runtime_common::{
+ dispatch::{CollectionDispatchT, CollectionDispatch},
+ weights::CommonWeights,
+ sponsoring::UniqueSponsorshipHandler,
+ eth_sponsoring::UniqueEthSponsorshipHandler,
+};
use up_data_structs::*;
// use pallet_contracts::weights::WeightInfo;
// #[cfg(any(feature = "std", test))]
@@ -846,6 +851,7 @@
}
impl pallet_common::Config for Runtime {
+ type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
type Event = Event;
type Currency = Balances;
type CollectionCreationPrice = CollectionCreationPrice;
@@ -881,6 +887,7 @@
impl pallet_unique::Config for Runtime {
type Event = Event;
type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
+ type CommonWeightInfo = CommonWeights<Self>;
}
parameter_types! {
@@ -902,11 +909,11 @@
// }
type EvmSponsorshipHandler = (
- pallet_unique::UniqueEthSponsorshipHandler<Runtime>,
+ UniqueEthSponsorshipHandler<Runtime>,
pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
);
type SponsorshipHandler = (
- pallet_unique::UniqueSponsorshipHandler<Runtime>,
+ UniqueSponsorshipHandler<Runtime>,
//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
);