Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose collection attributes from Inspect trait #1914

Merged
merged 14 commits into from
Oct 26, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -1081,10 +1081,10 @@ impl_runtime_apis! {

fn system_attribute(
collection: u32,
item: u32,
item: Option<u32>,
key: Vec<u8>,
) -> Option<Vec<u8>> {
<Nfts as Inspect<AccountId>>::system_attribute(&collection, &item, &key)
<Nfts as Inspect<AccountId>>::system_attribute(&collection, item.as_ref(), &key)
}

fn collection_attribute(collection: u32, key: Vec<u8>) -> Option<Vec<u8>> {
Expand Down
4 changes: 2 additions & 2 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2630,10 +2630,10 @@ impl_runtime_apis! {

fn system_attribute(
collection: u32,
item: u32,
item: Option<u32>,
key: Vec<u8>,
) -> Option<Vec<u8>> {
<Nfts as Inspect<AccountId>>::system_attribute(&collection, &item, &key)
<Nfts as Inspect<AccountId>>::system_attribute(&collection, item.as_ref(), &key)
}

fn collection_attribute(collection: u32, key: Vec<u8>) -> Option<Vec<u8>> {
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/nfts/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ sp_api::decl_runtime_apis! {

fn system_attribute(
collection: CollectionId,
item: ItemId,
item: Option<ItemId>,
key: Vec<u8>,
) -> Option<Vec<u8>>;

Expand Down
8 changes: 5 additions & 3 deletions substrate/frame/nfts/src/impl_nonfungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,19 @@ impl<T: Config<I>, I: 'static> Inspect<<T as SystemConfig>::AccountId> for Palle
Attribute::<T, I>::get((collection, Some(item), namespace, key)).map(|a| a.0.into())
}

/// Returns the system attribute value of `item` of `collection` corresponding to `key`.
/// Returns the system attribute value of `item` of `collection` corresponding to `key` if
/// `item` is `Some`. Otherwise, returns the system attribute value of `collection`
/// corresponding to `key`.
///
/// By default this is `None`; no attributes are defined.
fn system_attribute(
collection: &Self::CollectionId,
item: &Self::ItemId,
item: Option<&Self::ItemId>,
key: &[u8],
) -> Option<Vec<u8>> {
let namespace = AttributeNamespace::Pallet;
let key = BoundedSlice::<_, _>::try_from(key).ok()?;
Attribute::<T, I>::get((collection, Some(item), namespace, key)).map(|a| a.0.into())
Attribute::<T, I>::get((collection, item, namespace, key)).map(|a| a.0.into())
}

/// Returns the attribute value of `item` of `collection` corresponding to `key`.
Expand Down
82 changes: 81 additions & 1 deletion substrate/frame/nfts/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use enumflags2::BitFlags;
use frame_support::{
assert_noop, assert_ok,
traits::{
tokens::nonfungibles_v2::{Create, Destroy, Mutate},
tokens::nonfungibles_v2::{Create, Destroy, Inspect, Mutate},
Currency, Get,
},
};
Expand Down Expand Up @@ -982,6 +982,86 @@ fn set_collection_owner_attributes_should_work() {
});
}

#[test]
fn set_collection_system_attributes_should_work() {
new_test_ext().execute_with(|| {
Balances::make_free_balance_be(&account(1), 100);

assert_ok!(Nfts::force_create(
RuntimeOrigin::root(),
account(1),
collection_config_with_all_settings_enabled()
));
assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None));

let collection_id = 0;
let attribute_key = [0u8];
let attribute_value = [0u8];

assert_ok!(<Nfts as Mutate<AccountIdOf<Test>, ItemConfig>>::set_collection_attribute(
&collection_id,
&attribute_key,
&attribute_value
));

assert_eq!(attributes(0), vec![(None, AttributeNamespace::Pallet, bvec![0], bvec![0])]);

assert_eq!(
<Nfts as Inspect<AccountIdOf<Test>>>::system_attribute(
&collection_id,
None,
&attribute_key
),
Some(attribute_value.to_vec())
);

// test typed system attribute
let typed_attribute_key = [0u8; 32];
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
struct TypedAttributeValue(u32);
let typed_attribute_value = TypedAttributeValue(42);

assert_ok!(
<Nfts as Mutate<AccountIdOf<Test>, ItemConfig>>::set_typed_collection_attribute(
&collection_id,
&typed_attribute_key,
&typed_attribute_value
)
);

assert_eq!(
<Nfts as Inspect<AccountIdOf<Test>>>::typed_system_attribute(
&collection_id,
None,
&typed_attribute_key
),
Some(typed_attribute_value)
);

// check storage
assert_eq!(
attributes(collection_id),
[
(None, AttributeNamespace::Pallet, bvec![0], bvec![0]),
(
None,
AttributeNamespace::Pallet,
bvec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0
],
bvec![42, 0, 0, 0]
)
]
);

assert_ok!(Nfts::burn(RuntimeOrigin::root(), collection_id, 0));
let w = Nfts::get_destroy_witness(&0).unwrap();
assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), collection_id, w));
assert_eq!(attributes(collection_id), vec![]);
})
}

