frame_support/traits/tokens/asset_ops.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Abstract asset operations traits.
19//!
20//! The following operations are defined:
21//! * [`Inspect`]
22//! * [`Update`]
23//! * [`Create`]
24//! * [`Destroy`]
25//! * [`Stash`]
26//! * [`Restore`]
27//!
28//! Also, all the operations above (except the `Create` operation) use
29//! the [`AssetDefinition`] to retrieve the `Id` type of the asset.
30//!
31//! An asset operation can be implemented multiple times
32//! using different strategies associated with this operation.
33//!
34//! A strategy defines the operation behavior,
35//! may supply additional parameters,
36//! and may define a return value type of the operation.
37//!
38//! ### Usage Example
39//!
40//! This example shows how to interact with pallet-uniques (assuming the pallet called Uniques in
41//! the chain’s Runtime) via the asset ops.
42//!
43//! If you are interested in the implementation example, you can look at the pallet-uniques
44//! implementation. You can check out the pallet-uniques tests if you want more examples of usage.
45//!
46//! ```rust,ignore
47//! type Collection = pallet_uniques::asset_ops::Collection<Uniques>;
48//! type Item = pallet_uniques::asset_ops::Item<Uniques>;
49//!
50//! // Collection creation
51//! //
52//! // Note the `Owner` and `Admin` are inspect strategies.
53//! //
54//! // **Any** inspect strategy can be used to produce a config value
55//! // using the `WithConfig` creation strategy.
56//! Collection::create(WithConfig::new(
57//! (
58//! Owner::with_config_value(collection_owner),
59//! Admin::with_config_value(collection_admin)
60//! ),
61//! PredefinedId::from(collection_id),
62//! )).unwrap();
63//!
64//! // Get the collection owner
65//! let owner = Collection::inspect(&collection_id, Owner::default()).unwrap();
66//!
67//! // Get the collection admin
68//! let admin = Collection::inspect(&collection_id, Admin::default()).unwrap();
69//!
70//! // Get collection metadata
71//! let metadata = Collection::inspect(&collection_id, Bytes::default()).unwrap();
72//!
73//! // Get collection attribute
74//! use pallet_uniques::asset_strategies::Attribute;
75//! let attr_key = "example-key";
76//! let attr_value = Collection::inspect(
77//! &collection_id,
78//! Bytes(Attribute(attr_key.as_slice())),
79//! ).unwrap();
80//!
81//! // Item creation (note the usage of the same strategy -- WithConfig)
82//! Item::create(WithConfig::new(
83//! Owner::with_config_value(item_owner),
84//! PredefinedId::from(item_id),
85//! )).unwrap();
86//!
87//! // Get the item owner
88//! let item_owner = Item::inspect(&(collection_id, item_id), Owner::default()).unwrap();
89//!
90//! // Get item attribute
91//! let attr_key = "example-key";
92//! let attr_value = Item::inspect(
93//! &(collection_id, item_id),
94//! Bytes(Attribute(attr_key.as_slice())),
95//! ).unwrap();
96//!
97//! // Unconditionally update the item's owner (unchecked transfer)
98//! Item::update(&(collection_id, item_id), Owner::default(), &bob).unwrap();
99//!
100//! // CheckOrigin then transfer
101//! Item::update(
102//! &(collection_id, item_id),
103//! CheckOrigin(RuntimeOrigin::root(), Owner::default()),
104//! &bob,
105//! ).unwrap();
106//!
107//! // From-To transfer
108//! Item::update(
109//! &(collection_id, item_id),
110//! ChangeOwnerFrom::check(alice),
111//! &bob,
112//! ).unwrap();
113//!
114//! // Lock item (forbid changing its Owner)
115//! //
116//! // Note that Owner strategy is turned into the `CanUpdate<Owner>` strategy
117//! // via the `as_can_update` function.
118//! //
119//! // **Any** update strategy can be turned into the `CanUpdate` this way.
120//! Item::update(
121//! &(collection_id, item_id),
122//! Owner::default().as_can_update(),
123//! false,
124//! );
125//! ```
126
127use core::marker::PhantomData;
128use sp_runtime::DispatchError;
129use sp_std::vec::Vec;
130
131pub mod common_strategies;
132
133/// Trait for defining an asset.
134/// The definition must provide the `Id` type to identify the asset.
135pub trait AssetDefinition {
136 /// Type for identifying the asset.
137 type Id;
138}
139
140/// Get the `Id` type of the asset definition.
141pub type AssetIdOf<T> = <T as AssetDefinition>::Id;
142
143/// A strategy for use in the [`Inspect`] implementations.
144///
145/// The common inspect strategies are:
146/// * [`Bytes`](common_strategies::Bytes)
147/// * [`Owner`](common_strategies::Owner)
148/// * [`CanCreate`](common_strategies::CanCreate)
149/// * [`CanDestroy`](common_strategies::CanDestroy)
150/// * [`CanUpdate`](common_strategies::CanUpdate)
151pub trait InspectStrategy {
152 /// The value representing the asset's state related to this `InspectStrategy`.
153 type Value;
154}
155
156/// A trait representing the ability of a certain asset to **provide** its state
157/// information.
158///
159/// This trait can be implemented multiple times using different
160/// [`inspect strategies`](InspectStrategy).
161///
162/// An inspect strategy defines how the asset state is identified/retrieved
163/// and what [`Value`](InspectStrategy::Value) type is returned.
164pub trait Inspect<Strategy: InspectStrategy>: AssetDefinition {
165 /// Inspect state information of the asset
166 /// using the given `id` and the inspect `strategy`.
167 ///
168 /// The ID type is retrieved from the [`AssetDefinition`].
169 fn inspect(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Value, DispatchError>;
170}
171
172/// A strategy for use in the [`Update`] implementations.
173///
174/// The common update strategies are:
175/// * [`Bytes`](common_strategies::Bytes)
176/// * [`CanCreate`](common_strategies::CanCreate)
177/// * [`CanDestroy`](common_strategies::CanDestroy)
178/// * [`CanUpdate`](common_strategies::CanUpdate)
179pub trait UpdateStrategy {
180 /// The value to update the asset's state.
181 /// Usually, it should be related to the corresponding `InspectStrategy::Value`.
182 ///
183 /// For instance:
184 /// * If the `Value` is `Vec<u8>`, the `UpdateValue` can be `Option<&'a [u8]>` (e.g., asset
185 /// attributes that can be modified or deleted).
186 /// * If the `Value` is `bool`, the `UpdateValue` can also be `bool`.
187 type UpdateValue<'a>;
188
189 /// This type represents a successful asset state update.
190 /// It will be in the [`Result`] type of the [`Update::update`] function.
191 type Success;
192}
193
194/// A trait representing the ability of a certain asset to **update** its state information.
195///
196/// This trait can be implemented multiple times using different
197/// [`update strategies`](UpdateStrategy).
198///
199/// An update strategy defines how the asset state is identified
200/// and what [`UpdateValue`](UpdateStrategy::UpdateValue) type is used.
201pub trait Update<Strategy: UpdateStrategy>: AssetDefinition {
202 /// Update the state information of the asset
203 /// using the given `id`, the update `strategy`, and the strategy's `update_value`.
204 ///
205 /// The ID type is retrieved from the [`AssetDefinition`].
206 fn update(
207 id: &Self::Id,
208 strategy: Strategy,
209 update_value: Strategy::UpdateValue<'_>,
210 ) -> Result<Strategy::Success, DispatchError>;
211}
212
213/// A strategy for use in the [`Create`] implementations.
214///
215/// The common "create" strategy is [`WithConfig`](common_strategies::WithConfig).
216pub trait CreateStrategy {
217 /// This type represents a successful asset creation.
218 /// It will be in the [`Result`] type of the [`Create::create`] function.
219 type Success;
220}
221
222/// An ID assignment approach to use in the "create" strategies.
223///
224/// The common ID assignments are:
225/// * [`AutoId`](common_strategies::AutoId)
226/// * [`PredefinedId`](common_strategies::PredefinedId)
227/// * [`DeriveAndReportId`](common_strategies::DeriveAndReportId)
228pub trait IdAssignment {
229 /// The reported ID type.
230 ///
231 /// Examples:
232 /// * [`AutoId`](common_strategies::AutoId) returns the ID of the newly created asset
233 /// * [`PredefinedId`](common_strategies::PredefinedId) accepts the ID to be assigned to the
234 /// newly created asset
235 /// * [`DeriveAndReportId`](common_strategies::DeriveAndReportId) returns the ID derived from
236 /// the input parameters
237 type ReportedId;
238}
239
240/// A trait representing the ability of a certain asset to be created.
241///
242/// This trait can be implemented multiple times using different
243/// [`"create" strategies`](CreateStrategy).
244///
245/// A create strategy defines all aspects of asset creation including how an asset ID is assigned.
246pub trait Create<Strategy: CreateStrategy> {
247 /// Create a new asset using the provided `strategy`.
248 fn create(strategy: Strategy) -> Result<Strategy::Success, DispatchError>;
249}
250
251/// A strategy for use in the [`Destroy`] implementations.
252///
253/// The common destroy strategies are:
254/// * [`NoParams`](common_strategies::NoParams)
255/// * [`IfOwnedBy`](common_strategies::IfOwnedBy)
256/// * [`WithWitness`](common_strategies::WithWitness)
257pub trait DestroyStrategy {
258 /// This type represents a successful asset destruction.
259 /// It will be in the [`Result`] type of the [`Destroy::destroy`] function.
260 type Success;
261}
262
263/// A trait representing the ability of a certain asset to be destroyed.
264///
265/// This trait can be implemented multiple times using different
266/// [`destroy strategies`](DestroyStrategy).
267///
268/// A destroy strategy defines destroy parameters and the result value type.
269pub trait Destroy<Strategy: DestroyStrategy>: AssetDefinition {
270 /// Destroy the asset identified by the given `id` using the provided `strategy`.
271 ///
272 /// The ID type is retrieved from the [`AssetDefinition`].
273 fn destroy(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError>;
274}
275
276/// A strategy for use in the [`Stash`] implementations.
277///
278/// The common stash strategies are:
279/// * [`NoParams`](common_strategies::NoParams)
280/// * [`IfOwnedBy`](common_strategies::IfOwnedBy)
281pub trait StashStrategy {
282 /// This type represents a successful asset stashing.
283 /// It will be in the [`Result`] type of the [`Stash::stash`] function.
284 type Success;
285}
286
287/// A trait representing the ability of a certain asset to be stashed.
288///
289/// This trait can be implemented multiple times using different
290/// [`stash strategies`](StashStrategy).
291///
292/// A stash strategy defines stash parameters.
293pub trait Stash<Strategy: StashStrategy>: AssetDefinition {
294 /// Stash the asset identified by the given `id` using the provided `strategy`.
295 ///
296 /// The ID type is retrieved from the [`AssetDefinition`].
297 fn stash(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError>;
298}
299
300/// A strategy for use in the [`Restore`] implementations.
301/// The common restore strategies are:
302/// * [`NoParams`](common_strategies::NoParams)
303/// * [`WithConfig`](common_strategies::WithConfig)
304pub trait RestoreStrategy {
305 /// This type represents a successful asset restoration.
306 /// It will be in the [`Result`] type of the [`Restore::restore`] function.
307 type Success;
308}
309
310/// A trait representing the ability of a certain asset to be restored.
311///
312/// This trait can be implemented multiple times using different
313/// [`restore strategies`](RestoreStrategy).
314///
315/// A restore strategy defines restore parameters.
316pub trait Restore<Strategy: RestoreStrategy>: AssetDefinition {
317 /// Restore the asset identified by the given `id` using the provided `strategy`.
318 ///
319 /// The ID type is retrieved from the [`AssetDefinition`].
320 fn restore(id: &Self::Id, strategy: Strategy) -> Result<Strategy::Success, DispatchError>;
321}