Skip to content
67 changes: 67 additions & 0 deletions substrate/frame/nfts/src/impl_nonfungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,33 @@ impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId, ItemConfig
})
}

fn set_metadata(
who: &T::AccountId,
collection: &Self::CollectionId,
item: &Self::ItemId,
data: &[u8],
) -> DispatchResult {
Self::do_set_item_metadata(
Some(who.clone()),
*collection,
*item,
Self::construct_metadata(data.to_vec())?,
None,
)
}

fn set_collection_metadata(
who: &T::AccountId,
collection: &Self::CollectionId,
data: &[u8],
) -> DispatchResult {
Self::do_set_collection_metadata(
Some(who.clone()),
*collection,
Self::construct_metadata(data.to_vec())?,
)
}

fn clear_attribute(
collection: &Self::CollectionId,
item: &Self::ItemId,
Expand Down Expand Up @@ -362,6 +389,21 @@ impl<T: Config<I>, I: 'static> Mutate<<T as SystemConfig>::AccountId, ItemConfig
<Self as Mutate<T::AccountId, ItemConfig>>::clear_collection_attribute(collection, k)
})
}

fn clear_metadata(
who: &T::AccountId,
collection: &Self::CollectionId,
item: &Self::ItemId,
) -> DispatchResult {
Self::do_clear_item_metadata(Some(who.clone()), *collection, *item)
}

fn clear_collection_metadata(
who: &T::AccountId,
collection: &Self::CollectionId,
) -> DispatchResult {
Self::do_clear_collection_metadata(Some(who.clone()), *collection)
}
}

impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> {
Expand Down Expand Up @@ -398,6 +440,31 @@ impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> {
}
}

impl<T: Config<I>, I: 'static> Trading<T::AccountId, ItemPrice<T, I>> for Pallet<T, I> {
fn buy_item(
collection: &Self::CollectionId,
item: &Self::ItemId,
buyer: &T::AccountId,
bid_price: &ItemPrice<T, I>,
) -> DispatchResult {
Self::do_buy_item(*collection, *item, buyer.clone(), *bid_price)
}

fn set_price(
collection: &Self::CollectionId,
item: &Self::ItemId,
sender: &T::AccountId,
price: Option<ItemPrice<T, I>>,
whitelisted_buyer: Option<T::AccountId>,
) -> DispatchResult {
Self::do_set_price(*collection, *item, sender.clone(), price, whitelisted_buyer)
}

fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option<ItemPrice<T, I>> {
ItemPriceOf::<T, I>::get(collection, item).map(|a| a.0)
}
}

impl<T: Config<I>, I: 'static> InspectEnumerable<T::AccountId> for Pallet<T, I> {
type CollectionsIterator = KeyPrefixIterator<<T as Config<I>>::CollectionId>;
type ItemsIterator = KeyPrefixIterator<<T as Config<I>>::ItemId>;
Expand Down
3 changes: 2 additions & 1 deletion substrate/frame/support/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ pub use tokens::{
},
fungible, fungibles,
imbalance::{Imbalance, OnUnbalanced, SignedImbalance},
nonfungible, nonfungibles, BalanceStatus, ExistenceRequirement, Locker, WithdrawReasons,
nonfungible, nonfungible_v2, nonfungibles, nonfungibles_v2, BalanceStatus,
ExistenceRequirement, Locker, WithdrawReasons,
};

mod members;
Expand Down
16 changes: 15 additions & 1 deletion substrate/frame/support/src/traits/tokens/nonfungible_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub trait InspectEnumerable<AccountId>: Inspect<AccountId> {
}

/// Trait for providing an interface for NFT-like items which may be minted, burned and/or have
/// attributes set on them.
/// attributes and metadata set on them.
pub trait Mutate<AccountId, ItemConfig>: Inspect<AccountId> {
/// Mint some `item` to be owned by `who`.
///
Expand Down Expand Up @@ -158,6 +158,13 @@ pub trait Mutate<AccountId, ItemConfig>: Inspect<AccountId> {
key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(item, k, v)))
}