#[test]
fn set_item_owner_attributes_should_work() {
new_test_ext().execute_with(|| {
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/support/src/traits/tokens/nonfungible_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ impl<
<F as nonfungibles::Inspect<AccountId>>::custom_attribute(account, &A::get(), item, key)
}
fn system_attribute(item: &Self::ItemId, key: &[u8]) -> Option<Vec<u8>> {
<F as nonfungibles::Inspect<AccountId>>::system_attribute(&A::get(), item, key)
<F as nonfungibles::Inspect<AccountId>>::system_attribute(&A::get(), Some(item), 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)
Expand All @@ -244,7 +244,7 @@ impl<
)
}
fn typed_system_attribute<K: Encode, V: Decode>(item: &Self::ItemId, key: &K) -> Option<V> {
<F as nonfungibles::Inspect<AccountId>>::typed_system_attribute(&A::get(), item, key)
<F as nonfungibles::Inspect<AccountId>>::typed_system_attribute(&A::get(), Some(item), key)
}
fn can_transfer(item: &Self::ItemId) -> bool {
<F as nonfungibles::Inspect<AccountId>>::can_transfer(&A::get(), item)
Expand Down
13 changes: 8 additions & 5 deletions substrate/frame/support/src/traits/tokens/nonfungibles_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,14 @@ pub trait Inspect<AccountId> {
None
}

/// Returns the system attribute value of `item` of `collection` corresponding to `key`.
/// Returns the system attribute value of `item` of `collection` corresponding to `key` if
/// `item` is `Some`. Otherwise, returns the system attribute value of `collection`
/// corresponding to `key`.
///
/// By default this is `None`; no attributes are defined.
fn system_attribute(
_collection: &Self::CollectionId,
_item: &Self::ItemId,
_item: Option<&Self::ItemId>,
_key: &[u8],
) -> Option<Vec<u8>> {
None
Expand Down Expand Up @@ -113,13 +115,14 @@ pub trait Inspect<AccountId> {
.and_then(|v| V::decode(&mut &v[..]).ok())
}

/// Returns the strongly-typed system attribute value of `item` of `collection` corresponding to
/// `key`.
/// Returns the strongly-typed system attribute value of `item` corresponding to `key` if
/// `item` is `Some`. Otherwise, returns the strongly-typed system attribute value of
/// `collection` corresponding to `key`.
///
/// By default this just attempts to use `system_attribute`.
fn typed_system_attribute<K: Encode, V: Decode>(
collection: &Self::CollectionId,
item: &Self::ItemId,
item: Option<&Self::ItemId>,
key: &K,
) -> Option<V> {
key.using_encoded(|d| Self::system_attribute(collection, item, d))
Expand Down