difftreelog
refactor Remove variable data from tokens
in: master
23 files changed
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -71,13 +71,6 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Vec<u8>>;
- #[rpc(name = "unique_variableMetadata")]
- fn variable_metadata(
- &self,
- collection: CollectionId,
- token: TokenId,
- at: Option<BlockHash>,
- ) -> Result<Vec<u8>>;
#[rpc(name = "unique_collectionProperties")]
fn collection_properties(
@@ -279,7 +272,6 @@
);
pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);
pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);
- pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);
pass_method!(collection_properties(
collection: CollectionId,
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -33,7 +33,7 @@
MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId,
CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT,
FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT,
- CUSTOM_DATA_LIMIT, CollectionLimits, CustomDataLimit, CreateCollectionData, SponsorshipState,
+ CUSTOM_DATA_LIMIT, CollectionLimits, CreateCollectionData, SponsorshipState,
CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,
PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission,
PropertiesError, PropertyKeyPermission, TokenData, TrySet,
@@ -312,8 +312,6 @@
CollectionTokenPrefixLimitExceeded,
/// Total collections bound exceeded.
TotalCollectionsLimitExceeded,
- /// variable_data exceeded data limit.
- TokenVariableDataLimitExceeded,
/// Exceeded max admin count
CollectionAdminCountExceeded,
/// Collection limit bounds per collection exceeded
@@ -1073,7 +1071,6 @@
fn approve() -> Weight;
fn transfer_from() -> Weight;
fn burn_from() -> Weight;
- fn set_variable_metadata(bytes: u32) -> Weight;
}
pub trait CommonCollectionOperations<T: Config> {
@@ -1163,13 +1160,6 @@
nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo;
- fn set_variable_metadata(
- &self,
- sender: T::CrossAccountId,
- token: TokenId,
- data: BoundedVec<u8, CustomDataLimit>,
- ) -> DispatchResultWithPostInfo;
-
fn check_nesting(
&self,
sender: T::CrossAccountId,
@@ -1185,7 +1175,6 @@
fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;
fn const_metadata(&self, token: TokenId) -> Vec<u8>;
- fn variable_metadata(&self, token: TokenId) -> Vec<u8>;
fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property>;
/// Amount of unique collection tokens
fn total_supply(&self) -> u32;
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -16,12 +16,12 @@
use core::marker::PhantomData;
-use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec};
+use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget};
use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
use sp_runtime::ArithmeticError;
use sp_std::{vec::Vec, vec};
-use up_data_structs::{CustomDataLimit, Property, PropertyKey, PropertyKeyPermission};
+use up_data_structs::{Property, PropertyKey, PropertyKeyPermission};
use crate::{
Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,
@@ -85,11 +85,6 @@
fn burn_from() -> Weight {
<SelfWeightOf<T>>::burn_from()
}
-
- fn set_variable_metadata(_bytes: u32) -> Weight {
- // Error
- 0
- }
}
impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {
@@ -287,15 +282,6 @@
fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
- fn set_variable_metadata(
- &self,
- _sender: T::CrossAccountId,
- _token: TokenId,
- _data: BoundedVec<u8, CustomDataLimit>,
- ) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::FungibleItemsDontHaveData)
- }
-
fn check_nesting(
&self,
_sender: <T>::CrossAccountId,
@@ -330,9 +316,6 @@
None
}
fn const_metadata(&self, _token: TokenId) -> Vec<u8> {
- Vec::new()
- }
- fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {
Vec::new()
}
pallets/nonfungible/Cargo.tomldiffbeforeafterboth--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -27,6 +27,7 @@
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
+struct-versioning = { path = "../../crates/struct-versioning" }
[features]
default = ["std"]
pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -28,10 +28,8 @@
fn create_max_item_data<T: Config>(owner: T::CrossAccountId) -> CreateItemData<T> {
let const_data = create_data::<CUSTOM_DATA_LIMIT>();
- let variable_data = create_data::<CUSTOM_DATA_LIMIT>();
CreateItemData::<T> {
const_data,
- variable_data,
owner,
}
}
@@ -125,14 +123,4 @@
let item = create_max_item(&collection, &owner, sender.clone())?;
<Pallet<T>>::set_allowance(&collection, &sender, item, Some(&burner))?;
}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, &Unlimited)?}
-
- set_variable_metadata {
- let b in 0..CUSTOM_DATA_LIMIT;
- bench_init!{
- owner: sub; collection: collection(owner);
- owner: cross_from_sub; sender: cross_sub;
- };
- let item = create_max_item(&collection, &owner, sender.clone())?;
- let data = create_var_data(b).try_into().unwrap();
- }: {<Pallet<T>>::set_variable_metadata(&collection, &sender, item, data)?}
}
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -16,9 +16,9 @@
use core::marker::PhantomData;
-use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec};
+use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
use up_data_structs::{
- TokenId, CustomDataLimit, CreateItemExData, CollectionId, budget::Budget, Property,
+ TokenId, CreateItemExData, CollectionId, budget::Budget, Property,
PropertyKey, PropertyKeyPermission,
};
use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
@@ -85,10 +85,6 @@
fn burn_from() -> Weight {
<SelfWeightOf<T>>::burn_from()
- }
-
- fn set_variable_metadata(bytes: u32) -> Weight {
- <SelfWeightOf<T>>::set_variable_metadata(bytes)
}
}
@@ -99,7 +95,6 @@
match data {
up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {
const_data: data.const_data,
- variable_data: data.variable_data,
properties: data.properties,
owner: to.clone(),
}),
@@ -325,19 +320,6 @@
} else {
Ok(().into())
}
- }
-
- fn set_variable_metadata(
- &self,
- sender: T::CrossAccountId,
- token: TokenId,
- data: BoundedVec<u8, CustomDataLimit>,
- ) -> DispatchResultWithPostInfo {
- let len = data.len();
- with_weight(
- <Pallet<T>>::set_variable_metadata(self, &sender, token, data),
- <CommonWeights<T>>::set_variable_metadata(len as u32),
- )
}
fn check_nesting(
@@ -376,12 +358,6 @@
fn const_metadata(&self, token: TokenId) -> Vec<u8> {
<TokenData<T>>::get((self.id, token))
.map(|t| t.const_data)
- .unwrap_or_default()
- .into_inner()
- }
- fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
- <TokenData<T>>::get((self.id, token))
- .map(|t| t.variable_data)
.unwrap_or_default()
.into_inner()
}
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -24,7 +24,7 @@
use up_data_structs::{TokenId, SchemaVersion};
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_core::{H160, U256};
-use sp_std::{vec::Vec, vec};
+use sp_std::vec::Vec;
use pallet_common::{
erc::{CommonEvmHandler, PrecompileResult, CollectionPropertiesCall},
CollectionHandle,
@@ -274,7 +274,6 @@
&caller,
CreateItemData::<T> {
const_data: BoundedVec::default(),
- variable_data: BoundedVec::default(),
properties: BoundedVec::default(),
owner: to,
},
@@ -322,7 +321,6 @@
const_data: Vec::<u8>::from(token_uri)
.try_into()
.map_err(|_| "token uri is too long")?,
- variable_data: BoundedVec::default(),
properties: BoundedVec::default(),
owner: to,
},
@@ -387,37 +385,6 @@
.into())
}
- #[weight(<SelfWeightOf<T>>::set_variable_metadata(data.len() as u32))]
- fn set_variable_metadata(
- &mut self,
- caller: caller,
- token_id: uint256,
- data: bytes,
- ) -> Result<void> {
- let caller = T::CrossAccountId::from_eth(caller);
- let token = token_id.try_into()?;
-
- <Pallet<T>>::set_variable_metadata(
- self,
- &caller,
- token,
- data.try_into()
- .map_err(|_| "metadata size exceeded limit")?,
- )
- .map_err(dispatch_to_evm::<T>)?;
- Ok(())
- }
-
- fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {
- self.consume_store_reads(1)?;
- let token: TokenId = token_id.try_into()?;
-
- Ok(<TokenData<T>>::get((self.id, token))
- .ok_or("token not found")?
- .variable_data
- .into_inner())
- }
-
#[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
let caller = T::CrossAccountId::from_eth(caller);
@@ -440,7 +407,6 @@
let data = (0..total_tokens)
.map(|_| CreateItemData::<T> {
const_data: BoundedVec::default(),
- variable_data: BoundedVec::default(),
properties: BoundedVec::default(),
owner: to.clone(),
})
@@ -484,7 +450,6 @@
const_data: Vec::<u8>::from(token_uri)
.try_into()
.map_err(|_| "token uri is too long")?,
- variable_data: vec![].try_into().unwrap(),
properties: BoundedVec::default(),
owner: to.clone(),
});
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -49,17 +49,22 @@
pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
+#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct ItemData<CrossAccountId> {
pub const_data: BoundedVec<u8, CustomDataLimit>,
+
+ #[version(..2)]
pub variable_data: BoundedVec<u8, CustomDataLimit>,
+
pub owner: CrossAccountId,
}
#[frame_support::pallet]
pub mod pallet {
use super::*;
- use frame_support::{Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};
+ use frame_support::{Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};
+ use frame_system::pallet_prelude::*;
use up_data_structs::{CollectionId, TokenId};
use super::weights::WeightInfo;
@@ -78,7 +83,10 @@
type WeightInfo: WeightInfo;
}
+ const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
#[pallet::pallet]
+ #[pallet::storage_version(STORAGE_VERSION)]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
@@ -133,6 +141,19 @@
Value = T::CrossAccountId,
QueryKind = OptionQuery,
>;
+
+ #[pallet::hooks]
+ impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+ fn on_runtime_upgrade() -> Weight {
+ if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
+ <TokenData<T>>::translate_values::<ItemDataVersion1<T::CrossAccountId>, _>(|v| {
+ Some(<ItemDataVersion2<T::CrossAccountId>>::from(v))
+ })
+ }
+
+ 0
+ }
+ }
}
pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
@@ -577,7 +598,6 @@
(collection.id, token),
ItemData {
const_data: data.const_data,
- variable_data: data.variable_data,
owner: data.owner.clone(),
},
);
@@ -773,28 +793,6 @@
// =========
Self::burn(collection, from, token)
- }
-
- pub fn set_variable_metadata(
- collection: &NonfungibleHandle<T>,
- sender: &T::CrossAccountId,
- token: TokenId,
- data: BoundedVec<u8, CustomDataLimit>,
- ) -> DispatchResult {
- let token_data =
- <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
- collection.check_can_update_meta(sender, &token_data.owner)?;
-
- // =========
-
- <TokenData<T>>::insert(
- (collection.id, token),
- ItemData {
- variable_data: data,
- ..token_data
- },
- );
- Ok(())
}
pub fn check_nesting(
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -61,6 +61,24 @@
}
}
+// Selector: 56fd500b
+contract CollectionProperties is Dummy, ERC165 {
+ // Selector: setProperty(string,string) 62d9491f
+ function setProperty(string memory key, string memory value) public {
+ require(false, stub_error);
+ key;
+ value;
+ dummy = 0;
+ }
+
+ // Selector: deleteProperty(string) 34241914
+ function deleteProperty(string memory key) public {
+ require(false, stub_error);
+ key;
+ dummy = 0;
+ }
+}
+
// Selector: 58800161
contract ERC721 is Dummy, ERC165, ERC721Events {
// Selector: balanceOf(address) 70a08231
@@ -276,7 +294,7 @@
}
}
-// Selector: e562194d
+// Selector: d74d154f
contract ERC721UniqueExtensions is Dummy, ERC165 {
// Selector: transfer(address,uint256) a9059cbb
function transfer(address to, uint256 tokenId) public {
@@ -301,26 +319,6 @@
return 0;
}
- // Selector: setVariableMetadata(uint256,bytes) d4eac26d
- function setVariableMetadata(uint256 tokenId, bytes memory data) public {
- require(false, stub_error);
- tokenId;
- data;
- dummy = 0;
- }
-
- // Selector: getVariableMetadata(uint256) e6c5ce6f
- function getVariableMetadata(uint256 tokenId)
- public
- view
- returns (bytes memory)
- {
- require(false, stub_error);
- tokenId;
- dummy;
- return hex"";
- }
-
// Selector: mintBulk(address,uint256[]) 44a9945e
function mintBulk(address to, uint256[] memory tokenIds)
public
@@ -354,5 +352,6 @@
ERC721Enumerable,
ERC721UniqueExtensions,
ERC721Mintable,
- ERC721Burnable
+ ERC721Burnable,
+ CollectionProperties
{}
pallets/nonfungible/src/weights.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/weights.rs
+++ b/pallets/nonfungible/src/weights.rs
@@ -45,7 +45,6 @@
fn approve() -> Weight;
fn transfer_from() -> Weight;
fn burn_from() -> Weight;
- fn set_variable_metadata(b: u32, ) -> Weight;
}
/// Weights for pallet_nonfungible using the Substrate node and recommended hardware.
@@ -155,12 +154,6 @@
(27_580_000 as Weight)
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(5 as Weight))
- }
- // Storage: Nonfungible TokenData (r:1 w:1)
- fn set_variable_metadata(_b: u32, ) -> Weight {
- (7_700_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
}
}
@@ -270,11 +263,5 @@
(27_580_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
.saturating_add(RocksDbWeight::get().writes(5 as Weight))
- }
- // Storage: Nonfungible TokenData (r:1 w:1)
- fn set_variable_metadata(_b: u32, ) -> Weight {
- (7_700_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
}
pallets/refungible/Cargo.tomldiffbeforeafterboth--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -24,6 +24,7 @@
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
+struct-versioning = { path = "../../crates/struct-versioning" }
[features]
default = ["std"]
pallets/refungible/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -31,10 +31,8 @@
users: impl IntoIterator<Item = (CrossAccountId, u128)>,
) -> CreateRefungibleExData<CrossAccountId> {
let const_data = create_data::<CUSTOM_DATA_LIMIT>();
- let variable_data = create_data::<CUSTOM_DATA_LIMIT>();
CreateRefungibleExData {
const_data,
- variable_data,
users: users
.into_iter()
.collect::<BTreeMap<_, _>>()
@@ -203,14 +201,4 @@
let item = create_max_item(&collection, &owner, [(sender.clone(), 200)])?;
<Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;
}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}
-
- set_variable_metadata {
- let b in 0..CUSTOM_DATA_LIMIT;
- bench_init!{
- owner: sub; collection: collection(owner);
- sender: cross_from_sub(owner);
- };
- let item = create_max_item(&collection, &sender, [(sender.clone(), 200)])?;
- let data = create_var_data(b).try_into().unwrap();
- }: {<Pallet<T>>::set_variable_metadata(&collection, &sender, item, data)?}
}
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -17,9 +17,9 @@
use core::marker::PhantomData;
use sp_std::collections::btree_map::BTreeMap;
-use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight, BoundedVec};
+use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight};
use up_data_structs::{
- CollectionId, TokenId, CustomDataLimit, CreateItemExData, CreateRefungibleExData,
+ CollectionId, TokenId, CreateItemExData, CreateRefungibleExData,
budget::Budget, Property, PropertyKey, PropertyKeyPermission,
};
use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
@@ -110,10 +110,6 @@
fn burn_from() -> Weight {
<SelfWeightOf<T>>::burn_from()
- }
-
- fn set_variable_metadata(bytes: u32) -> Weight {
- <SelfWeightOf<T>>::set_variable_metadata(bytes)
}
}
@@ -124,7 +120,6 @@
match data {
up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateRefungibleExData {
const_data: data.const_data,
- variable_data: data.variable_data,
users: {
let mut out = BTreeMap::new();
out.insert(to.clone(), data.pieces);
@@ -306,19 +301,6 @@
fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
- fn set_variable_metadata(
- &self,
- sender: T::CrossAccountId,
- token: TokenId,
- data: BoundedVec<u8, CustomDataLimit>,
- ) -> DispatchResultWithPostInfo {
- let len = data.len();
- with_weight(
- <Pallet<T>>::set_variable_metadata(self, &sender, token, data),
- <CommonWeights<T>>::set_variable_metadata(len as u32),
- )
- }
-
fn check_nesting(
&self,
_sender: <T>::CrossAccountId,
@@ -355,11 +337,6 @@
fn const_metadata(&self, token: TokenId) -> Vec<u8> {
<TokenData<T>>::get((self.id, token))
.const_data
- .into_inner()
- }
- fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
- <TokenData<T>>::get((self.id, token))
- .variable_data
.into_inner()
}
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -41,16 +41,20 @@
pub mod weights;
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
+#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]
pub struct ItemData {
pub const_data: BoundedVec<u8, CustomDataLimit>,
+
+ #[version(..2)]
pub variable_data: BoundedVec<u8, CustomDataLimit>,
}
#[frame_support::pallet]
pub mod pallet {
use super::*;
- use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};
+ use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};
+ use frame_system::pallet_prelude::*;
use up_data_structs::{CollectionId, TokenId};
use super::weights::WeightInfo;
@@ -73,7 +77,10 @@
type WeightInfo: WeightInfo;
}
+ const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
#[pallet::pallet]
+ #[pallet::storage_version(STORAGE_VERSION)]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
@@ -146,6 +153,19 @@
Value = u128,
QueryKind = ValueQuery,
>;
+
+ #[pallet::hooks]
+ impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+ fn on_runtime_upgrade() -> Weight {
+ if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
+ <TokenData<T>>::translate_values::<ItemDataVersion1, _>(|v| {
+ Some(<ItemDataVersion2>::from(v))
+ })
+ }
+
+ 0
+ }
+ }
}
pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
@@ -494,7 +514,6 @@
(collection.id, token_id),
ItemData {
const_data: token.const_data,
- variable_data: token.variable_data,
},
);
for (user, amount) in token.users.into_iter() {
@@ -643,31 +662,6 @@
if let Some(allowance) = allowance {
Self::set_allowance_unchecked(collection, from, spender, token, allowance);
}
- Ok(())
- }
-
- pub fn set_variable_metadata(
- collection: &RefungibleHandle<T>,
- sender: &T::CrossAccountId,
- token: TokenId,
- data: BoundedVec<u8, CustomDataLimit>,
- ) -> DispatchResult {
- collection.check_can_update_meta(
- sender,
- &T::CrossAccountId::from_sub(collection.owner.clone()),
- )?;
-
- let token_data = <TokenData<T>>::get((collection.id, token));
-
- // =========
-
- <TokenData<T>>::insert(
- (collection.id, token),
- ItemData {
- variable_data: data,
- ..token_data
- },
- );
Ok(())
}
pallets/refungible/src/weights.rsdiffbeforeafterboth--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -53,7 +53,6 @@
fn transfer_from_removing() -> Weight;
fn transfer_from_creating_removing() -> Weight;
fn burn_from() -> Weight;
- fn set_variable_metadata(b: u32, ) -> Weight;
}
/// Weights for pallet_refungible using the Substrate node and recommended hardware.
@@ -242,12 +241,6 @@
(42_043_000 as Weight)
.saturating_add(T::DbWeight::get().reads(5 as Weight))
.saturating_add(T::DbWeight::get().writes(7 as Weight))
- }
- // Storage: Refungible TokenData (r:1 w:1)
- fn set_variable_metadata(_b: u32, ) -> Weight {
- (7_364_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
}
}
@@ -436,11 +429,5 @@
(42_043_000 as Weight)
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
.saturating_add(RocksDbWeight::get().writes(7 as Weight))
- }
- // Storage: Refungible TokenData (r:1 w:1)
- fn set_variable_metadata(_b: u32, ) -> Weight {
- (7_364_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
}
}
pallets/unique/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20 clippy::too_many_arguments,21 clippy::unnecessary_mut_passed,22 clippy::unused_unit23)]2425use frame_support::{26 decl_module, decl_storage, decl_error, decl_event,27 dispatch::DispatchResult,28 ensure,29 weights::{Weight},30 transactional,31 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32 BoundedVec,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38 CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,39 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,40 AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,41 SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData, CustomDataLimit,42 CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46 CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,47 dispatch::dispatch_call, dispatch::CollectionDispatch,48};4950#[cfg(feature = "runtime-benchmarks")]51mod benchmarking;52pub mod weights;53use weights::WeightInfo;5455decl_error! {56 /// Error for non-fungible-token module.57 pub enum Error for Module<T: Config> {58 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.59 CollectionDecimalPointLimitExceeded,60 /// This address is not set as sponsor, use setCollectionSponsor first.61 ConfirmUnsetSponsorFail,62 /// Length of items properties must be greater than 0.63 EmptyArgument,64 }65}6667pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {68 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;6970 /// Weight information for extrinsics in this pallet.71 type WeightInfo: WeightInfo;72 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;73}7475decl_event! {76 pub enum Event<T>77 where78 <T as frame_system::Config>::AccountId,79 <T as pallet_evm::account::Config>::CrossAccountId,80 {81 /// Collection sponsor was removed82 ///83 /// # Arguments84 ///85 /// * collection_id: Globally unique collection identifier.86 CollectionSponsorRemoved(CollectionId),8788 /// Collection admin was added89 ///90 /// # Arguments91 ///92 /// * collection_id: Globally unique collection identifier.93 ///94 /// * admin: Admin address.95 CollectionAdminAdded(CollectionId, CrossAccountId),9697 /// Collection owned was change98 ///99 /// # Arguments100 ///101 /// * collection_id: Globally unique collection identifier.102 ///103 /// * owner: New owner address.104 CollectionOwnedChanged(CollectionId, AccountId),105106 /// Collection sponsor was set107 ///108 /// # Arguments109 ///110 /// * collection_id: Globally unique collection identifier.111 ///112 /// * owner: New sponsor address.113 CollectionSponsorSet(CollectionId, AccountId),114115 /// const on chain schema was set116 ///117 /// # Arguments118 ///119 /// * collection_id: Globally unique collection identifier.120 ConstOnChainSchemaSet(CollectionId),121122 /// New sponsor was confirm123 ///124 /// # Arguments125 ///126 /// * collection_id: Globally unique collection identifier.127 ///128 /// * sponsor: New sponsor address.129 SponsorshipConfirmed(CollectionId, AccountId),130131 /// Collection admin was removed132 ///133 /// # Arguments134 ///135 /// * collection_id: Globally unique collection identifier.136 ///137 /// * admin: Admin address.138 CollectionAdminRemoved(CollectionId, CrossAccountId),139140 /// Address was remove from allow list141 ///142 /// # Arguments143 ///144 /// * collection_id: Globally unique collection identifier.145 ///146 /// * user: Address.147 AllowListAddressRemoved(CollectionId, CrossAccountId),148149 /// Address was add to allow list150 ///151 /// # Arguments152 ///153 /// * collection_id: Globally unique collection identifier.154 ///155 /// * user: Address.156 AllowListAddressAdded(CollectionId, CrossAccountId),157158 /// Collection limits was set159 ///160 /// # Arguments161 ///162 /// * collection_id: Globally unique collection identifier.163 CollectionLimitSet(CollectionId),164165 /// Mint permission was set166 ///167 /// # Arguments168 ///169 /// * collection_id: Globally unique collection identifier.170 MintPermissionSet(CollectionId),171172 /// Offchain schema was set173 ///174 /// # Arguments175 ///176 /// * collection_id: Globally unique collection identifier.177 OffchainSchemaSet(CollectionId),178179 /// Public access mode was set180 ///181 /// # Arguments182 ///183 /// * collection_id: Globally unique collection identifier.184 ///185 /// * mode: New access state.186 PublicAccessModeSet(CollectionId, AccessMode),187188 /// Schema version was set189 ///190 /// # Arguments191 ///192 /// * collection_id: Globally unique collection identifier.193 SchemaVersionSet(CollectionId),194 }195}196197type SelfWeightOf<T> = <T as Config>::WeightInfo;198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204// i.e autoincrementing index205// can use non-cryptographic hash206// real - key is controlled by user207// but it is hard to generate enough colliding values, i.e owner of signed txs208// can use non-cryptographic hash209// controlled - key is completly controlled by users210// i.e maps with mutable keys211// should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216// collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218// same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220// no confirmation required, so addresses can be easily generated221decl_storage! {222 trait Store for Module<T: Config> as Unique {223224 //#region Private members225 /// Used for migrations226 ChainVersion: u64;227 //#endregion228229 //#region Tokens transfer rate limit baskets230 /// (Collection id (controlled?2), who created (real))231 /// TODO: Off chain worker should remove from this map when collection gets removed232 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;233 /// Collection id (controlled?2), token id (controlled?2)234 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;235 /// Collection id (controlled?2), owning user (real)236 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;237 /// Collection id (controlled?2), token id (controlled?2)238 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239 //#endregion240241 /// Variable metadata sponsoring242 /// Collection id (controlled?2), token id (controlled?2)243 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;244 /// Approval sponsoring245 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;246 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;247 pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;248 }249}250251decl_module! {252 pub struct Module<T: Config> for enum Call253 where254 origin: T::Origin255 {256 type Error = Error<T>;257258 fn deposit_event() = default;259260 fn on_initialize(_now: T::BlockNumber) -> Weight {261 0262 }263264 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.265 ///266 /// # Permissions267 ///268 /// * Anyone.269 ///270 /// # Arguments271 ///272 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.273 ///274 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.275 ///276 /// * token_prefix: UTF-8 string with token prefix.277 ///278 /// * mode: [CollectionMode] collection type and type dependent data.279 // returns collection ID280 #[weight = <SelfWeightOf<T>>::create_collection()]281 #[transactional]282 #[deprecated]283 pub fn create_collection(origin,284 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,285 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,286 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,287 mode: CollectionMode) -> DispatchResult {288 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {289 name: collection_name,290 description: collection_description,291 token_prefix,292 mode,293 ..Default::default()294 };295 Self::create_collection_ex(origin, data)296 }297298 /// This method creates a collection299 ///300 /// Prefer it to deprecated [`created_collection`] method301 #[weight = <SelfWeightOf<T>>::create_collection()]302 #[transactional]303 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {304 let sender = ensure_signed(origin)?;305306 // =========307308 T::CollectionDispatch::create(sender, data)?;309310 Ok(())311 }312313 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.314 ///315 /// # Permissions316 ///317 /// * Collection Owner.318 ///319 /// # Arguments320 ///321 /// * collection_id: collection to destroy.322 #[weight = <SelfWeightOf<T>>::destroy_collection()]323 #[transactional]324 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {325 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);326 let collection = <CollectionHandle<T>>::try_get(collection_id)?;327328 // =========329330 T::CollectionDispatch::destroy(sender, collection)?;331332 <NftTransferBasket<T>>::remove_prefix(collection_id, None);333 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);334 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);335336 <VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);337 <NftApproveBasket<T>>::remove_prefix(collection_id, None);338 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);339 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);340341 Ok(())342 }343344 /// Add an address to allow list.345 ///346 /// # Permissions347 ///348 /// * Collection Owner349 /// * Collection Admin350 ///351 /// # Arguments352 ///353 /// * collection_id.354 ///355 /// * address.356 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]357 #[transactional]358 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{359360 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);361 let collection = <CollectionHandle<T>>::try_get(collection_id)?;362363 <PalletCommon<T>>::toggle_allowlist(364 &collection,365 &sender,366 &address,367 true,368 )?;369370 Self::deposit_event(Event::<T>::AllowListAddressAdded(371 collection_id,372 address373 ));374375 Ok(())376 }377378 /// Remove an address from allow list.379 ///380 /// # Permissions381 ///382 /// * Collection Owner383 /// * Collection Admin384 ///385 /// # Arguments386 ///387 /// * collection_id.388 ///389 /// * address.390 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]391 #[transactional]392 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{393394 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);395 let collection = <CollectionHandle<T>>::try_get(collection_id)?;396397 <PalletCommon<T>>::toggle_allowlist(398 &collection,399 &sender,400 &address,401 false,402 )?;403404 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(405 collection_id,406 address407 ));408409 Ok(())410 }411412 /// Toggle between normal and allow list access for the methods with access for `Anyone`.413 ///414 /// # Permissions415 ///416 /// * Collection Owner.417 ///418 /// # Arguments419 ///420 /// * collection_id.421 ///422 /// * mode: [AccessMode]423 #[weight = <SelfWeightOf<T>>::set_public_access_mode()]424 #[transactional]425 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult426 {427 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);428429 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;430 target_collection.check_is_owner(&sender)?;431432 target_collection.access = mode.clone();433434 <Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(435 collection_id,436 mode437 ));438439 target_collection.save()440 }441442 /// Allows Anyone to create tokens if:443 /// * Allow List is enabled, and444 /// * Address is added to allow list, and445 /// * This method was called with True parameter446 ///447 /// # Permissions448 /// * Collection Owner449 ///450 /// # Arguments451 ///452 /// * collection_id.453 ///454 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.455 #[weight = <SelfWeightOf<T>>::set_mint_permission()]456 #[transactional]457 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult458 {459 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);460461 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;462 target_collection.check_is_owner(&sender)?;463464 target_collection.mint_mode = mint_permission;465466 <Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(467 collection_id468 ));469470 target_collection.save()471 }472473 /// Change the owner of the collection.474 ///475 /// # Permissions476 ///477 /// * Collection Owner.478 ///479 /// # Arguments480 ///481 /// * collection_id.482 ///483 /// * new_owner.484 #[weight = <SelfWeightOf<T>>::change_collection_owner()]485 #[transactional]486 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {487488 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);489490 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;491 target_collection.check_is_owner(&sender)?;492493 target_collection.owner = new_owner.clone();494 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(495 collection_id,496 new_owner497 ));498499 target_collection.save()500 }501502 /// Adds an admin of the Collection.503 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.504 ///505 /// # Permissions506 ///507 /// * Collection Owner.508 /// * Collection Admin.509 ///510 /// # Arguments511 ///512 /// * collection_id: ID of the Collection to add admin for.513 ///514 /// * new_admin_id: Address of new admin to add.515 #[weight = <SelfWeightOf<T>>::add_collection_admin()]516 #[transactional]517 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {518 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);519 let collection = <CollectionHandle<T>>::try_get(collection_id)?;520521 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(522 collection_id,523 new_admin_id.clone()524 ));525526 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)527 }528529 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.530 ///531 /// # Permissions532 ///533 /// * Collection Owner.534 /// * Collection Admin.535 ///536 /// # Arguments537 ///538 /// * collection_id: ID of the Collection to remove admin for.539 ///540 /// * account_id: Address of admin to remove.541 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]542 #[transactional]543 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {544 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);545 let collection = <CollectionHandle<T>>::try_get(collection_id)?;546547 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(548 collection_id,549 account_id.clone()550 ));551552 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)553 }554555 /// # Permissions556 ///557 /// * Collection Owner558 ///559 /// # Arguments560 ///561 /// * collection_id.562 ///563 /// * new_sponsor.564 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]565 #[transactional]566 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {567 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);568569 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;570 target_collection.check_is_owner(&sender)?;571572 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());573574 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(575 collection_id,576 new_sponsor577 ));578579 target_collection.save()580 }581582 /// # Permissions583 ///584 /// * Sponsor.585 ///586 /// # Arguments587 ///588 /// * collection_id.589 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]590 #[transactional]591 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {592 let sender = ensure_signed(origin)?;593594 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;595 ensure!(596 target_collection.sponsorship.pending_sponsor() == Some(&sender),597 Error::<T>::ConfirmUnsetSponsorFail598 );599600 target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());601602 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(603 collection_id,604 sender605 ));606607 target_collection.save()608 }609610 /// Switch back to pay-per-own-transaction model.611 ///612 /// # Permissions613 ///614 /// * Collection owner.615 ///616 /// # Arguments617 ///618 /// * collection_id.619 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]620 #[transactional]621 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {622 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);623624 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;625 target_collection.check_is_owner(&sender)?;626627 target_collection.sponsorship = SponsorshipState::Disabled;628629 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(630 collection_id631 ));632 target_collection.save()633 }634635 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.636 ///637 /// # Permissions638 ///639 /// * Collection Owner.640 /// * Collection Admin.641 /// * Anyone if642 /// * Allow List is enabled, and643 /// * Address is added to allow list, and644 /// * MintPermission is enabled (see SetMintPermission method)645 ///646 /// # Arguments647 ///648 /// * collection_id: ID of the collection.649 ///650 /// * owner: Address, initial owner of the NFT.651 ///652 /// * data: Token data to store on chain.653 #[weight = T::CommonWeightInfo::create_item()]654 #[transactional]655 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {656 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);657 let budget = budget::Value::new(2);658659 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))660 }661662 /// This method creates multiple items in a collection created with CreateCollection method.663 ///664 /// # Permissions665 ///666 /// * Collection Owner.667 /// * Collection Admin.668 /// * Anyone if669 /// * Allow List is enabled, and670 /// * Address is added to allow list, and671 /// * MintPermission is enabled (see SetMintPermission method)672 ///673 /// # Arguments674 ///675 /// * collection_id: ID of the collection.676 ///677 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].678 ///679 /// * owner: Address, initial owner of the NFT.680 #[weight = T::CommonWeightInfo::create_multiple_items(items_data.len() as u32)]681 #[transactional]682 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {683 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);684 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);685 let budget = budget::Value::new(2);686687 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))688 }689690 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]691 #[transactional]692 pub fn set_collection_properties(693 origin,694 collection_id: CollectionId,695 properties: Vec<Property>696 ) -> DispatchResultWithPostInfo {697 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);698699 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);700701 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))702 }703704 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]705 #[transactional]706 pub fn delete_collection_properties(707 origin,708 collection_id: CollectionId,709 property_keys: Vec<PropertyKey>,710 ) -> DispatchResultWithPostInfo {711 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);712713 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);714715 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))716 }717718 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]719 #[transactional]720 pub fn set_token_properties(721 origin,722 collection_id: CollectionId,723 token_id: TokenId,724 properties: Vec<Property>725 ) -> DispatchResultWithPostInfo {726 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);727728 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);729730 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))731 }732733 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]734 #[transactional]735 pub fn delete_token_properties(736 origin,737 collection_id: CollectionId,738 token_id: TokenId,739 property_keys: Vec<PropertyKey>740 ) -> DispatchResultWithPostInfo {741 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);742743 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);744745 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))746 }747748 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]749 #[transactional]750 pub fn set_property_permissions(751 origin,752 collection_id: CollectionId,753 property_permissions: Vec<PropertyKeyPermission>,754 ) -> DispatchResultWithPostInfo {755 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);756757 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);758759 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))760 }761762 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]763 #[transactional]764 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {765 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);766 let budget = budget::Value::new(2);767768 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))769 }770771 // TODO! transaction weight772773 /// Set transfers_enabled value for particular collection774 ///775 /// # Permissions776 ///777 /// * Collection Owner.778 ///779 /// # Arguments780 ///781 /// * collection_id: ID of the collection.782 ///783 /// * value: New flag value.784 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]785 #[transactional]786 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {787 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);788 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;789 target_collection.check_is_owner(&sender)?;790791 // =========792793 target_collection.limits.transfers_enabled = Some(value);794 target_collection.save()795 }796797 /// Destroys a concrete instance of NFT.798 ///799 /// # Permissions800 ///801 /// * Collection Owner.802 /// * Collection Admin.803 /// * Current NFT Owner.804 ///805 /// # Arguments806 ///807 /// * collection_id: ID of the collection.808 ///809 /// * item_id: ID of NFT to burn.810 #[weight = T::CommonWeightInfo::burn_item()]811 #[transactional]812 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {813 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);814815 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;816 if value == 1 {817 <NftTransferBasket<T>>::remove(collection_id, item_id);818 <NftApproveBasket<T>>::remove(collection_id, item_id);819 }820 // Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?821 // <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());822 // <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));823 Ok(post_info)824 }825826 /// Destroys a concrete instance of NFT on behalf of the owner827 /// See also: [`approve`]828 ///829 /// # Permissions830 ///831 /// * Collection Owner.832 /// * Collection Admin.833 /// * Current NFT Owner.834 ///835 /// # Arguments836 ///837 /// * collection_id: ID of the collection.838 ///839 /// * item_id: ID of NFT to burn.840 ///841 /// * from: owner of item842 #[weight = T::CommonWeightInfo::burn_from()]843 #[transactional]844 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {845 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);846 let budget = budget::Value::new(2);847848 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))849 }850851 /// Change ownership of the token.852 ///853 /// # Permissions854 ///855 /// * Collection Owner856 /// * Collection Admin857 /// * Current NFT owner858 ///859 /// # Arguments860 ///861 /// * recipient: Address of token recipient.862 ///863 /// * collection_id.864 ///865 /// * item_id: ID of the item866 /// * Non-Fungible Mode: Required.867 /// * Fungible Mode: Ignored.868 /// * Re-Fungible Mode: Required.869 ///870 /// * value: Amount to transfer.871 /// * Non-Fungible Mode: Ignored872 /// * Fungible Mode: Must specify transferred amount873 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)874 #[weight = T::CommonWeightInfo::transfer()]875 #[transactional]876 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {877 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);878 let budget = budget::Value::new(2);879880 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))881 }882883 /// Set, change, or remove approved address to transfer the ownership of the NFT.884 ///885 /// # Permissions886 ///887 /// * Collection Owner888 /// * Collection Admin889 /// * Current NFT owner890 ///891 /// # Arguments892 ///893 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).894 ///895 /// * collection_id.896 ///897 /// * item_id: ID of the item.898 #[weight = T::CommonWeightInfo::approve()]899 #[transactional]900 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {901 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);902903 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))904 }905906 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.907 ///908 /// # Permissions909 /// * Collection Owner910 /// * Collection Admin911 /// * Current NFT owner912 /// * Address approved by current NFT owner913 ///914 /// # Arguments915 ///916 /// * from: Address that owns token.917 ///918 /// * recipient: Address of token recipient.919 ///920 /// * collection_id.921 ///922 /// * item_id: ID of the item.923 ///924 /// * value: Amount to transfer.925 #[weight = T::CommonWeightInfo::transfer_from()]926 #[transactional]927 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {928 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);929 let budget = budget::Value::new(2);930931 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))932 }933934 /// Set off-chain data schema.935 ///936 /// # Permissions937 ///938 /// * Collection Owner939 /// * Collection Admin940 ///941 /// # Arguments942 ///943 /// * collection_id.944 ///945 /// * schema: String representing the offchain data schema.946 #[weight = T::CommonWeightInfo::set_variable_metadata(data.len() as u32)]947 #[transactional]948 pub fn set_variable_meta_data (949 origin,950 collection_id: CollectionId,951 item_id: TokenId,952 data: BoundedVec<u8, CustomDataLimit>,953 ) -> DispatchResultWithPostInfo {954 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);955956 dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))957 }958959 /// Set meta_update_permission value for particular collection960 ///961 /// # Permissions962 ///963 /// * Collection Owner.964 ///965 /// # Arguments966 ///967 /// * collection_id: ID of the collection.968 ///969 /// * value: New flag value.970 #[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]971 #[transactional]972 pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {973 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);974 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;975976 ensure!(977 target_collection.meta_update_permission != MetaUpdatePermission::None,978 <CommonError<T>>::MetadataFlagFrozen,979 );980 target_collection.check_is_owner(&sender)?;981982 target_collection.meta_update_permission = value;983984 target_collection.save()985 }986987 /// Set schema standard988 /// ImageURL989 /// Unique990 ///991 /// # Permissions992 ///993 /// * Collection Owner994 /// * Collection Admin995 ///996 /// # Arguments997 ///998 /// * collection_id.999 ///1000 /// * schema: SchemaVersion: enum1001 #[weight = <SelfWeightOf<T>>::set_schema_version()]1002 #[transactional]1003 pub fn set_schema_version(1004 origin,1005 collection_id: CollectionId,1006 version: SchemaVersion1007 ) -> DispatchResult {1008 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1009 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1010 target_collection.check_is_owner_or_admin(&sender)?;1011 target_collection.schema_version = version;10121013 <Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(1014 collection_id1015 ));10161017 target_collection.save()1018 }10191020 /// Set off-chain data schema.1021 ///1022 /// # Permissions1023 ///1024 /// * Collection Owner1025 /// * Collection Admin1026 ///1027 /// # Arguments1028 ///1029 /// * collection_id.1030 ///1031 /// * schema: String representing the offchain data schema.1032 #[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]1033 #[transactional]1034 pub fn set_offchain_schema(1035 origin,1036 collection_id: CollectionId,1037 schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,1038 ) -> DispatchResult {1039 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1040 let collection = <CollectionHandle<T>>::try_get(collection_id)?;10411042 // =========10431044 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;10451046 <Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1047 collection_id1048 ));1049 Ok(())1050 }10511052 /// Set const on-chain data schema.1053 ///1054 /// # Permissions1055 ///1056 /// * Collection Owner1057 /// * Collection Admin1058 ///1059 /// # Arguments1060 ///1061 /// * collection_id.1062 ///1063 /// * schema: String representing the const on-chain data schema.1064 #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1065 #[transactional]1066 pub fn set_const_on_chain_schema (1067 origin,1068 collection_id: CollectionId,1069 schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1070 ) -> DispatchResult {1071 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1072 let collection = <CollectionHandle<T>>::try_get(collection_id)?;10731074 // =========10751076 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;10771078 <Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1079 collection_id1080 ));1081 Ok(())1082 }10831084 #[weight = <SelfWeightOf<T>>::set_collection_limits()]1085 #[transactional]1086 pub fn set_collection_limits(1087 origin,1088 collection_id: CollectionId,1089 new_limit: CollectionLimits,1090 ) -> DispatchResult {1091 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1092 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1093 target_collection.check_is_owner(&sender)?;1094 let old_limit = &target_collection.limits;10951096 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10971098 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1099 collection_id1100 ));11011102 target_collection.save()1103 }1104 }1105}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20 clippy::too_many_arguments,21 clippy::unnecessary_mut_passed,22 clippy::unused_unit23)]2425use frame_support::{26 decl_module, decl_storage, decl_error, decl_event,27 dispatch::DispatchResult,28 ensure,29 weights::{Weight},30 transactional,31 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32 BoundedVec,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38 CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,39 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,40 AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,41 SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData,42 CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46 CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,47 dispatch::dispatch_call, dispatch::CollectionDispatch,48};4950#[cfg(feature = "runtime-benchmarks")]51mod benchmarking;52pub mod weights;53use weights::WeightInfo;5455decl_error! {56 /// Error for non-fungible-token module.57 pub enum Error for Module<T: Config> {58 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.59 CollectionDecimalPointLimitExceeded,60 /// This address is not set as sponsor, use setCollectionSponsor first.61 ConfirmUnsetSponsorFail,62 /// Length of items properties must be greater than 0.63 EmptyArgument,64 }65}6667pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {68 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;6970 /// Weight information for extrinsics in this pallet.71 type WeightInfo: WeightInfo;72 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;73}7475decl_event! {76 pub enum Event<T>77 where78 <T as frame_system::Config>::AccountId,79 <T as pallet_evm::account::Config>::CrossAccountId,80 {81 /// Collection sponsor was removed82 ///83 /// # Arguments84 ///85 /// * collection_id: Globally unique collection identifier.86 CollectionSponsorRemoved(CollectionId),8788 /// Collection admin was added89 ///90 /// # Arguments91 ///92 /// * collection_id: Globally unique collection identifier.93 ///94 /// * admin: Admin address.95 CollectionAdminAdded(CollectionId, CrossAccountId),9697 /// Collection owned was change98 ///99 /// # Arguments100 ///101 /// * collection_id: Globally unique collection identifier.102 ///103 /// * owner: New owner address.104 CollectionOwnedChanged(CollectionId, AccountId),105106 /// Collection sponsor was set107 ///108 /// # Arguments109 ///110 /// * collection_id: Globally unique collection identifier.111 ///112 /// * owner: New sponsor address.113 CollectionSponsorSet(CollectionId, AccountId),114115 /// const on chain schema was set116 ///117 /// # Arguments118 ///119 /// * collection_id: Globally unique collection identifier.120 ConstOnChainSchemaSet(CollectionId),121122 /// New sponsor was confirm123 ///124 /// # Arguments125 ///126 /// * collection_id: Globally unique collection identifier.127 ///128 /// * sponsor: New sponsor address.129 SponsorshipConfirmed(CollectionId, AccountId),130131 /// Collection admin was removed132 ///133 /// # Arguments134 ///135 /// * collection_id: Globally unique collection identifier.136 ///137 /// * admin: Admin address.138 CollectionAdminRemoved(CollectionId, CrossAccountId),139140 /// Address was remove from allow list141 ///142 /// # Arguments143 ///144 /// * collection_id: Globally unique collection identifier.145 ///146 /// * user: Address.147 AllowListAddressRemoved(CollectionId, CrossAccountId),148149 /// Address was add to allow list150 ///151 /// # Arguments152 ///153 /// * collection_id: Globally unique collection identifier.154 ///155 /// * user: Address.156 AllowListAddressAdded(CollectionId, CrossAccountId),157158 /// Collection limits was set159 ///160 /// # Arguments161 ///162 /// * collection_id: Globally unique collection identifier.163 CollectionLimitSet(CollectionId),164165 /// Mint permission was set166 ///167 /// # Arguments168 ///169 /// * collection_id: Globally unique collection identifier.170 MintPermissionSet(CollectionId),171172 /// Offchain schema was set173 ///174 /// # Arguments175 ///176 /// * collection_id: Globally unique collection identifier.177 OffchainSchemaSet(CollectionId),178179 /// Public access mode was set180 ///181 /// # Arguments182 ///183 /// * collection_id: Globally unique collection identifier.184 ///185 /// * mode: New access state.186 PublicAccessModeSet(CollectionId, AccessMode),187188 /// Schema version was set189 ///190 /// # Arguments191 ///192 /// * collection_id: Globally unique collection identifier.193 SchemaVersionSet(CollectionId),194 }195}196197type SelfWeightOf<T> = <T as Config>::WeightInfo;198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204// i.e autoincrementing index205// can use non-cryptographic hash206// real - key is controlled by user207// but it is hard to generate enough colliding values, i.e owner of signed txs208// can use non-cryptographic hash209// controlled - key is completly controlled by users210// i.e maps with mutable keys211// should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216// collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218// same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220// no confirmation required, so addresses can be easily generated221decl_storage! {222 trait Store for Module<T: Config> as Unique {223224 //#region Private members225 /// Used for migrations226 ChainVersion: u64;227 //#endregion228229 //#region Tokens transfer rate limit baskets230 /// (Collection id (controlled?2), who created (real))231 /// TODO: Off chain worker should remove from this map when collection gets removed232 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;233 /// Collection id (controlled?2), token id (controlled?2)234 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;235 /// Collection id (controlled?2), owning user (real)236 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;237 /// Collection id (controlled?2), token id (controlled?2)238 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239 //#endregion240241 /// Approval sponsoring242 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;243 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;244 pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;245 }246}247248decl_module! {249 pub struct Module<T: Config> for enum Call250 where251 origin: T::Origin252 {253 type Error = Error<T>;254255 fn deposit_event() = default;256257 fn on_initialize(_now: T::BlockNumber) -> Weight {258 0259 }260261 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.262 ///263 /// # Permissions264 ///265 /// * Anyone.266 ///267 /// # Arguments268 ///269 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.270 ///271 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.272 ///273 /// * token_prefix: UTF-8 string with token prefix.274 ///275 /// * mode: [CollectionMode] collection type and type dependent data.276 // returns collection ID277 #[weight = <SelfWeightOf<T>>::create_collection()]278 #[transactional]279 #[deprecated]280 pub fn create_collection(origin,281 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,282 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,283 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,284 mode: CollectionMode) -> DispatchResult {285 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {286 name: collection_name,287 description: collection_description,288 token_prefix,289 mode,290 ..Default::default()291 };292 Self::create_collection_ex(origin, data)293 }294295 /// This method creates a collection296 ///297 /// Prefer it to deprecated [`created_collection`] method298 #[weight = <SelfWeightOf<T>>::create_collection()]299 #[transactional]300 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {301 let sender = ensure_signed(origin)?;302303 // =========304305 T::CollectionDispatch::create(sender, data)?;306307 Ok(())308 }309310 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.311 ///312 /// # Permissions313 ///314 /// * Collection Owner.315 ///316 /// # Arguments317 ///318 /// * collection_id: collection to destroy.319 #[weight = <SelfWeightOf<T>>::destroy_collection()]320 #[transactional]321 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {322 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);323 let collection = <CollectionHandle<T>>::try_get(collection_id)?;324325 // =========326327 T::CollectionDispatch::destroy(sender, collection)?;328329 <NftTransferBasket<T>>::remove_prefix(collection_id, None);330 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);331 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);332333 <NftApproveBasket<T>>::remove_prefix(collection_id, None);334 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);335 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);336337 Ok(())338 }339340 /// Add an address to allow list.341 ///342 /// # Permissions343 ///344 /// * Collection Owner345 /// * Collection Admin346 ///347 /// # Arguments348 ///349 /// * collection_id.350 ///351 /// * address.352 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]353 #[transactional]354 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{355356 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);357 let collection = <CollectionHandle<T>>::try_get(collection_id)?;358359 <PalletCommon<T>>::toggle_allowlist(360 &collection,361 &sender,362 &address,363 true,364 )?;365366 Self::deposit_event(Event::<T>::AllowListAddressAdded(367 collection_id,368 address369 ));370371 Ok(())372 }373374 /// Remove an address from allow list.375 ///376 /// # Permissions377 ///378 /// * Collection Owner379 /// * Collection Admin380 ///381 /// # Arguments382 ///383 /// * collection_id.384 ///385 /// * address.386 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]387 #[transactional]388 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{389390 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);391 let collection = <CollectionHandle<T>>::try_get(collection_id)?;392393 <PalletCommon<T>>::toggle_allowlist(394 &collection,395 &sender,396 &address,397 false,398 )?;399400 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(401 collection_id,402 address403 ));404405 Ok(())406 }407408 /// Toggle between normal and allow list access for the methods with access for `Anyone`.409 ///410 /// # Permissions411 ///412 /// * Collection Owner.413 ///414 /// # Arguments415 ///416 /// * collection_id.417 ///418 /// * mode: [AccessMode]419 #[weight = <SelfWeightOf<T>>::set_public_access_mode()]420 #[transactional]421 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult422 {423 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);424425 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;426 target_collection.check_is_owner(&sender)?;427428 target_collection.access = mode.clone();429430 <Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(431 collection_id,432 mode433 ));434435 target_collection.save()436 }437438 /// Allows Anyone to create tokens if:439 /// * Allow List is enabled, and440 /// * Address is added to allow list, and441 /// * This method was called with True parameter442 ///443 /// # Permissions444 /// * Collection Owner445 ///446 /// # Arguments447 ///448 /// * collection_id.449 ///450 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.451 #[weight = <SelfWeightOf<T>>::set_mint_permission()]452 #[transactional]453 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult454 {455 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);456457 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;458 target_collection.check_is_owner(&sender)?;459460 target_collection.mint_mode = mint_permission;461462 <Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(463 collection_id464 ));465466 target_collection.save()467 }468469 /// Change the owner of the collection.470 ///471 /// # Permissions472 ///473 /// * Collection Owner.474 ///475 /// # Arguments476 ///477 /// * collection_id.478 ///479 /// * new_owner.480 #[weight = <SelfWeightOf<T>>::change_collection_owner()]481 #[transactional]482 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {483484 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);485486 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;487 target_collection.check_is_owner(&sender)?;488489 target_collection.owner = new_owner.clone();490 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(491 collection_id,492 new_owner493 ));494495 target_collection.save()496 }497498 /// Adds an admin of the Collection.499 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.500 ///501 /// # Permissions502 ///503 /// * Collection Owner.504 /// * Collection Admin.505 ///506 /// # Arguments507 ///508 /// * collection_id: ID of the Collection to add admin for.509 ///510 /// * new_admin_id: Address of new admin to add.511 #[weight = <SelfWeightOf<T>>::add_collection_admin()]512 #[transactional]513 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {514 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);515 let collection = <CollectionHandle<T>>::try_get(collection_id)?;516517 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(518 collection_id,519 new_admin_id.clone()520 ));521522 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)523 }524525 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.526 ///527 /// # Permissions528 ///529 /// * Collection Owner.530 /// * Collection Admin.531 ///532 /// # Arguments533 ///534 /// * collection_id: ID of the Collection to remove admin for.535 ///536 /// * account_id: Address of admin to remove.537 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]538 #[transactional]539 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {540 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);541 let collection = <CollectionHandle<T>>::try_get(collection_id)?;542543 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(544 collection_id,545 account_id.clone()546 ));547548 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)549 }550551 /// # Permissions552 ///553 /// * Collection Owner554 ///555 /// # Arguments556 ///557 /// * collection_id.558 ///559 /// * new_sponsor.560 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]561 #[transactional]562 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {563 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);564565 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;566 target_collection.check_is_owner(&sender)?;567568 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());569570 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(571 collection_id,572 new_sponsor573 ));574575 target_collection.save()576 }577578 /// # Permissions579 ///580 /// * Sponsor.581 ///582 /// # Arguments583 ///584 /// * collection_id.585 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]586 #[transactional]587 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {588 let sender = ensure_signed(origin)?;589590 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;591 ensure!(592 target_collection.sponsorship.pending_sponsor() == Some(&sender),593 Error::<T>::ConfirmUnsetSponsorFail594 );595596 target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());597598 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(599 collection_id,600 sender601 ));602603 target_collection.save()604 }605606 /// Switch back to pay-per-own-transaction model.607 ///608 /// # Permissions609 ///610 /// * Collection owner.611 ///612 /// # Arguments613 ///614 /// * collection_id.615 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]616 #[transactional]617 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {618 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);619620 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;621 target_collection.check_is_owner(&sender)?;622623 target_collection.sponsorship = SponsorshipState::Disabled;624625 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(626 collection_id627 ));628 target_collection.save()629 }630631 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.632 ///633 /// # Permissions634 ///635 /// * Collection Owner.636 /// * Collection Admin.637 /// * Anyone if638 /// * Allow List is enabled, and639 /// * Address is added to allow list, and640 /// * MintPermission is enabled (see SetMintPermission method)641 ///642 /// # Arguments643 ///644 /// * collection_id: ID of the collection.645 ///646 /// * owner: Address, initial owner of the NFT.647 ///648 /// * data: Token data to store on chain.649 #[weight = T::CommonWeightInfo::create_item()]650 #[transactional]651 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {652 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);653 let budget = budget::Value::new(2);654655 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))656 }657658 /// This method creates multiple items in a collection created with CreateCollection method.659 ///660 /// # Permissions661 ///662 /// * Collection Owner.663 /// * Collection Admin.664 /// * Anyone if665 /// * Allow List is enabled, and666 /// * Address is added to allow list, and667 /// * MintPermission is enabled (see SetMintPermission method)668 ///669 /// # Arguments670 ///671 /// * collection_id: ID of the collection.672 ///673 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].674 ///675 /// * owner: Address, initial owner of the NFT.676 #[weight = T::CommonWeightInfo::create_multiple_items(items_data.len() as u32)]677 #[transactional]678 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {679 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);680 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);681 let budget = budget::Value::new(2);682683 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))684 }685686 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]687 #[transactional]688 pub fn set_collection_properties(689 origin,690 collection_id: CollectionId,691 properties: Vec<Property>692 ) -> DispatchResultWithPostInfo {693 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);694695 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);696697 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))698 }699700 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]701 #[transactional]702 pub fn delete_collection_properties(703 origin,704 collection_id: CollectionId,705 property_keys: Vec<PropertyKey>,706 ) -> DispatchResultWithPostInfo {707 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);708709 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);710711 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))712 }713714 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]715 #[transactional]716 pub fn set_token_properties(717 origin,718 collection_id: CollectionId,719 token_id: TokenId,720 properties: Vec<Property>721 ) -> DispatchResultWithPostInfo {722 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);723724 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);725726 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))727 }728729 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]730 #[transactional]731 pub fn delete_token_properties(732 origin,733 collection_id: CollectionId,734 token_id: TokenId,735 property_keys: Vec<PropertyKey>736 ) -> DispatchResultWithPostInfo {737 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);738739 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);740741 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))742 }743744 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]745 #[transactional]746 pub fn set_property_permissions(747 origin,748 collection_id: CollectionId,749 property_permissions: Vec<PropertyKeyPermission>,750 ) -> DispatchResultWithPostInfo {751 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);752753 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);754755 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))756 }757758 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]759 #[transactional]760 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {761 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);762 let budget = budget::Value::new(2);763764 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))765 }766767 // TODO! transaction weight768769 /// Set transfers_enabled value for particular collection770 ///771 /// # Permissions772 ///773 /// * Collection Owner.774 ///775 /// # Arguments776 ///777 /// * collection_id: ID of the collection.778 ///779 /// * value: New flag value.780 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]781 #[transactional]782 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {783 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);784 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;785 target_collection.check_is_owner(&sender)?;786787 // =========788789 target_collection.limits.transfers_enabled = Some(value);790 target_collection.save()791 }792793 /// Destroys a concrete instance of NFT.794 ///795 /// # Permissions796 ///797 /// * Collection Owner.798 /// * Collection Admin.799 /// * Current NFT Owner.800 ///801 /// # Arguments802 ///803 /// * collection_id: ID of the collection.804 ///805 /// * item_id: ID of NFT to burn.806 #[weight = T::CommonWeightInfo::burn_item()]807 #[transactional]808 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {809 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);810811 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;812 if value == 1 {813 <NftTransferBasket<T>>::remove(collection_id, item_id);814 <NftApproveBasket<T>>::remove(collection_id, item_id);815 }816 // Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?817 // <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());818 // <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));819 Ok(post_info)820 }821822 /// Destroys a concrete instance of NFT on behalf of the owner823 /// See also: [`approve`]824 ///825 /// # Permissions826 ///827 /// * Collection Owner.828 /// * Collection Admin.829 /// * Current NFT Owner.830 ///831 /// # Arguments832 ///833 /// * collection_id: ID of the collection.834 ///835 /// * item_id: ID of NFT to burn.836 ///837 /// * from: owner of item838 #[weight = T::CommonWeightInfo::burn_from()]839 #[transactional]840 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {841 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);842 let budget = budget::Value::new(2);843844 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))845 }846847 /// Change ownership of the token.848 ///849 /// # Permissions850 ///851 /// * Collection Owner852 /// * Collection Admin853 /// * Current NFT owner854 ///855 /// # Arguments856 ///857 /// * recipient: Address of token recipient.858 ///859 /// * collection_id.860 ///861 /// * item_id: ID of the item862 /// * Non-Fungible Mode: Required.863 /// * Fungible Mode: Ignored.864 /// * Re-Fungible Mode: Required.865 ///866 /// * value: Amount to transfer.867 /// * Non-Fungible Mode: Ignored868 /// * Fungible Mode: Must specify transferred amount869 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)870 #[weight = T::CommonWeightInfo::transfer()]871 #[transactional]872 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {873 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);874 let budget = budget::Value::new(2);875876 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))877 }878879 /// Set, change, or remove approved address to transfer the ownership of the NFT.880 ///881 /// # Permissions882 ///883 /// * Collection Owner884 /// * Collection Admin885 /// * Current NFT owner886 ///887 /// # Arguments888 ///889 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).890 ///891 /// * collection_id.892 ///893 /// * item_id: ID of the item.894 #[weight = T::CommonWeightInfo::approve()]895 #[transactional]896 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {897 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);898899 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))900 }901902 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.903 ///904 /// # Permissions905 /// * Collection Owner906 /// * Collection Admin907 /// * Current NFT owner908 /// * Address approved by current NFT owner909 ///910 /// # Arguments911 ///912 /// * from: Address that owns token.913 ///914 /// * recipient: Address of token recipient.915 ///916 /// * collection_id.917 ///918 /// * item_id: ID of the item.919 ///920 /// * value: Amount to transfer.921 #[weight = T::CommonWeightInfo::transfer_from()]922 #[transactional]923 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {924 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);925 let budget = budget::Value::new(2);926927 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))928 }929930 /// Set meta_update_permission value for particular collection931 ///932 /// # Permissions933 ///934 /// * Collection Owner.935 ///936 /// # Arguments937 ///938 /// * collection_id: ID of the collection.939 ///940 /// * value: New flag value.941 #[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]942 #[transactional]943 pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {944 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);945 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;946947 ensure!(948 target_collection.meta_update_permission != MetaUpdatePermission::None,949 <CommonError<T>>::MetadataFlagFrozen,950 );951 target_collection.check_is_owner(&sender)?;952953 target_collection.meta_update_permission = value;954955 target_collection.save()956 }957958 /// Set schema standard959 /// ImageURL960 /// Unique961 ///962 /// # Permissions963 ///964 /// * Collection Owner965 /// * Collection Admin966 ///967 /// # Arguments968 ///969 /// * collection_id.970 ///971 /// * schema: SchemaVersion: enum972 #[weight = <SelfWeightOf<T>>::set_schema_version()]973 #[transactional]974 pub fn set_schema_version(975 origin,976 collection_id: CollectionId,977 version: SchemaVersion978 ) -> DispatchResult {979 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);980 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;981 target_collection.check_is_owner_or_admin(&sender)?;982 target_collection.schema_version = version;983984 <Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(985 collection_id986 ));987988 target_collection.save()989 }990991 /// Set off-chain data schema.992 ///993 /// # Permissions994 ///995 /// * Collection Owner996 /// * Collection Admin997 ///998 /// # Arguments999 ///1000 /// * collection_id.1001 ///1002 /// * schema: String representing the offchain data schema.1003 #[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]1004 #[transactional]1005 pub fn set_offchain_schema(1006 origin,1007 collection_id: CollectionId,1008 schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,1009 ) -> DispatchResult {1010 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1011 let collection = <CollectionHandle<T>>::try_get(collection_id)?;10121013 // =========10141015 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;10161017 <Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1018 collection_id1019 ));1020 Ok(())1021 }10221023 /// Set const on-chain data schema.1024 ///1025 /// # Permissions1026 ///1027 /// * Collection Owner1028 /// * Collection Admin1029 ///1030 /// # Arguments1031 ///1032 /// * collection_id.1033 ///1034 /// * schema: String representing the const on-chain data schema.1035 #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1036 #[transactional]1037 pub fn set_const_on_chain_schema (1038 origin,1039 collection_id: CollectionId,1040 schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1041 ) -> DispatchResult {1042 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1043 let collection = <CollectionHandle<T>>::try_get(collection_id)?;10441045 // =========10461047 <PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;10481049 <Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1050 collection_id1051 ));1052 Ok(())1053 }10541055 #[weight = <SelfWeightOf<T>>::set_collection_limits()]1056 #[transactional]1057 pub fn set_collection_limits(1058 origin,1059 collection_id: CollectionId,1060 new_limit: CollectionLimits,1061 ) -> DispatchResult {1062 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1063 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1064 target_collection.check_is_owner(&sender)?;1065 let old_limit = &target_collection.limits;10661067 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10681069 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1070 collection_id1071 ));10721073 target_collection.save()1074 }1075 }1076}primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -364,28 +364,6 @@
pub type CollectionPropertiesVec =
BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;
-#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct NftItemType<AccountId> {
- pub owner: AccountId,
- pub const_data: Vec<u8>,
- pub variable_data: Vec<u8>,
-}
-
-#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct FungibleItemType {
- pub value: u128,
-}
-
-#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct ReFungibleItemType<AccountId> {
- pub owner: Vec<Ownership<AccountId>>,
- pub const_data: Vec<u8>,
- pub variable_data: Vec<u8>,
-}
-
/// All fields are wrapped in `Option`s, where None means chain default
#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
@@ -393,6 +371,8 @@
pub struct CollectionLimits {
pub account_token_ownership_limit: Option<u32>,
pub sponsored_data_size: Option<u32>,
+
+ /// FIXME should we delete this or repurpose it?
/// None - setVariableMetadata is not sponsored
/// Some(v) - setVariableMetadata is sponsored
/// if there is v block between txs
@@ -490,9 +470,6 @@
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub const_data: BoundedVec<u8, CustomDataLimit>,
- #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
- #[derivative(Debug(format_with = "bounded::vec_debug"))]
- pub variable_data: BoundedVec<u8, CustomDataLimit>,
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
#[derivative(Debug(format_with = "bounded::vec_debug"))]
@@ -512,9 +489,6 @@
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub const_data: BoundedVec<u8, CustomDataLimit>,
- #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
- #[derivative(Debug(format_with = "bounded::vec_debug"))]
- pub variable_data: BoundedVec<u8, CustomDataLimit>,
pub pieces: u128,
}
@@ -545,8 +519,6 @@
pub struct CreateNftExData<CrossAccountId> {
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub const_data: BoundedVec<u8, CustomDataLimit>,
- #[derivative(Debug(format_with = "bounded::vec_debug"))]
- pub variable_data: BoundedVec<u8, CustomDataLimit>,
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub properties: CollectionPropertiesVec,
pub owner: CrossAccountId,
@@ -557,8 +529,6 @@
pub struct CreateRefungibleExData<CrossAccountId> {
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub const_data: BoundedVec<u8, CustomDataLimit>,
- #[derivative(Debug(format_with = "bounded::vec_debug"))]
- pub variable_data: BoundedVec<u8, CustomDataLimit>,
#[derivative(Debug(format_with = "bounded::map_debug"))]
pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,
}
@@ -586,8 +556,8 @@
impl CreateItemData {
pub fn data_size(&self) -> usize {
match self {
- CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),
- CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),
+ CreateItemData::NFT(data) => data.const_data.len(),
+ CreateItemData::ReFungible(data) => data.const_data.len(),
_ => 0,
}
}
primitives/rpc/src/lib.rsdiffbeforeafterboth--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -42,7 +42,6 @@
fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;
- fn variable_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;
fn collection_properties(collection: CollectionId, properties: Vec<Vec<u8>>) -> Result<Vec<Property>>;
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -32,9 +32,6 @@
fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {
dispatch_unique_runtime!(collection.const_metadata(token))
}
- fn variable_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {
- dispatch_unique_runtime!(collection.variable_metadata(token))
- }
fn collection_properties(
collection: CollectionId,
runtime/common/src/sponsoring.rsdiffbeforeafterboth--- a/runtime/common/src/sponsoring.rs
+++ b/runtime/common/src/sponsoring.rs
@@ -21,7 +21,7 @@
storage::{StorageMap, StorageDoubleMap, StorageNMap},
};
use up_data_structs::{
- CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MetaUpdatePermission,
+ CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode,
CreateItemData,
};
@@ -30,7 +30,7 @@
use pallet_evm::account::CrossAccountId;
use pallet_unique::{
Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
- NftApproveBasket, VariableMetaDataBasket, CreateItemBasket, ReFungibleTransferBasket,
+ NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket,
FungibleTransferBasket, NftTransferBasket,
};
use pallet_fungible::Config as FungibleConfig;
@@ -139,64 +139,7 @@
Some(())
}
-
-pub fn withdraw_set_variable_meta_data<T: Config>(
- who: &T::CrossAccountId,
- collection: &CollectionHandle<T>,
- item_id: &TokenId,
- data: &[u8],
-) -> Option<()> {
- // TODO: make it work for admins
- if collection.meta_update_permission != MetaUpdatePermission::ItemOwner {
- return None;
- }
- // preliminary sponsoring correctness check
- match collection.mode {
- CollectionMode::NFT => {
- let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
- if !owner.conv_eq(who) {
- return None;
- }
- }
- CollectionMode::Fungible(_) => {
- if item_id != &TokenId::default() {
- return None;
- }
- if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
- return None;
- }
- }
- CollectionMode::ReFungible => {
- if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
- return None;
- }
- }
- }
- // Can't sponsor fungible collection, this tx will be rejected
- // as invalid
- if matches!(collection.mode, CollectionMode::Fungible(_)) {
- return None;
- }
- if data.len() > collection.limits.sponsored_data_size() as usize {
- return None;
- }
-
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
- let limit = collection.limits.sponsored_data_rate_limit()?;
-
- if let Some(last_tx_block) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {
- let timeout = last_tx_block + limit.into();
- if block_number < timeout {
- return None;
- }
- }
-
- <VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);
-
- Some(())
-}
-
pub fn withdraw_approve<T: Config>(
collection: &CollectionHandle<T>,
who: &T::AccountId,
@@ -290,20 +233,6 @@
} => {
let (sponsor, collection) = load(*collection_id)?;
withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
- }
- UniqueCall::set_variable_meta_data {
- collection_id,
- item_id,
- data,
- } => {
- let (sponsor, collection) = load(*collection_id)?;
- withdraw_set_variable_meta_data::<T>(
- &T::CrossAccountId::from_sub(who.clone()),
- &collection,
- item_id,
- data,
- )
- .map(|()| sponsor)
}
_ => None,
}
runtime/common/src/weights.rsdiffbeforeafterboth--- a/runtime/common/src/weights.rs
+++ b/runtime/common/src/weights.rs
@@ -86,10 +86,6 @@
dispatch_weight::<T>() + max_weight_of!(transfer_from())
}
- fn set_variable_metadata(bytes: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(set_variable_metadata(bytes))
- }
-
fn burn_from() -> Weight {
dispatch_weight::<T>() + max_weight_of!(burn_from())
}
runtime/tests/src/tests.rsdiffbeforeafterboth--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -47,7 +47,6 @@
fn default_nft_data() -> CreateNftData {
CreateNftData {
const_data: vec![1, 2, 3].try_into().unwrap(),
- variable_data: vec![3, 2, 1].try_into().unwrap(),
}
}
@@ -58,7 +57,6 @@
fn default_re_fungible_data() -> CreateReFungibleData {
CreateReFungibleData {
const_data: vec![1, 2, 3].try_into().unwrap(),
- variable_data: vec![3, 2, 1].try_into().unwrap(),
pieces: 1023,
}
}
@@ -215,7 +213,6 @@
let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();
assert_eq!(item.const_data, data.const_data.into_inner());
- assert_eq!(item.variable_data, data.variable_data.into_inner());
});
}
@@ -247,7 +244,6 @@
))
.unwrap();
assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
- assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
}
});
}
@@ -263,7 +259,6 @@
let balance =
<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));
assert_eq!(item.const_data, data.const_data.into_inner());
- assert_eq!(item.variable_data, data.variable_data.into_inner());
assert_eq!(balance, 1023);
});
}
@@ -299,7 +294,6 @@
let balance =
<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));
assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
- assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
assert_eq!(balance, 1023);
}
});
@@ -413,7 +407,6 @@
create_test_item(collection_id, &data.clone().into());
let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
assert_eq!(item.const_data, data.const_data.into_inner());
- assert_eq!(item.variable_data, data.variable_data.into_inner());
assert_eq!(
<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
1
@@ -2427,117 +2420,6 @@
}
#[test]
-fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {
- new_test_ext().execute_with(|| {
- let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
- let origin1 = Origin::signed(1);
-
- let data = default_nft_data();
- create_test_item(CollectionId(1), &data.into());
-
- let variable_data = b"test data".to_vec();
- assert_ok!(Unique::set_variable_meta_data(
- origin1,
- collection_id,
- TokenId(1),
- variable_data.clone().try_into().unwrap()
- ));
-
- assert_eq!(
- <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
- .unwrap()
- .variable_data,
- variable_data
- );
- });
-}
-
-#[test]
-fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {
- new_test_ext().execute_with(|| {
- let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
- let origin1 = Origin::signed(1);
-
- let data = default_re_fungible_data();
- create_test_item(collection_id, &data.into());
-
- let variable_data = b"test data".to_vec();
- assert_ok!(Unique::set_variable_meta_data(
- origin1,
- collection_id,
- TokenId(1),
- variable_data.clone().try_into().unwrap()
- ));
-
- assert_eq!(
- <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,
- variable_data
- );
- });
-}
-
-#[test]
-fn set_variable_meta_data_on_fungible_token_fails() {
- new_test_ext().execute_with(|| {
- let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
- let origin1 = Origin::signed(1);
-
- let data = default_fungible_data();
- create_test_item(collection_id, &data.into());
-
- let variable_data = b"test data".to_vec();
- assert_noop!(
- Unique::set_variable_meta_data(
- origin1,
- collection_id,
- TokenId(0),
- variable_data.try_into().unwrap()
- )
- .map_err(|e| e.error),
- <pallet_fungible::Error<Test>>::FungibleItemsDontHaveData
- );
- });
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {
- new_test_ext().execute_with(|| {
- //default_limits();
-
- let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
- let origin1 = Origin::signed(1);
-
- let data = default_nft_data();
- create_test_item(collection_id, &data.into());
-
- assert_ok!(Unique::set_meta_update_permission_flag(
- origin1.clone(),
- collection_id,
- MetaUpdatePermission::ItemOwner,
- ));
-
- let variable_data = b"ten chars.".to_vec();
- assert_ok!(Unique::set_variable_meta_data(
- origin1,
- collection_id,
- TokenId(1),
- variable_data.clone().try_into().unwrap()
- ));
-
- assert_eq!(
- <pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))
- .unwrap()
- .variable_data,
- variable_data
- );
- });
-}
-
-#[test]
fn collection_transfer_flag_works() {
new_test_ext().execute_with(|| {
let origin1 = Origin::signed(1);
@@ -2590,105 +2472,6 @@
}
#[test]
-fn set_variable_meta_data_on_nft_with_admin_flag() {
- new_test_ext().execute_with(|| {
- // default_limits();
-
- let collection_id =
- create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
- let origin1 = Origin::signed(1);
- let origin2 = Origin::signed(2);
-
- assert_ok!(Unique::set_mint_permission(
- origin2.clone(),
- collection_id,
- true
- ));
- assert_ok!(Unique::add_to_allow_list(
- origin2.clone(),
- collection_id,
- account(1)
- ));
-
- assert_ok!(Unique::add_collection_admin(
- origin2.clone(),
- collection_id,
- account(1)
- ));
-
- let data = default_nft_data();
- create_test_item(collection_id, &data.into());
-
- assert_ok!(Unique::set_meta_update_permission_flag(
- origin2.clone(),
- collection_id,
- MetaUpdatePermission::Admin,
- ));
-
- let variable_data = b"test.".to_vec();
- assert_ok!(Unique::set_variable_meta_data(
- origin1,
- collection_id,
- TokenId(1),
- variable_data.clone().try_into().unwrap()
- ));
-
- assert_eq!(
- <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
- .unwrap()
- .variable_data,
- variable_data
- );
- });
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_admin_flag_neg() {
- new_test_ext().execute_with(|| {
- // default_limits();
-
- let collection_id =
- create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
- let origin1 = Origin::signed(1);
- let origin2 = Origin::signed(2);
-
- assert_ok!(Unique::set_mint_permission(
- origin2.clone(),
- collection_id,
- true
- ));
- assert_ok!(Unique::add_to_allow_list(
- origin2.clone(),
- collection_id,
- account(1)
- ));
-
- let data = default_nft_data();
- create_test_item(collection_id, &data.into());
-
- assert_ok!(Unique::set_meta_update_permission_flag(
- origin2.clone(),
- collection_id,
- MetaUpdatePermission::Admin,
- ));
-
- let variable_data = b"test.".to_vec();
- assert_noop!(
- Unique::set_variable_meta_data(
- origin1,
- collection_id,
- TokenId(1),
- variable_data.try_into().unwrap()
- )
- .map_err(|e| e.error),
- CommonError::<Test>::NoPermission
- );
- });
-}
-
-#[test]
fn set_variable_meta_flag_after_freeze() {
new_test_ext().execute_with(|| {
// default_limits();
@@ -2710,38 +2493,6 @@
MetaUpdatePermission::Admin
),
CommonError::<Test>::MetadataFlagFrozen
- );
- });
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_none_flag_neg() {
- new_test_ext().execute_with(|| {
- // default_limits();
-
- let collection_id =
- create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
- let origin1 = Origin::signed(1);
-
- let data = default_nft_data();
- create_test_item(collection_id, &data.into());
-
- assert_ok!(Unique::set_meta_update_permission_flag(
- origin1.clone(),
- collection_id,
- MetaUpdatePermission::None,
- ));
-
- let variable_data = b"test.".to_vec();
- assert_noop!(
- Unique::set_variable_meta_data(
- origin1.clone(),
- collection_id,
- TokenId(1),
- variable_data.try_into().unwrap()
- )
- .map_err(|e| e.error),
- CommonError::<Test>::NoPermission
);
});
}
smart_contracs/transfer/lib.rsdiffbeforeafterboth--- a/smart_contracs/transfer/lib.rs
+++ b/smart_contracs/transfer/lib.rs
@@ -58,14 +58,12 @@
pub enum CreateItemData {
Nft {
const_data: Vec<u8>,
- variable_data: Vec<u8>,
},
Fungible {
value: u128,
},
ReFungible {
const_data: Vec<u8>,
- variable_data: Vec<u8>,
pieces: u128,
},
}
@@ -88,8 +86,6 @@
fn approve(spender: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);
#[ink(extension = 4, returns_result = false)]
fn transfer_from(owner: DefaultAccountId, recipient: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);
- #[ink(extension = 5, returns_result = false)]
- fn set_variable_meta_data(collection_id: u32, item_id: u32, data: Vec<u8>);
#[ink(extension = 6, returns_result = false)]
fn toggle_allow_list(collection_id: u32, address: DefaultAccountId, allowlisted: bool);
}
@@ -143,12 +139,6 @@
let _ = self.env()
.extension()
.transfer_from(owner, recipient, collection_id, item_id, amount);
- }
- #[ink(message)]
- pub fn set_variable_meta_data(&mut self, collection_id: u32, item_id: u32, data: Vec<u8>) {
- let _ = self.env()
- .extension()
- .set_variable_meta_data(collection_id, item_id, data);
}
#[ink(message)]
pub fn toggle_allow_list(&mut self, collection_id: u32, address: AccountId, allowlisted: bool) {