/// Set the metadata `data` of an `item`.
///
/// By default, this is not a supported operation.
fn set_metadata(_who: &AccountId, _item: &Self::ItemId, _data: &[u8]) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Clear attribute of `item`'s `key`.
///
/// By default, this is not a supported operation.
Expand All @@ -171,6 +178,13 @@ pub trait Mutate<AccountId, ItemConfig>: Inspect<AccountId> {
fn clear_typed_attribute<K: Encode>(item: &Self::ItemId, key: &K) -> DispatchResult {
key.using_encoded(|k| Self::clear_attribute(item, k))
}

/// Clear the metadata of an `item`.
///
/// By default, this is not a supported operation.
fn clear_metadata(_who: &AccountId, _item: &Self::ItemId) -> DispatchResult {
Err(TokenError::Unsupported.into())
}
}

/// Trait for transferring and controlling the transfer of non-fungible sets of items.
Expand Down
70 changes: 69 additions & 1 deletion substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ pub trait Destroy<AccountId>: Inspect<AccountId> {
}

/// Trait for providing an interface for multiple collections of NFT-like items which may be
/// minted, burned and/or have attributes set on them.
/// minted, burned and/or have attributes and metadata set on them.
pub trait Mutate<AccountId, ItemConfig>: Inspect<AccountId> {
/// Mint some `item` of `collection` to be owned by `who`.
///
Expand Down Expand Up @@ -307,6 +307,29 @@ pub trait Mutate<AccountId, ItemConfig>: Inspect<AccountId> {
})
}

/// Set the metadata `data` of an `item` of `collection`.
///
/// By default, this is not a supported operation.
fn set_metadata(
_who: &AccountId,
_collection: &Self::CollectionId,
_item: &Self::ItemId,
_data: &[u8],
) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Set the metadata `data` of a `collection`.
///
/// By default, this is not a supported operation.
fn set_collection_metadata(
_who: &AccountId,
_collection: &Self::CollectionId,
_data: &[u8],
) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Clear attribute of `item` of `collection`'s `key`.
///
/// By default, this is not a supported operation.
Expand Down Expand Up @@ -345,6 +368,27 @@ pub trait Mutate<AccountId, ItemConfig>: Inspect<AccountId> {
) -> DispatchResult {
key.using_encoded(|k| Self::clear_collection_attribute(collection, k))
}

/// Clear the metadata of an `item` of `collection`.
///
/// By default, this is not a supported operation.
fn clear_metadata(
_who: &AccountId,
_collection: &Self::CollectionId,
_item: &Self::ItemId,
) -> DispatchResult {
Err(TokenError::Unsupported.into())
}

/// Clear the metadata of a `collection`.
///
/// By default, this is not a supported operation.
fn clear_collection_metadata(
_who: &AccountId,
_collection: &Self::CollectionId,
) -> DispatchResult {
Err(TokenError::Unsupported.into())
}
}

/// Trait for transferring non-fungible sets of items.
Expand All @@ -370,3 +414,27 @@ pub trait Transfer<AccountId>: Inspect<AccountId> {
Err(TokenError::Unsupported.into())
}
}

/// Trait for trading non-fungible items.
pub trait Trading<AccountId, ItemPrice>: Inspect<AccountId> {
/// Allows `buyer` to buy an `item` of `collection` if it's up for sale with a `bid_price` to
/// pay.
fn buy_item(
collection: &Self::CollectionId,
item: &Self::ItemId,
buyer: &AccountId,
bid_price: &ItemPrice,
) -> DispatchResult;

/// Set the item price of `item` of `collection` to make it available for sale
fn set_price(
collection: &Self::CollectionId,
item: &Self::ItemId,
sender: &AccountId,
price: Option<ItemPrice>,
whitelisted_buyer: Option<AccountId>,
) -> DispatchResult;

/// Returns the item price of `item` of `collection`, or `None` if the item is not for sale
fn item_price(collection: &Self::CollectionId, item: &Self::ItemId) -> Option<ItemPrice>;
}