mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 09:21:04 +00:00
Uniques: An economically-secure basic-featured NFT pallet (#8813)
* Uniques: An economically-secure basic-featured NFT pallet * force_transfer * freeze/thaw * team management * approvals * Fixes * force_asset_status * class_metadata * instance metadata * Fixes * use nmap * Fixes * class metadata has information field * Intiial mock/tests and a fix * Remove impl_non_fungibles * Docs * Update frame/uniques/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update frame/uniques/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update frame/uniques/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update frame/uniques/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Reserve, don't transfer. * Fixes * Tests * Tests * refresh_deposit * Tests and proper handling of metdata destruction * test burn * Tests * Update impl_fungibles.rs * Initial benchmarking * benchmark * Fixes * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Attributes * Attribute metadata * Fixes * Update frame/uniques/README.md * Docs * Docs * Docs * Simple metadata * Use BoundedVec * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/uniques/src/lib.rs Co-authored-by: Lohann Paterno Coutinho Ferreira <developer@lohann.dev> * Update frame/uniques/src/lib.rs Co-authored-by: Lohann Paterno Coutinho Ferreira <developer@lohann.dev> * Update frame/uniques/src/lib.rs Co-authored-by: Lohann Paterno Coutinho Ferreira <developer@lohann.dev> * Update frame/uniques/src/lib.rs Co-authored-by: Lohann Paterno Coutinho Ferreira <developer@lohann.dev> * Update frame/uniques/src/lib.rs Co-authored-by: Lohann Paterno Coutinho Ferreira <developer@lohann.dev> * Fixes * Update frame/uniques/README.md Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update frame/uniques/README.md Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update frame/uniques/README.md Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Docs * Bump Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Parity Bot <admin@parity.io> Co-authored-by: Lohann Paterno Coutinho Ferreira <developer@lohann.dev> Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
[package]
|
||||
name = "pallet-uniques"
|
||||
version = "3.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://substrate.dev"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
description = "FRAME NFT asset management pallet"
|
||||
readme = "README.md"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
|
||||
sp-std = { version = "3.0.0", default-features = false, path = "../../primitives/std" }
|
||||
sp-core = { version = "3.0.0", default-features = false, path = "../../primitives/core" }
|
||||
sp-runtime = { version = "3.0.0", default-features = false, path = "../../primitives/runtime" }
|
||||
frame-support = { version = "3.0.0", default-features = false, path = "../support" }
|
||||
frame-system = { version = "3.0.0", default-features = false, path = "../system" }
|
||||
frame-benchmarking = { version = "3.1.0", default-features = false, path = "../benchmarking", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-std = { version = "3.0.0", path = "../../primitives/std" }
|
||||
sp-core = { version = "3.0.0", path = "../../primitives/core" }
|
||||
sp-io = { version = "3.0.0", path = "../../primitives/io" }
|
||||
pallet-balances = { version = "3.0.0", path = "../balances" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"sp-std/std",
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"frame-benchmarking/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"frame-benchmarking",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = ["frame-support/try-runtime"]
|
||||
@@ -0,0 +1,78 @@
|
||||
# Uniques Module
|
||||
|
||||
A simple, secure module for dealing with non-fungible assets.
|
||||
|
||||
## Overview
|
||||
|
||||
The Uniques module provides functionality for asset management of non-fungible asset classes, including:
|
||||
|
||||
* Asset Issuance
|
||||
* Asset Transfer
|
||||
* Asset Destruction
|
||||
|
||||
To use it in your runtime, you need to implement the assets [`uniques::Config`](https://docs.rs/pallet-uniques/latest/pallet_uniques/pallet/trait.Config.html).
|
||||
|
||||
The supported dispatchable functions are documented in the [`uniques::Call`](https://docs.rs/pallet-uniques/latest/pallet_uniques/pallet/enum.Call.html) enum.
|
||||
|
||||
### Terminology
|
||||
|
||||
* **Asset issuance:** The creation of a new asset instance.
|
||||
* **Asset transfer:** The action of transferring an asset instance from one account to another.
|
||||
* **Asset burning:** The destruction of an asset instance.
|
||||
* **Non-fungible asset:** An asset for which each unit has unique characteristics. There is exactly
|
||||
one instance of such an asset in existance and there is exactly one owning account.
|
||||
|
||||
### Goals
|
||||
|
||||
The Uniques pallet in Substrate is designed to make the following possible:
|
||||
|
||||
* Allow accounts to permissionlessly create asset classes (collections of asset instances).
|
||||
* Allow a named (permissioned) account to mint and burn unique assets within a class.
|
||||
* Move asset instances between accounts permissionlessly.
|
||||
* Allow a named (permissioned) account to freeze and unfreeze unique assets within a
|
||||
class or the entire class.
|
||||
* Allow the owner of an asset instance to delegate the ability to transfer the asset to some
|
||||
named third-party.
|
||||
|
||||
## Interface
|
||||
|
||||
### Permissionless dispatchables
|
||||
* `create`: Create a new asset class by placing a deposit.
|
||||
* `transfer`: Transfer an asset instance to a new owner.
|
||||
* `redeposit`: Update the deposit amount of an asset instance, potentially freeing funds.
|
||||
* `approve_transfer`: Name a delegate who may authorise a transfer.
|
||||
* `cancel_approval`: Revert the effects of a previous `approve_transfer`.
|
||||
|
||||
### Permissioned dispatchables
|
||||
* `destroy`: Destroy an asset class.
|
||||
* `mint`: Mint a new asset instance within an asset class.
|
||||
* `burn`: Burn an asset instance within an asset class.
|
||||
* `freeze`: Prevent an individual asset from being transferred.
|
||||
* `thaw`: Revert the effects of a previous `freeze`.
|
||||
* `freeze_class`: Prevent all asset within a class from being transferred.
|
||||
* `thaw_class`: Revert the effects of a previous `freeze_class`.
|
||||
* `transfer_ownership`: Alter the owner of an asset class, moving all associated deposits.
|
||||
* `set_team`: Alter the permissioned accounts of an asset class.
|
||||
|
||||
### Metadata (permissioned) dispatchables
|
||||
* `set_attribute`: Set a metadata attribute of an asset instance or class.
|
||||
* `clear_attribute`: Remove a metadata attribute of an asset instance or class.
|
||||
* `set_metadata`: Set general metadata of an asset instance.
|
||||
* `clear_metadata`: Remove general metadata of an asset instance.
|
||||
* `set_class_metadata`: Set general metadata of an asset class.
|
||||
* `clear_class_metadata`: Remove general metadata of an asset class.
|
||||
|
||||
### Force (i.e. governance) dispatchables
|
||||
* `force_create`: Create a new asset class.
|
||||
* `force_asset_status`: Alter the underlying characteristics of an asset class.
|
||||
|
||||
Please refer to the [`Call`](https://docs.rs/pallet-assets/latest/pallet_assets/enum.Call.html) enum
|
||||
and its associated variants for documentation on each function.
|
||||
|
||||
## Related Modules
|
||||
|
||||
* [`System`](https://docs.rs/frame-system/latest/frame_system/)
|
||||
* [`Support`](https://docs.rs/frame-support/latest/frame_support/)
|
||||
* [`Assets`](https://docs.rs/pallet-assets/latest/pallet_assetss/)
|
||||
|
||||
License: Apache-2.0
|
||||
@@ -0,0 +1,376 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Assets pallet benchmarking.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use sp_std::{prelude::*, convert::TryInto};
|
||||
use super::*;
|
||||
use sp_runtime::traits::Bounded;
|
||||
use frame_system::RawOrigin as SystemOrigin;
|
||||
use frame_benchmarking::{
|
||||
benchmarks_instance_pallet, account, whitelisted_caller, whitelist_account, impl_benchmark_test_suite
|
||||
};
|
||||
use frame_support::{traits::{Get, EnsureOrigin}, dispatch::UnfilteredDispatchable, BoundedVec};
|
||||
|
||||
use crate::Pallet as Uniques;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
fn create_class<T: Config<I>, I: 'static>()
|
||||
-> (T::ClassId, T::AccountId, <T::Lookup as StaticLookup>::Source)
|
||||
{
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
let class = Default::default();
|
||||
T::Currency::make_free_balance_be(&caller, DepositBalanceOf::<T, I>::max_value());
|
||||
assert!(Uniques::<T, I>::create(
|
||||
SystemOrigin::Signed(caller.clone()).into(),
|
||||
class,
|
||||
caller_lookup.clone(),
|
||||
).is_ok());
|
||||
(class, caller, caller_lookup)
|
||||
}
|
||||
|
||||
fn add_class_metadata<T: Config<I>, I: 'static>()
|
||||
-> (T::AccountId, <T::Lookup as StaticLookup>::Source)
|
||||
{
|
||||
let caller = Class::<T, I>::get(T::ClassId::default()).unwrap().owner;
|
||||
if caller != whitelisted_caller() {
|
||||
whitelist_account!(caller);
|
||||
}
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
assert!(Uniques::<T, I>::set_class_metadata(
|
||||
SystemOrigin::Signed(caller.clone()).into(),
|
||||
Default::default(),
|
||||
vec![0; T::StringLimit::get() as usize].try_into().unwrap(),
|
||||
false,
|
||||
).is_ok());
|
||||
(caller, caller_lookup)
|
||||
}
|
||||
|
||||
fn mint_instance<T: Config<I>, I: 'static>(index: u16)
|
||||
-> (T::InstanceId, T::AccountId, <T::Lookup as StaticLookup>::Source)
|
||||
{
|
||||
let caller = Class::<T, I>::get(T::ClassId::default()).unwrap().admin;
|
||||
if caller != whitelisted_caller() {
|
||||
whitelist_account!(caller);
|
||||
}
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
let instance = index.into();
|
||||
assert!(Uniques::<T, I>::mint(
|
||||
SystemOrigin::Signed(caller.clone()).into(),
|
||||
Default::default(),
|
||||
instance,
|
||||
caller_lookup.clone(),
|
||||
).is_ok());
|
||||
(instance, caller, caller_lookup)
|
||||
}
|
||||
|
||||
fn add_instance_metadata<T: Config<I>, I: 'static>(instance: T::InstanceId)
|
||||
-> (T::AccountId, <T::Lookup as StaticLookup>::Source)
|
||||
{
|
||||
let caller = Class::<T, I>::get(T::ClassId::default()).unwrap().owner;
|
||||
if caller != whitelisted_caller() {
|
||||
whitelist_account!(caller);
|
||||
}
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
assert!(Uniques::<T, I>::set_metadata(
|
||||
SystemOrigin::Signed(caller.clone()).into(),
|
||||
Default::default(),
|
||||
instance,
|
||||
vec![0; T::StringLimit::get() as usize].try_into().unwrap(),
|
||||
false,
|
||||
).is_ok());
|
||||
(caller, caller_lookup)
|
||||
}
|
||||
|
||||
fn add_instance_attribute<T: Config<I>, I: 'static>(instance: T::InstanceId)
|
||||
-> (BoundedVec<u8, T::KeyLimit>, T::AccountId, <T::Lookup as StaticLookup>::Source)
|
||||
{
|
||||
let caller = Class::<T, I>::get(T::ClassId::default()).unwrap().owner;
|
||||
if caller != whitelisted_caller() {
|
||||
whitelist_account!(caller);
|
||||
}
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
let key: BoundedVec<_, _> = vec![0; T::KeyLimit::get() as usize].try_into().unwrap();
|
||||
assert!(Uniques::<T, I>::set_attribute(
|
||||
SystemOrigin::Signed(caller.clone()).into(),
|
||||
Default::default(),
|
||||
Some(instance),
|
||||
key.clone(),
|
||||
vec![0; T::ValueLimit::get() as usize].try_into().unwrap(),
|
||||
).is_ok());
|
||||
(key, caller, caller_lookup)
|
||||
}
|
||||
|
||||
fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::Event) {
|
||||
let events = frame_system::Pallet::<T>::events();
|
||||
let system_event: <T as frame_system::Config>::Event = generic_event.into();
|
||||
// compare to the last event record
|
||||
let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
|
||||
assert_eq!(event, &system_event);
|
||||
}
|
||||
|
||||
benchmarks_instance_pallet! {
|
||||
create {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
T::Currency::make_free_balance_be(&caller, DepositBalanceOf::<T, I>::max_value());
|
||||
}: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Created(Default::default(), caller.clone(), caller).into());
|
||||
}
|
||||
|
||||
force_create {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
let caller_lookup = T::Lookup::unlookup(caller.clone());
|
||||
}: _(SystemOrigin::Root, Default::default(), caller_lookup, true)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ForceCreated(Default::default(), caller).into());
|
||||
}
|
||||
|
||||
destroy {
|
||||
let n in 0 .. 1_000;
|
||||
let m in 0 .. 1_000;
|
||||
let a in 0 .. 1_000;
|
||||
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
add_class_metadata::<T, I>();
|
||||
for i in 0..n {
|
||||
mint_instance::<T, I>(i as u16);
|
||||
}
|
||||
for i in 0..m {
|
||||
add_instance_metadata::<T, I>((i as u16).into());
|
||||
}
|
||||
for i in 0..a {
|
||||
add_instance_attribute::<T, I>((i as u16).into());
|
||||
}
|
||||
let witness = Class::<T, I>::get(class).unwrap().destroy_witness();
|
||||
}: _(SystemOrigin::Signed(caller), class, witness)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Destroyed(class).into());
|
||||
}
|
||||
|
||||
mint {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let instance = Default::default();
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instance, caller_lookup)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Issued(class, instance, caller).into());
|
||||
}
|
||||
|
||||
burn {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instance, Some(caller_lookup))
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Burned(class, instance, caller).into());
|
||||
}
|
||||
|
||||
transfer {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(Default::default());
|
||||
|
||||
let target: T::AccountId = account("target", 0, SEED);
|
||||
let target_lookup = T::Lookup::unlookup(target.clone());
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instance, target_lookup)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Transferred(class, instance, caller, target).into());
|
||||
}
|
||||
|
||||
redeposit {
|
||||
let i in 0 .. 5_000;
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let instances = (0..i).map(|x| mint_instance::<T, I>(x as u16).0).collect::<Vec<_>>();
|
||||
Uniques::<T, I>::force_asset_status(
|
||||
SystemOrigin::Root.into(),
|
||||
class,
|
||||
caller_lookup.clone(),
|
||||
caller_lookup.clone(),
|
||||
caller_lookup.clone(),
|
||||
caller_lookup.clone(),
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instances.clone())
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Redeposited(class, instances).into());
|
||||
}
|
||||
|
||||
freeze {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(Default::default());
|
||||
}: _(SystemOrigin::Signed(caller.clone()), Default::default(), Default::default())
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Frozen(Default::default(), Default::default()).into());
|
||||
}
|
||||
|
||||
thaw {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(Default::default());
|
||||
Uniques::<T, I>::freeze(
|
||||
SystemOrigin::Signed(caller.clone()).into(),
|
||||
class,
|
||||
instance,
|
||||
)?;
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instance)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::Thawed(class, instance).into());
|
||||
}
|
||||
|
||||
freeze_class {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ClassFrozen(class).into());
|
||||
}
|
||||
|
||||
thaw_class {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let origin = SystemOrigin::Signed(caller.clone()).into();
|
||||
Uniques::<T, I>::freeze_class(origin, class)?;
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ClassThawed(class).into());
|
||||
}
|
||||
|
||||
transfer_ownership {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let target: T::AccountId = account("target", 0, SEED);
|
||||
let target_lookup = T::Lookup::unlookup(target.clone());
|
||||
T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance());
|
||||
}: _(SystemOrigin::Signed(caller), class, target_lookup)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::OwnerChanged(class, target).into());
|
||||
}
|
||||
|
||||
set_team {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let target0 = T::Lookup::unlookup(account("target", 0, SEED));
|
||||
let target1 = T::Lookup::unlookup(account("target", 1, SEED));
|
||||
let target2 = T::Lookup::unlookup(account("target", 2, SEED));
|
||||
}: _(SystemOrigin::Signed(caller), Default::default(), target0.clone(), target1.clone(), target2.clone())
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::TeamChanged(
|
||||
class,
|
||||
account("target", 0, SEED),
|
||||
account("target", 1, SEED),
|
||||
account("target", 2, SEED),
|
||||
).into());
|
||||
}
|
||||
|
||||
force_asset_status {
|
||||
let (class, caller, caller_lookup) = create_class::<T, I>();
|
||||
let origin = T::ForceOrigin::successful_origin();
|
||||
let call = Call::<T, I>::force_asset_status(
|
||||
class,
|
||||
caller_lookup.clone(),
|
||||
caller_lookup.clone(),
|
||||
caller_lookup.clone(),
|
||||
caller_lookup.clone(),
|
||||
true,
|
||||
false,
|
||||
);
|
||||
}: { call.dispatch_bypass_filter(origin)? }
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::AssetStatusChanged(class).into());
|
||||
}
|
||||
|
||||
set_attribute {
|
||||
let key: BoundedVec<_, _> = vec![0u8; T::KeyLimit::get() as usize].try_into().unwrap();
|
||||
let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap();
|
||||
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
add_instance_metadata::<T, I>(instance);
|
||||
}: _(SystemOrigin::Signed(caller), class, Some(instance), key.clone(), value.clone())
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::AttributeSet(class, Some(instance), key, value).into());
|
||||
}
|
||||
|
||||
clear_attribute {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
add_instance_metadata::<T, I>(instance);
|
||||
let (key, ..) = add_instance_attribute::<T, I>(instance);
|
||||
}: _(SystemOrigin::Signed(caller), class, Some(instance), key.clone())
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::AttributeCleared(class, Some(instance), key).into());
|
||||
}
|
||||
|
||||
set_metadata {
|
||||
let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap();
|
||||
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
}: _(SystemOrigin::Signed(caller), class, instance, data.clone(), false)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::MetadataSet(class, instance, data, false).into());
|
||||
}
|
||||
|
||||
clear_metadata {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
add_instance_metadata::<T, I>(instance);
|
||||
}: _(SystemOrigin::Signed(caller), class, instance)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::MetadataCleared(class, instance).into());
|
||||
}
|
||||
|
||||
set_class_metadata {
|
||||
let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap();
|
||||
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
}: _(SystemOrigin::Signed(caller), class, data.clone(), false)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ClassMetadataSet(class, data, false).into());
|
||||
}
|
||||
|
||||
clear_class_metadata {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
add_class_metadata::<T, I>();
|
||||
}: _(SystemOrigin::Signed(caller), class)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ClassMetadataCleared(class).into());
|
||||
}
|
||||
|
||||
approve_transfer {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
let delegate: T::AccountId = account("delegate", 0, SEED);
|
||||
let delegate_lookup = T::Lookup::unlookup(delegate.clone());
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instance, delegate_lookup)
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ApprovedTransfer(class, instance, caller, delegate).into());
|
||||
}
|
||||
|
||||
cancel_approval {
|
||||
let (class, caller, _) = create_class::<T, I>();
|
||||
let (instance, ..) = mint_instance::<T, I>(0);
|
||||
let delegate: T::AccountId = account("delegate", 0, SEED);
|
||||
let delegate_lookup = T::Lookup::unlookup(delegate.clone());
|
||||
let origin = SystemOrigin::Signed(caller.clone()).into();
|
||||
Uniques::<T, I>::approve_transfer(origin, class, instance, delegate_lookup.clone())?;
|
||||
}: _(SystemOrigin::Signed(caller.clone()), class, instance, Some(delegate_lookup))
|
||||
verify {
|
||||
assert_last_event::<T, I>(Event::ApprovalCancelled(class, instance, caller, delegate).into());
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Uniques, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Test environment for Assets pallet.
|
||||
|
||||
use super::*;
|
||||
use crate as pallet_uniques;
|
||||
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::Header};
|
||||
use frame_support::{parameter_types, construct_runtime};
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Test where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>},
|
||||
}
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = u64;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = Event;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type DbWeight = ();
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pallet_balances::AccountData<u64>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ExistentialDeposit: u64 = 1;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for Test {
|
||||
type Balance = u64;
|
||||
type DustRemoval = ();
|
||||
type Event = Event;
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type MaxLocks = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ClassDeposit: u64 = 2;
|
||||
pub const InstanceDeposit: u64 = 1;
|
||||
pub const KeyLimit: u32 = 50;
|
||||
pub const ValueLimit: u32 = 50;
|
||||
pub const StringLimit: u32 = 50;
|
||||
pub const MetadataDepositBase: u64 = 1;
|
||||
pub const AttributeDepositBase: u64 = 1;
|
||||
pub const MetadataDepositPerByte: u64 = 1;
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type Event = Event;
|
||||
type ClassId = u32;
|
||||
type InstanceId = u32;
|
||||
type Currency = Balances;
|
||||
type ForceOrigin = frame_system::EnsureRoot<u64>;
|
||||
type ClassDeposit = ClassDeposit;
|
||||
type InstanceDeposit = InstanceDeposit;
|
||||
type MetadataDepositBase = MetadataDepositBase;
|
||||
type AttributeDepositBase = AttributeDepositBase;
|
||||
type DepositPerByte = MetadataDepositPerByte;
|
||||
type StringLimit = StringLimit;
|
||||
type KeyLimit = KeyLimit;
|
||||
type ValueLimit = ValueLimit;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
||||
|
||||
let mut ext = sp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| System::set_block_number(1));
|
||||
ext
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Tests for Uniques pallet.
|
||||
|
||||
use super::*;
|
||||
use crate::mock::*;
|
||||
use sp_std::convert::TryInto;
|
||||
use frame_support::{assert_ok, assert_noop, traits::Currency};
|
||||
use pallet_balances::Error as BalancesError;
|
||||
|
||||
fn assets() -> Vec<(u64, u32, u32)> {
|
||||
let mut r: Vec<_> = Account::<Test>::iter().map(|x| x.0).collect();
|
||||
r.sort();
|
||||
let mut s: Vec<_> = Asset::<Test>::iter().map(|x| (x.2.owner, x.0, x.1)).collect();
|
||||
s.sort();
|
||||
assert_eq!(r, s);
|
||||
for class in Asset::<Test>::iter()
|
||||
.map(|x| x.0)
|
||||
.scan(None, |s, item| if s.map_or(false, |last| last == item) {
|
||||
*s = Some(item);
|
||||
Some(None)
|
||||
} else {
|
||||
Some(Some(item))
|
||||
}
|
||||
).filter_map(|item| item)
|
||||
{
|
||||
let details = Class::<Test>::get(class).unwrap();
|
||||
let instances = Asset::<Test>::iter_prefix(class).count() as u32;
|
||||
assert_eq!(details.instances, instances);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
macro_rules! bvec {
|
||||
($( $x:tt )*) => {
|
||||
vec![$( $x )*].try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn attributes(class: u32) -> Vec<(Option<u32>, Vec<u8>, Vec<u8>)> {
|
||||
let mut s: Vec<_> = Attribute::<Test>::iter_prefix((class,))
|
||||
.map(|(k, v)| (k.0, k.1.into(), v.0.into()))
|
||||
.collect();
|
||||
s.sort();
|
||||
s
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_setup_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(assets(), vec![]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_minting_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_eq!(assets(), vec![(1, 0, 42)]);
|
||||
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1));
|
||||
assert_eq!(assets(), vec![(1, 0, 42), (1, 1, 69)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lifecycle_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
assert_ok!(Uniques::create(Origin::signed(1), 0, 1));
|
||||
assert_eq!(Balances::reserved_balance(&1), 2);
|
||||
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0, 0], false));
|
||||
assert_eq!(Balances::reserved_balance(&1), 5);
|
||||
assert!(ClassMetadataOf::<Test>::contains_key(0));
|
||||
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 10));
|
||||
assert_eq!(Balances::reserved_balance(&1), 6);
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 20));
|
||||
assert_eq!(Balances::reserved_balance(&1), 7);
|
||||
assert_eq!(assets(), vec![(10, 0, 42), (20, 0, 69)]);
|
||||
assert_eq!(Class::<Test>::get(0).unwrap().instances, 2);
|
||||
assert_eq!(Class::<Test>::get(0).unwrap().instance_metadatas, 0);
|
||||
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![42, 42], false));
|
||||
assert_eq!(Balances::reserved_balance(&1), 10);
|
||||
assert!(InstanceMetadataOf::<Test>::contains_key(0, 42));
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![69, 69], false));
|
||||
assert_eq!(Balances::reserved_balance(&1), 13);
|
||||
assert!(InstanceMetadataOf::<Test>::contains_key(0, 69));
|
||||
|
||||
let w = Class::<Test>::get(0).unwrap().destroy_witness();
|
||||
assert_eq!(w.instances, 2);
|
||||
assert_eq!(w.instance_metadatas, 2);
|
||||
assert_ok!(Uniques::destroy(Origin::signed(1), 0, w));
|
||||
assert_eq!(Balances::reserved_balance(&1), 0);
|
||||
|
||||
assert!(!Class::<Test>::contains_key(0));
|
||||
assert!(!Asset::<Test>::contains_key(0, 42));
|
||||
assert!(!Asset::<Test>::contains_key(0, 69));
|
||||
assert!(!ClassMetadataOf::<Test>::contains_key(0));
|
||||
assert!(!InstanceMetadataOf::<Test>::contains_key(0, 42));
|
||||
assert!(!InstanceMetadataOf::<Test>::contains_key(0, 69));
|
||||
assert_eq!(assets(), vec![]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destroy_with_bad_witness_should_not_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
assert_ok!(Uniques::create(Origin::signed(1), 0, 1));
|
||||
|
||||
let w = Class::<Test>::get(0).unwrap().destroy_witness();
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_noop!(Uniques::destroy(Origin::signed(1), 0, w), Error::<Test>::BadWitness);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mint_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_eq!(Uniques::owner(0, 42).unwrap(), 1);
|
||||
assert_eq!(assets(), vec![(1, 0, 42)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2));
|
||||
|
||||
assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 3));
|
||||
assert_eq!(assets(), vec![(3, 0, 42)]);
|
||||
assert_noop!(Uniques::transfer(Origin::signed(2), 0, 42, 4), Error::<Test>::NoPermission);
|
||||
|
||||
assert_ok!(Uniques::approve_transfer(Origin::signed(3), 0, 42, 2));
|
||||
assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 4));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn freezing_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_ok!(Uniques::freeze(Origin::signed(1), 0, 42));
|
||||
assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::<Test>::Frozen);
|
||||
|
||||
assert_ok!(Uniques::thaw(Origin::signed(1), 0, 42));
|
||||
assert_ok!(Uniques::freeze_class(Origin::signed(1), 0));
|
||||
assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::<Test>::Frozen);
|
||||
|
||||
assert_ok!(Uniques::thaw_class(Origin::signed(1), 0));
|
||||
assert_ok!(Uniques::transfer(Origin::signed(1), 0, 42, 2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn origin_guards_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_noop!(Uniques::transfer_ownership(Origin::signed(2), 0, 2), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::set_team(Origin::signed(2), 0, 2, 2, 2), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::freeze(Origin::signed(2), 0, 42), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::thaw(Origin::signed(2), 0, 42), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::mint(Origin::signed(2), 0, 69, 2), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::burn(Origin::signed(2), 0, 42, None), Error::<Test>::NoPermission);
|
||||
let w = Class::<Test>::get(0).unwrap().destroy_witness();
|
||||
assert_noop!(Uniques::destroy(Origin::signed(2), 0, w), Error::<Test>::NoPermission);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_owner_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
Balances::make_free_balance_be(&2, 100);
|
||||
Balances::make_free_balance_be(&3, 100);
|
||||
assert_ok!(Uniques::create(Origin::signed(1), 0, 1));
|
||||
assert_ok!(Uniques::transfer_ownership(Origin::signed(1), 0, 2));
|
||||
assert_eq!(Balances::total_balance(&1), 98);
|
||||
assert_eq!(Balances::total_balance(&2), 102);
|
||||
assert_eq!(Balances::reserved_balance(&1), 0);
|
||||
assert_eq!(Balances::reserved_balance(&2), 2);
|
||||
|
||||
assert_noop!(Uniques::transfer_ownership(Origin::signed(1), 0, 1), Error::<Test>::NoPermission);
|
||||
|
||||
// Mint and set metadata now and make sure that deposit gets transferred back.
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(2), 0, bvec![0u8; 20], false));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false));
|
||||
assert_ok!(Uniques::transfer_ownership(Origin::signed(2), 0, 3));
|
||||
assert_eq!(Balances::total_balance(&2), 57);
|
||||
assert_eq!(Balances::total_balance(&3), 145);
|
||||
assert_eq!(Balances::reserved_balance(&2), 0);
|
||||
assert_eq!(Balances::reserved_balance(&3), 45);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_team_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4));
|
||||
|
||||
assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 2));
|
||||
assert_ok!(Uniques::freeze(Origin::signed(4), 0, 42));
|
||||
assert_ok!(Uniques::thaw(Origin::signed(3), 0, 42));
|
||||
assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 3));
|
||||
assert_ok!(Uniques::burn(Origin::signed(3), 0, 42, None));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_class_metadata_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Cannot add metadata to unknown asset
|
||||
assert_noop!(
|
||||
Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 20], false),
|
||||
Error::<Test>::Unknown,
|
||||
);
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false));
|
||||
// Cannot add metadata to unowned asset
|
||||
assert_noop!(
|
||||
Uniques::set_class_metadata(Origin::signed(2), 0, bvec![0u8; 20], false),
|
||||
Error::<Test>::NoPermission,
|
||||
);
|
||||
|
||||
// Successfully add metadata and take deposit
|
||||
Balances::make_free_balance_be(&1, 30);
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 20], false));
|
||||
assert_eq!(Balances::free_balance(&1), 9);
|
||||
assert!(ClassMetadataOf::<Test>::contains_key(0));
|
||||
|
||||
// Force origin works, too.
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::root(), 0, bvec![0u8; 18], false));
|
||||
|
||||
// Update deposit
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 15], false));
|
||||
assert_eq!(Balances::free_balance(&1), 14);
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 25], false));
|
||||
assert_eq!(Balances::free_balance(&1), 4);
|
||||
|
||||
// Cannot over-reserve
|
||||
assert_noop!(
|
||||
Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 40], false),
|
||||
BalancesError::<Test, _>::InsufficientBalance,
|
||||
);
|
||||
|
||||
// Can't set or clear metadata once frozen
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 15], true));
|
||||
assert_noop!(
|
||||
Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0u8; 15], false),
|
||||
Error::<Test, _>::Frozen,
|
||||
);
|
||||
assert_noop!(Uniques::clear_class_metadata(Origin::signed(1), 0), Error::<Test>::Frozen);
|
||||
|
||||
// Clear Metadata
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::root(), 0, bvec![0u8; 15], false));
|
||||
assert_noop!(Uniques::clear_class_metadata(Origin::signed(2), 0), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::clear_class_metadata(Origin::signed(1), 1), Error::<Test>::Unknown);
|
||||
assert_ok!(Uniques::clear_class_metadata(Origin::signed(1), 0));
|
||||
assert!(!ClassMetadataOf::<Test>::contains_key(0));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_instance_metadata_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 30);
|
||||
|
||||
// Cannot add metadata to unknown asset
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
// Cannot add metadata to unowned asset
|
||||
assert_noop!(
|
||||
Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false),
|
||||
Error::<Test>::NoPermission,
|
||||
);
|
||||
|
||||
// Successfully add metadata and take deposit
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 20], false));
|
||||
assert_eq!(Balances::free_balance(&1), 8);
|
||||
assert!(InstanceMetadataOf::<Test>::contains_key(0, 42));
|
||||
|
||||
// Force origin works, too.
|
||||
assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 18], false));
|
||||
|
||||
// Update deposit
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], false));
|
||||
assert_eq!(Balances::free_balance(&1), 13);
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 25], false));
|
||||
assert_eq!(Balances::free_balance(&1), 3);
|
||||
|
||||
// Cannot over-reserve
|
||||
assert_noop!(
|
||||
Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 40], false),
|
||||
BalancesError::<Test, _>::InsufficientBalance,
|
||||
);
|
||||
|
||||
// Can't set or clear metadata once frozen
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], true));
|
||||
assert_noop!(
|
||||
Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], false),
|
||||
Error::<Test, _>::Frozen,
|
||||
);
|
||||
assert_noop!(Uniques::clear_metadata(Origin::signed(1), 0, 42), Error::<Test>::Frozen);
|
||||
|
||||
// Clear Metadata
|
||||
assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 15], false));
|
||||
assert_noop!(Uniques::clear_metadata(Origin::signed(2), 0, 42), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::clear_metadata(Origin::signed(1), 1, 42), Error::<Test>::Unknown);
|
||||
assert_ok!(Uniques::clear_metadata(Origin::signed(1), 0, 42));
|
||||
assert!(!InstanceMetadataOf::<Test>::contains_key(0, 42));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_attribute_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false));
|
||||
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0]));
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0]));
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![1], bvec![0]));
|
||||
assert_eq!(attributes(0), vec![
|
||||
(None, bvec![0], bvec![0]),
|
||||
(Some(0), bvec![0], bvec![0]),
|
||||
(Some(0), bvec![1], bvec![0]),
|
||||
]);
|
||||
assert_eq!(Balances::reserved_balance(1), 9);
|
||||
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0; 10]));
|
||||
assert_eq!(attributes(0), vec![
|
||||
(None, bvec![0], bvec![0; 10]),
|
||||
(Some(0), bvec![0], bvec![0]),
|
||||
(Some(0), bvec![1], bvec![0]),
|
||||
]);
|
||||
assert_eq!(Balances::reserved_balance(1), 18);
|
||||
|
||||
assert_ok!(Uniques::clear_attribute(Origin::signed(1), 0, Some(0), bvec![1]));
|
||||
assert_eq!(attributes(0), vec![
|
||||
(None, bvec![0], bvec![0; 10]),
|
||||
(Some(0), bvec![0], bvec![0]),
|
||||
]);
|
||||
assert_eq!(Balances::reserved_balance(1), 15);
|
||||
|
||||
let w = Class::<Test>::get(0).unwrap().destroy_witness();
|
||||
assert_ok!(Uniques::destroy(Origin::signed(1), 0, w));
|
||||
assert_eq!(attributes(0), vec![]);
|
||||
assert_eq!(Balances::reserved_balance(1), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_attribute_should_respect_freeze() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false));
|
||||
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0]));
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0]));
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(1), bvec![0], bvec![0]));
|
||||
assert_eq!(attributes(0), vec![
|
||||
(None, bvec![0], bvec![0]),
|
||||
(Some(0), bvec![0], bvec![0]),
|
||||
(Some(1), bvec![0], bvec![0]),
|
||||
]);
|
||||
assert_eq!(Balances::reserved_balance(1), 9);
|
||||
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![], true));
|
||||
let e = Error::<Test>::Frozen;
|
||||
assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0]), e);
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1]));
|
||||
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 0, bvec![], true));
|
||||
let e = Error::<Test>::Frozen;
|
||||
assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1]), e);
|
||||
assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(1), bvec![0], bvec![1]));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn force_asset_status_should_work(){
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 2));
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0; 20], false));
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false));
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false));
|
||||
assert_eq!(Balances::reserved_balance(1), 65);
|
||||
|
||||
//force asset status to be free holding
|
||||
assert_ok!(Uniques::force_asset_status(Origin::root(), 0, 1, 1, 1, 1, true, false));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 142, 1));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 169, 2));
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 142, bvec![0; 20], false));
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 169, bvec![0; 20], false));
|
||||
assert_eq!(Balances::reserved_balance(1), 65);
|
||||
|
||||
assert_ok!(Uniques::redeposit(Origin::signed(1), 0, bvec![0, 42, 50, 69, 100]));
|
||||
assert_eq!(Balances::reserved_balance(1), 63);
|
||||
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false));
|
||||
assert_eq!(Balances::reserved_balance(1), 42);
|
||||
|
||||
assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false));
|
||||
assert_eq!(Balances::reserved_balance(1), 21);
|
||||
|
||||
assert_ok!(Uniques::set_class_metadata(Origin::signed(1), 0, bvec![0; 20], false));
|
||||
assert_eq!(Balances::reserved_balance(1), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn burn_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&1, 100);
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false));
|
||||
assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4));
|
||||
|
||||
assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(5)), Error::<Test>::Unknown);
|
||||
|
||||
assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 5));
|
||||
assert_ok!(Uniques::mint(Origin::signed(2), 0, 69, 5));
|
||||
assert_eq!(Balances::reserved_balance(1), 2);
|
||||
|
||||
assert_noop!(Uniques::burn(Origin::signed(0), 0, 42, None), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(6)), Error::<Test>::WrongOwner);
|
||||
|
||||
assert_ok!(Uniques::burn(Origin::signed(5), 0, 42, Some(5)));
|
||||
assert_ok!(Uniques::burn(Origin::signed(3), 0, 69, Some(5)));
|
||||
assert_eq!(Balances::reserved_balance(1), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn approval_lifecycle_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2));
|
||||
assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3));
|
||||
assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 4));
|
||||
assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 3), Error::<Test>::NoPermission);
|
||||
assert!(Asset::<Test>::get(0, 42).unwrap().approved.is_none());
|
||||
|
||||
assert_ok!(Uniques::approve_transfer(Origin::signed(4), 0, 42, 2));
|
||||
assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_approval_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2));
|
||||
|
||||
assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3));
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(2), 1, 42, None), Error::<Test>::Unknown);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(2), 0, 43, None), Error::<Test>::Unknown);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(3), 0, 42, None), Error::<Test>::NoPermission);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(2), 0, 42, Some(4)), Error::<Test>::WrongDelegate);
|
||||
|
||||
assert_ok!(Uniques::cancel_approval(Origin::signed(2), 0, 42, Some(3)));
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(2), 0, 42, None), Error::<Test>::NoDelegate);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_approval_works_with_admin() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2));
|
||||
|
||||
assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3));
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(1), 1, 42, None), Error::<Test>::Unknown);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(1), 0, 43, None), Error::<Test>::Unknown);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(4)), Error::<Test>::WrongDelegate);
|
||||
|
||||
assert_ok!(Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(3)));
|
||||
assert_noop!(Uniques::cancel_approval(Origin::signed(1), 0, 42, None), Error::<Test>::NoDelegate);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_approval_works_with_force() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true));
|
||||
assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2));
|
||||
|
||||
assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3));
|
||||
assert_noop!(Uniques::cancel_approval(Origin::root(), 1, 42, None), Error::<Test>::Unknown);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::root(), 0, 43, None), Error::<Test>::Unknown);
|
||||
assert_noop!(Uniques::cancel_approval(Origin::root(), 0, 42, Some(4)), Error::<Test>::WrongDelegate);
|
||||
|
||||
assert_ok!(Uniques::cancel_approval(Origin::root(), 0, 42, Some(3)));
|
||||
assert_noop!(Uniques::cancel_approval(Origin::root(), 0, 42, None), Error::<Test>::NoDelegate);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Various basic types for use in the assets pallet.
|
||||
|
||||
use super::*;
|
||||
use frame_support::{traits::Get, BoundedVec};
|
||||
|
||||
pub(super) type DepositBalanceOf<T, I = ()> =
|
||||
<<T as Config<I>>::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance;
|
||||
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)]
|
||||
pub struct ClassDetails<
|
||||
AccountId,
|
||||
DepositBalance,
|
||||
> {
|
||||
/// Can change `owner`, `issuer`, `freezer` and `admin` accounts.
|
||||
pub(super) owner: AccountId,
|
||||
/// Can mint tokens.
|
||||
pub(super) issuer: AccountId,
|
||||
/// Can thaw tokens, force transfers and burn tokens from any account.
|
||||
pub(super) admin: AccountId,
|
||||
/// Can freeze tokens.
|
||||
pub(super) freezer: AccountId,
|
||||
/// The total balance deposited for the all storage associated with this asset class. Used by
|
||||
/// `destroy`.
|
||||
pub(super) total_deposit: DepositBalance,
|
||||
/// If `true`, then no deposit is needed to hold instances of this class.
|
||||
pub(super) free_holding: bool,
|
||||
/// The total number of outstanding instances of this asset class.
|
||||
pub(super) instances: u32,
|
||||
/// The total number of outstanding instance metadata of this asset class.
|
||||
pub(super) instance_metadatas: u32,
|
||||
/// The total number of attributes for this asset class.
|
||||
pub(super) attributes: u32,
|
||||
/// Whether the asset is frozen for non-admin transfers.
|
||||
pub(super) is_frozen: bool,
|
||||
}
|
||||
|
||||
/// Witness data for the destroy transactions.
|
||||
#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)]
|
||||
pub struct DestroyWitness {
|
||||
/// The total number of outstanding instances of this asset class.
|
||||
#[codec(compact)]
|
||||
pub(super) instances: u32,
|
||||
/// The total number of outstanding instance metadata of this asset class.
|
||||
#[codec(compact)]
|
||||
pub(super) instance_metadatas: u32,
|
||||
#[codec(compact)]
|
||||
/// The total number of attributes for this asset class.
|
||||
pub(super) attributes: u32,
|
||||
}
|
||||
|
||||
impl<AccountId, DepositBalance> ClassDetails<AccountId, DepositBalance> {
|
||||
pub fn destroy_witness(&self) -> DestroyWitness {
|
||||
DestroyWitness {
|
||||
instances: self.instances,
|
||||
instance_metadatas: self.instance_metadatas,
|
||||
attributes: self.attributes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information concerning the ownership of a single unique asset.
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)]
|
||||
pub struct InstanceDetails<AccountId, DepositBalance> {
|
||||
/// The owner of this asset.
|
||||
pub(super) owner: AccountId,
|
||||
/// The approved transferrer of this asset, if one is set.
|
||||
pub(super) approved: Option<AccountId>,
|
||||
/// Whether the asset can be transferred or not.
|
||||
pub(super) is_frozen: bool,
|
||||
/// The amount held in the pallet's default account for this asset. Free-hold assets will have
|
||||
/// this as zero.
|
||||
pub(super) deposit: DepositBalance,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)]
|
||||
pub struct ClassMetadata<DepositBalance, StringLimit: Get<u32>> {
|
||||
/// The balance deposited for this metadata.
|
||||
///
|
||||
/// This pays for the data stored in this struct.
|
||||
pub(super) deposit: DepositBalance,
|
||||
/// General information concerning this asset. Limited in length by `StringLimit`. This will
|
||||
/// generally be either a JSON dump or the hash of some JSON which can be found on a
|
||||
/// hash-addressable global publication system such as IPFS.
|
||||
pub(super) data: BoundedVec<u8, StringLimit>,
|
||||
/// Whether the asset metadata may be changed by a non Force origin.
|
||||
pub(super) is_frozen: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)]
|
||||
pub struct InstanceMetadata<DepositBalance, StringLimit: Get<u32>> {
|
||||
/// The balance deposited for this metadata.
|
||||
///
|
||||
/// This pays for the data stored in this struct.
|
||||
pub(super) deposit: DepositBalance,
|
||||
/// General information concerning this asset. Limited in length by `StringLimit`. This will
|
||||
/// generally be either a JSON dump or the hash of some JSON which can be found on a
|
||||
/// hash-addressable global publication system such as IPFS.
|
||||
pub(super) data: BoundedVec<u8, StringLimit>,
|
||||
/// Whether the asset metadata may be changed by a non Force origin.
|
||||
pub(super) is_frozen: bool,
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Autogenerated weights for pallet_uniques
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
|
||||
//! DATE: 2021-05-24, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
// target/release/substrate
|
||||
// benchmark
|
||||
// --chain=dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=pallet_uniques
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./frame/uniques/src/weights.rs
|
||||
// --template=./.maintain/frame-weight-template.hbs
|
||||
|
||||
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_uniques.
|
||||
pub trait WeightInfo {
|
||||
fn create() -> Weight;
|
||||
fn force_create() -> Weight;
|
||||
fn destroy(n: u32, m: u32, a: u32, ) -> Weight;
|
||||
fn mint() -> Weight;
|
||||
fn burn() -> Weight;
|
||||
fn transfer() -> Weight;
|
||||
fn redeposit(i: u32, ) -> Weight;
|
||||
fn freeze() -> Weight;
|
||||
fn thaw() -> Weight;
|
||||
fn freeze_class() -> Weight;
|
||||
fn thaw_class() -> Weight;
|
||||
fn transfer_ownership() -> Weight;
|
||||
fn set_team() -> Weight;
|
||||
fn force_asset_status() -> Weight;
|
||||
fn set_attribute() -> Weight;
|
||||
fn clear_attribute() -> Weight;
|
||||
fn set_metadata() -> Weight;
|
||||
fn clear_metadata() -> Weight;
|
||||
fn set_class_metadata() -> Weight;
|
||||
fn clear_class_metadata() -> Weight;
|
||||
fn approve_transfer() -> Weight;
|
||||
fn cancel_approval() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for pallet_uniques using the Substrate node and recommended hardware.
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
fn create() -> Weight {
|
||||
(55_264_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_create() -> Weight {
|
||||
(28_173_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn destroy(n: u32, m: u32, a: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((23_077_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((1_723_000 as Weight).saturating_mul(m as Weight))
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((1_534_000 as Weight).saturating_mul(a as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(m as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(a as Weight)))
|
||||
}
|
||||
fn mint() -> Weight {
|
||||
(73_250_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn burn() -> Weight {
|
||||
(74_443_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn transfer() -> Weight {
|
||||
(54_690_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn redeposit(i: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 19_000
|
||||
.saturating_add((34_624_000 as Weight).saturating_mul(i as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
|
||||
}
|
||||
fn freeze() -> Weight {
|
||||
(39_505_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn thaw() -> Weight {
|
||||
(38_844_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn freeze_class() -> Weight {
|
||||
(28_739_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn thaw_class() -> Weight {
|
||||
(28_963_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn transfer_ownership() -> Weight {
|
||||
(65_160_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_team() -> Weight {
|
||||
(30_000_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_asset_status() -> Weight {
|
||||
(29_145_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn set_attribute() -> Weight {
|
||||
(88_923_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn clear_attribute() -> Weight {
|
||||
(79_878_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_metadata() -> Weight {
|
||||
(67_110_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn clear_metadata() -> Weight {
|
||||
(66_191_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_class_metadata() -> Weight {
|
||||
(65_558_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn clear_class_metadata() -> Weight {
|
||||
(60_135_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn approve_transfer() -> Weight {
|
||||
(40_337_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn cancel_approval() -> Weight {
|
||||
(40_770_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn create() -> Weight {
|
||||
(55_264_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_create() -> Weight {
|
||||
(28_173_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn destroy(n: u32, m: u32, a: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((23_077_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((1_723_000 as Weight).saturating_mul(m as Weight))
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((1_534_000 as Weight).saturating_mul(a as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(m as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(a as Weight)))
|
||||
}
|
||||
fn mint() -> Weight {
|
||||
(73_250_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn burn() -> Weight {
|
||||
(74_443_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn transfer() -> Weight {
|
||||
(54_690_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn redeposit(i: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 19_000
|
||||
.saturating_add((34_624_000 as Weight).saturating_mul(i as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(i as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(i as Weight)))
|
||||
}
|
||||
fn freeze() -> Weight {
|
||||
(39_505_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn thaw() -> Weight {
|
||||
(38_844_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn freeze_class() -> Weight {
|
||||
(28_739_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn thaw_class() -> Weight {
|
||||
(28_963_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn transfer_ownership() -> Weight {
|
||||
(65_160_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_team() -> Weight {
|
||||
(30_000_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_asset_status() -> Weight {
|
||||
(29_145_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn set_attribute() -> Weight {
|
||||
(88_923_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn clear_attribute() -> Weight {
|
||||
(79_878_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_metadata() -> Weight {
|
||||
(67_110_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn clear_metadata() -> Weight {
|
||||
(66_191_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_class_metadata() -> Weight {
|
||||
(65_558_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn clear_class_metadata() -> Weight {
|
||||
(60_135_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn approve_transfer() -> Weight {
|
||||
(40_337_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn cancel_approval() -> Weight {
|
||||
(40_770_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user