Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,12 +1414,12 @@ parameter_types! {

impl pallet_uniques::Config for Runtime {
type Event = Event;
type ClassId = u32;
type InstanceId = u32;
type CollectionId = u32;
type ItemId = u32;
type Currency = Balances;
type ForceOrigin = frame_system::EnsureRoot<AccountId>;
type ClassDeposit = ClassDeposit;
type InstanceDeposit = InstanceDeposit;
type CollectionDeposit = ClassDeposit;
type ItemDeposit = InstanceDeposit;
type MetadataDepositBase = MetadataDepositBase;
type AttributeDepositBase = MetadataDepositBase;
type DepositPerByte = MetadataDepositPerByte;
Expand Down
8 changes: 4 additions & 4 deletions frame/support/src/traits/tokens/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,16 @@ pub trait BalanceConversion<InBalance, AssetId, OutBalance> {

/// Trait to handle asset locking mechanism to ensure interactions with the asset can be implemented
/// downstream to extend logic of Uniques current functionality.
pub trait Locker<ClassId, InstanceId> {
pub trait Locker<CollectionId, ItemId> {
/// Check if the asset should be locked and prevent interactions with the asset from executing.
fn is_locked(class: ClassId, instance: InstanceId) -> bool;
fn is_locked(collection: CollectionId, item: ItemId) -> bool;
}

impl<ClassId, InstanceId> Locker<ClassId, InstanceId> for () {
impl<CollectionId, ItemId> Locker<CollectionId, ItemId> for () {
// Default will be false if not implemented downstream.
// Note: The logic check in this function must be constant time and consistent for benchmarks
// to work.
fn is_locked(_class: ClassId, _instance: InstanceId) -> bool {
fn is_locked(_collection: CollectionId, _item: ItemId) -> bool {
false
}
}
125 changes: 61 additions & 64 deletions frame/support/src/traits/tokens/nonfungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Traits for dealing with a single non-fungible asset class.
//! Traits for dealing with a single non-fungible collection of items.
//!
//! This assumes a single level namespace identified by `Inspect::InstanceId`, and could
//! This assumes a single level namespace identified by `Inspect::ItemId`, and could
//! reasonably be implemented by pallets which wants to expose a single collection of NFT-like
//! objects.
//!
Expand All @@ -30,167 +30,164 @@ use codec::{Decode, Encode};
use sp_runtime::TokenError;
use sp_std::prelude::*;

/// Trait for providing an interface to a read-only NFT-like set of asset instances.
/// Trait for providing an interface to a read-only NFT-like set of items.
pub trait Inspect<AccountId> {
/// Type for identifying an asset instance.
type InstanceId;
/// Type for identifying an item.
type ItemId;

/// Returns the owner of asset `instance`, or `None` if the asset doesn't exist or has no
/// Returns the owner of `item`, or `None` if the item doesn't exist or has no
/// owner.
fn owner(instance: &Self::InstanceId) -> Option<AccountId>;
fn owner(item: &Self::ItemId) -> Option<AccountId>;

/// Returns the attribute value of `instance` corresponding to `key`.
/// Returns the attribute value of `item` corresponding to `key`.
///
/// By default this is `None`; no attributes are defined.
fn attribute(_instance: &Self::InstanceId, _key: &[u8]) -> Option<Vec<u8>> {
fn attribute(_item: &Self::ItemId, _key: &[u8]) -> Option<Vec<u8>> {
None
}

/// Returns the strongly-typed attribute value of `instance` corresponding to `key`.
/// Returns the strongly-typed attribute value of `item` corresponding to `key`.
///
/// By default this just attempts to use `attribute`.
fn typed_attribute<K: Encode, V: Decode>(instance: &Self::InstanceId, key: &K) -> Option<V> {
key.using_encoded(|d| Self::attribute(instance, d))
fn typed_attribute<K: Encode, V: Decode>(item: &Self::ItemId, key: &K) -> Option<V> {
key.using_encoded(|d| Self::attribute(item, d))
.and_then(|v| V::decode(&mut &v[..]).ok())
}

/// Returns `true` if the asset `instance` may be transferred.
/// Returns `true` if the `item` may be transferred.
///
/// Default implementation is that all assets are transferable.
fn can_transfer(_instance: &Self::InstanceId) -> bool {
/// Default implementation is that all items are transferable.
fn can_transfer(_item: &Self::ItemId) -> bool {
true
}
}

/// Interface for enumerating assets in existence or owned by a given account over a collection
/// Interface for enumerating items in existence or owned by a given account over a collection
/// of NFTs.
pub trait InspectEnumerable<AccountId>: Inspect<AccountId> {
/// Returns an iterator of the instances of an asset `class` in existence.
fn instances() -> Box<dyn Iterator<Item = Self::InstanceId>>;
/// Returns an iterator of the items within a `collection` in existence.
fn items() -> Box<dyn Iterator<Item = Self::ItemId>>;

/// Returns an iterator of the asset instances of all classes owned by `who`.
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = Self::InstanceId>>;
/// Returns an iterator of the items of all collections owned by `who`.
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = Self::ItemId>>;
}

/// Trait for providing an interface for NFT-like assets which may be minted, burned and/or have
/// Trait for providing an interface for NFT-like items which may be minted, burned and/or have
/// attributes set on them.
pub trait Mutate<AccountId>: Inspect<AccountId> {
/// Mint some asset `instance` to be owned by `who`.
/// Mint some `item` to be owned by `who`.
///
/// By default, this is not a supported operation.
fn mint_into(_instance: &Self::InstanceId, _who: &AccountId) -> DispatchResult {
fn mint_into(_item: &Self::ItemId, _who: &AccountId) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Burn some asset `instance`.
/// Burn some `item`.
///
/// By default, this is not a supported operation.
fn burn(
_instance: &Self::InstanceId,
_maybe_check_owner: Option<&AccountId>,
) -> DispatchResult {
fn burn(_item: &Self::ItemId, _maybe_check_owner: Option<&AccountId>) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Set attribute `value` of asset `instance`'s `key`.
/// Set attribute `value` of `item`'s `key`.
///
/// By default, this is not a supported operation.
fn set_attribute(_instance: &Self::InstanceId, _key: &[u8], _value: &[u8]) -> DispatchResult {
fn set_attribute(_item: &Self::ItemId, _key: &[u8], _value: &[u8]) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Attempt to set the strongly-typed attribute `value` of `instance`'s `key`.
/// Attempt to set the strongly-typed attribute `value` of `item`'s `key`.
///
/// By default this just attempts to use `set_attribute`.
fn set_typed_attribute<K: Encode, V: Encode>(
instance: &Self::InstanceId,
item: &Self::ItemId,
key: &K,
value: &V,
) -> DispatchResult {
key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(instance, k, v)))
key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(item, k, v)))
}
}

/// Trait for providing a non-fungible set of assets which can only be transferred.
/// Trait for providing a non-fungible set of items which can only be transferred.
pub trait Transfer<AccountId>: Inspect<AccountId> {
/// Transfer asset `instance` into `destination` account.
fn transfer(instance: &Self::InstanceId, destination: &AccountId) -> DispatchResult;
/// Transfer `item` into `destination` account.
fn transfer(item: &Self::ItemId, destination: &AccountId) -> DispatchResult;
}

/// Convert a `fungibles` trait implementation into a `fungible` trait implementation by identifying
/// a single item.
pub struct ItemOf<
F: nonfungibles::Inspect<AccountId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::ClassId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::CollectionId>,
AccountId,
>(sp_std::marker::PhantomData<(F, A, AccountId)>);

impl<
F: nonfungibles::Inspect<AccountId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::ClassId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::CollectionId>,
AccountId,
> Inspect<AccountId> for ItemOf<F, A, AccountId>
{
type InstanceId = <F as nonfungibles::Inspect<AccountId>>::InstanceId;
fn owner(instance: &Self::InstanceId) -> Option<AccountId> {
<F as nonfungibles::Inspect<AccountId>>::owner(&A::get(), instance)
type ItemId = <F as nonfungibles::Inspect<AccountId>>::ItemId;
fn owner(item: &Self::ItemId) -> Option<AccountId> {
<F as nonfungibles::Inspect<AccountId>>::owner(&A::get(), item)
}
fn attribute(instance: &Self::InstanceId, key: &[u8]) -> Option<Vec<u8>> {
<F as nonfungibles::Inspect<AccountId>>::attribute(&A::get(), instance, key)
fn attribute(item: &Self::ItemId, key: &[u8]) -> Option<Vec<u8>> {
<F as nonfungibles::Inspect<AccountId>>::attribute(&A::get(), item, key)
}
fn typed_attribute<K: Encode, V: Decode>(instance: &Self::InstanceId, key: &K) -> Option<V> {
<F as nonfungibles::Inspect<AccountId>>::typed_attribute(&A::get(), instance, key)
fn typed_attribute<K: Encode, V: Decode>(item: &Self::ItemId, key: &K) -> Option<V> {
<F as nonfungibles::Inspect<AccountId>>::typed_attribute(&A::get(), item, key)
}
fn can_transfer(instance: &Self::InstanceId) -> bool {
<F as nonfungibles::Inspect<AccountId>>::can_transfer(&A::get(), instance)
fn can_transfer(item: &Self::ItemId) -> bool {
<F as nonfungibles::Inspect<AccountId>>::can_transfer(&A::get(), item)
}
}

impl<
F: nonfungibles::InspectEnumerable<AccountId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::ClassId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::CollectionId>,
AccountId,
> InspectEnumerable<AccountId> for ItemOf<F, A, AccountId>
{
fn instances() -> Box<dyn Iterator<Item = Self::InstanceId>> {
<F as nonfungibles::InspectEnumerable<AccountId>>::instances(&A::get())
fn items() -> Box<dyn Iterator<Item = Self::ItemId>> {
<F as nonfungibles::InspectEnumerable<AccountId>>::items(&A::get())
}
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = Self::InstanceId>> {
<F as nonfungibles::InspectEnumerable<AccountId>>::owned_in_class(&A::get(), who)
fn owned(who: &AccountId) -> Box<dyn Iterator<Item = Self::ItemId>> {
<F as nonfungibles::InspectEnumerable<AccountId>>::owned_in_collection(&A::get(), who)
}
}

impl<
F: nonfungibles::Mutate<AccountId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::ClassId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::CollectionId>,
AccountId,
> Mutate<AccountId> for ItemOf<F, A, AccountId>
{
fn mint_into(instance: &Self::InstanceId, who: &AccountId) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::mint_into(&A::get(), instance, who)
fn mint_into(item: &Self::ItemId, who: &AccountId) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::mint_into(&A::get(), item, who)
}
fn burn(instance: &Self::InstanceId, maybe_check_owner: Option<&AccountId>) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::burn(&A::get(), instance, maybe_check_owner)
fn burn(item: &Self::ItemId, maybe_check_owner: Option<&AccountId>) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::burn(&A::get(), item, maybe_check_owner)
}
fn set_attribute(instance: &Self::InstanceId, key: &[u8], value: &[u8]) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::set_attribute(&A::get(), instance, key, value)
fn set_attribute(item: &Self::ItemId, key: &[u8], value: &[u8]) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::set_attribute(&A::get(), item, key, value)
}
fn set_typed_attribute<K: Encode, V: Encode>(
instance: &Self::InstanceId,
item: &Self::ItemId,
key: &K,
value: &V,
) -> DispatchResult {
<F as nonfungibles::Mutate<AccountId>>::set_typed_attribute(&A::get(), instance, key, value)
<F as nonfungibles::Mutate<AccountId>>::set_typed_attribute(&A::get(), item, key, value)
}
}

impl<
F: nonfungibles::Transfer<AccountId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::ClassId>,
A: Get<<F as nonfungibles::Inspect<AccountId>>::CollectionId>,
AccountId,
> Transfer<AccountId> for ItemOf<F, A, AccountId>
{
fn transfer(instance: &Self::InstanceId, destination: &AccountId) -> DispatchResult {
<F as nonfungibles::Transfer<AccountId>>::transfer(&A::get(), instance, destination)
fn transfer(item: &Self::ItemId, destination: &AccountId) -> DispatchResult {
<F as nonfungibles::Transfer<AccountId>>::transfer(&A::get(), item, destination)
}
}
Loading