difftreelog
fix evm nitpicks
in: master
11 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4290,9 +4290,6 @@
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-dependencies = [
- "spin",
-]
[[package]]
name = "lazycell"
@@ -5920,7 +5917,6 @@
"frame-benchmarking",
"frame-support",
"frame-system",
- "lazy_static",
"pallet-evm",
"pallet-evm-coder-substrate",
"parity-scale-codec 3.1.2",
pallets/common/Cargo.tomldiffbeforeafterboth--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -27,7 +27,6 @@
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
-lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
[features]
default = ["std"]
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -15,7 +15,7 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
use evm_coder::{
- solidity_interface,
+ solidity_interface, solidity,
types::*,
execution::{Result, Error},
};
@@ -88,40 +88,64 @@
Ok(())
}
- fn set_limit(&mut self, caller: caller, limit: string, value: string) -> Result<void> {
+ #[solidity(rename_selector = "setLimit")]
+ fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {
check_is_owner(caller, self)?;
let mut limits = self.limits.clone();
match limit.as_str() {
"accountTokenOwnershipLimit" => {
- limits.account_token_ownership_limit = parse_int(value)?;
+ limits.account_token_ownership_limit = Some(value);
}
"sponsoredDataSize" => {
- limits.sponsored_data_size = parse_int(value)?;
+ limits.sponsored_data_size = Some(value);
}
"sponsoredDataRateLimit" => {
- limits.sponsored_data_rate_limit =
- Some(SponsoringRateLimit::Blocks(parse_int(value)?.unwrap()));
+ limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(value));
}
"tokenLimit" => {
- limits.token_limit = parse_int(value)?;
+ limits.token_limit = Some(value);
}
"sponsorTransferTimeout" => {
- limits.sponsor_transfer_timeout = parse_int(value)?;
+ limits.sponsor_transfer_timeout = Some(value);
}
"sponsorApproveTimeout" => {
- limits.sponsor_approve_timeout = parse_int(value)?;
+ limits.sponsor_approve_timeout = Some(value);
}
+ _ => {
+ return Err(Error::Revert(format!(
+ "Unknown integer limit \"{}\"",
+ limit
+ )))
+ }
+ }
+ self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
+ .map_err(dispatch_to_evm::<T>)?;
+ save(self);
+ Ok(())
+ }
+
+ #[solidity(rename_selector = "setLimit")]
+ fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {
+ check_is_owner(caller, self)?;
+ let mut limits = self.limits.clone();
+
+ match limit.as_str() {
"ownerCanTransfer" => {
- limits.owner_can_transfer = parse_bool(value)?;
+ limits.owner_can_transfer = Some(value);
}
"ownerCanDestroy" => {
- limits.owner_can_destroy = parse_bool(value)?;
+ limits.owner_can_destroy = Some(value);
}
"transfersEnabled" => {
- limits.transfers_enabled = parse_bool(value)?;
+ limits.transfers_enabled = Some(value);
}
- _ => return Err(Error::Revert(format!("Unknown limit \"{}\"", limit))),
+ _ => {
+ return Err(Error::Revert(format!(
+ "Unknown boolean limit \"{}\"",
+ limit
+ )))
+ }
}
self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
.map_err(dispatch_to_evm::<T>)?;
@@ -146,16 +170,9 @@
<crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());
}
-fn parse_int(value: string) -> Result<Option<u32>> {
- value
- .parse::<u32>()
- .map_err(|e| Error::Revert(format!("Int value \"{}\" parse error: {}", value, e)))
- .map(|value| Some(value))
-}
-
-fn parse_bool(value: string) -> Result<Option<bool>> {
- value
- .parse::<bool>()
- .map_err(|e| Error::Revert(format!("Bool value \"{}\" parse error: {}", value, e)))
- .map(|value| Some(value))
+pub fn token_uri_key() -> up_data_structs::PropertyKey {
+ b"tokenURI"
+ .to_vec()
+ .try_into()
+ .expect("length < limit; qed")
}
pallets/common/src/eth.rsdiffbeforeafterboth--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -17,14 +17,6 @@
use up_data_structs::CollectionId;
use sp_core::H160;
-lazy_static::lazy_static! {
- pub static ref KEY_TOKEN_URI: up_data_structs::PropertyKey = {
- let key: evm_coder::types::string = "tokenURI".into(); //TODO: make static
- let key: up_data_structs::PropertyKey = key.into_bytes().try_into().expect("Can't create \"tokenURI\" key");
- key
- };
-}
-
// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1
// TODO: Unhardcode prefix
const ETH_COLLECTION_PREFIX: [u8; 16] = [
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -22,14 +22,14 @@
use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
use frame_support::BoundedVec;
use up_data_structs::{
- TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property, CollectionId,
- PropertyKey, CollectionPropertiesVec,
+ TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,
+ CollectionPropertiesVec,
};
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_core::{H160, U256};
use sp_std::vec::Vec;
use pallet_common::{
- erc::{CommonEvmHandler, PrecompileResult, CollectionCall},
+ erc::{CommonEvmHandler, PrecompileResult, CollectionCall, token_uri_key},
CollectionHandle, CollectionPropertyPermissions,
};
use pallet_evm::account::CrossAccountId;
@@ -161,7 +161,7 @@
/// Returns token's const_metadata
#[solidity(rename_selector = "tokenURI")]
fn token_uri(&self, token_id: uint256) -> Result<string> {
- let key = pallet_common::eth::KEY_TOKEN_URI.clone();
+ let key = token_uri_key();
if !has_token_permission::<T>(self.id, &key) {
return Err("No tokenURI permission".into());
}
@@ -362,7 +362,7 @@
token_id: uint256,
token_uri: string,
) -> Result<bool> {
- let key = pallet_common::eth::KEY_TOKEN_URI.clone();
+ let key = token_uri_key();
let permission = get_token_permission::<T>(self.id, &key)?;
if !permission.collection_admin {
return Err("Operation is not allowed".into());
@@ -524,6 +524,7 @@
to: address,
tokens: Vec<(uint256, string)>,
) -> Result<bool> {
+ let key = token_uri_key();
let caller = T::CrossAccountId::from_eth(caller);
let to = T::CrossAccountId::from_eth(to);
let mut expected_index = <TokensMinted<T>>::get(self.id)
@@ -541,8 +542,19 @@
}
expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
+ let mut properties = CollectionPropertiesVec::default();
+ properties
+ .try_push(Property {
+ key: key.clone(),
+ value: token_uri
+ .into_bytes()
+ .try_into()
+ .map_err(|_| "token uri is too long")?,
+ })
+ .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;
+
data.push(CreateItemData::<T> {
- properties: BoundedVec::default(),
+ properties,
owner: to.clone(),
});
}
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -15,29 +15,20 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
use core::marker::PhantomData;
-use evm_coder::{execution::*, generate_stubgen, solidity_interface, types::*, ToLog};
+use evm_coder::{execution::*, generate_stubgen, solidity_interface, weight, types::*};
use ethereum as _;
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
-use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, Pallet as PalletEvm};
+use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId};
use up_data_structs::{
CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
MAX_COLLECTION_NAME_LENGTH,
};
use frame_support::traits::Get;
-use sp_core::H160;
-use pallet_common::CollectionById;
+use pallet_common::{CollectionById, erc::token_uri_key};
+use crate::{SelfWeightOf, Config, weights::WeightInfo};
use sp_std::vec::Vec;
use alloc::format;
-
-pub trait Config:
- frame_system::Config
- + pallet_evm_coder_substrate::Config
- + pallet_evm::account::Config
- + pallet_nonfungible::Config
-{
- type ContractAddress: Get<H160>;
-}
struct EvmCollectionHelper<T: Config>(SubstrateRecorder<T>);
impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {
@@ -51,8 +42,9 @@
}
#[solidity_interface(name = "CollectionHelper")]
-impl<T: Config> EvmCollectionHelper<T> {
- fn create_721_collection(
+impl<T: Config + pallet_nonfungible::Config> EvmCollectionHelper<T> {
+ #[weight(<SelfWeightOf<T>>::create_collection())]
+ fn create_nonfungible_collection(
&self,
caller: caller,
name: string,
@@ -77,7 +69,7 @@
.try_into()
.map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;
- let key = pallet_common::eth::KEY_TOKEN_URI.clone();
+ let key = token_uri_key();
let permission = up_data_structs::PropertyPermission {
mutable: true,
collection_admin: true,
@@ -102,13 +94,6 @@
.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
- <PalletEvm<T>>::deposit_log(
- EthCollectionEvent::CollectionCreated {
- owner: *caller.as_eth(),
- collection_id: address,
- }
- .to_log(address),
- );
Ok(address)
}
@@ -122,18 +107,8 @@
}
}
-#[derive(ToLog)]
-pub enum EthCollectionEvent {
- CollectionCreated {
- #[indexed]
- owner: address,
- #[indexed]
- collection_id: address,
- },
-}
-
pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);
-impl<T: Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {
+impl<T: Config + pallet_nonfungible::Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {
fn is_reserved(contract: &sp_core::H160) -> bool {
contract == &T::ContractAddress::get()
}
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)]2425extern crate alloc;2627use frame_support::{28 decl_module, decl_storage, decl_error, decl_event,29 dispatch::DispatchResult,30 ensure,31 weights::{Weight},32 transactional,33 pallet_prelude::{DispatchResultWithPostInfo, ConstU32, Get},34 BoundedVec,35};36use sp_core::H160;37use scale_info::TypeInfo;38use frame_system::{self as system, ensure_signed};39use sp_runtime::{sp_std::prelude::Vec};40use up_data_structs::{41 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,42 CreateItemData, CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId,43 SponsorshipState, CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,44 PropertyKeyPermission,45};46use pallet_evm::account::CrossAccountId;47use pallet_common::{48 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,49 dispatch::CollectionDispatch,50};51pub mod eth;5253#[cfg(feature = "runtime-benchmarks")]54mod benchmarking;55pub mod weights;56use weights::WeightInfo;5758const NESTING_BUDGET: u32 = 5;5960decl_error! {61 /// Error for non-fungible-token module.62 pub enum Error for Module<T: Config> {63 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.64 CollectionDecimalPointLimitExceeded,65 /// This address is not set as sponsor, use setCollectionSponsor first.66 ConfirmUnsetSponsorFail,67 /// Length of items properties must be greater than 0.68 EmptyArgument,69 }70}7172pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {73 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;7475 /// Weight information for extrinsics in this pallet.76 type WeightInfo: WeightInfo;77 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;78 type ContractAddress: Get<H160>;79}8081decl_event! {82 pub enum Event<T>83 where84 <T as frame_system::Config>::AccountId,85 <T as pallet_evm::account::Config>::CrossAccountId,86 {87 /// Collection sponsor was removed88 ///89 /// # Arguments90 ///91 /// * collection_id: Globally unique collection identifier.92 CollectionSponsorRemoved(CollectionId),9394 /// Collection admin was added95 ///96 /// # Arguments97 ///98 /// * collection_id: Globally unique collection identifier.99 ///100 /// * admin: Admin address.101 CollectionAdminAdded(CollectionId, CrossAccountId),102103 /// Collection owned was change104 ///105 /// # Arguments106 ///107 /// * collection_id: Globally unique collection identifier.108 ///109 /// * owner: New owner address.110 CollectionOwnedChanged(CollectionId, AccountId),111112 /// Collection sponsor was set113 ///114 /// # Arguments115 ///116 /// * collection_id: Globally unique collection identifier.117 ///118 /// * owner: New sponsor address.119 CollectionSponsorSet(CollectionId, AccountId),120121 /// New sponsor was confirm122 ///123 /// # Arguments124 ///125 /// * collection_id: Globally unique collection identifier.126 ///127 /// * sponsor: New sponsor address.128 SponsorshipConfirmed(CollectionId, AccountId),129130 /// Collection admin was removed131 ///132 /// # Arguments133 ///134 /// * collection_id: Globally unique collection identifier.135 ///136 /// * admin: Admin address.137 CollectionAdminRemoved(CollectionId, CrossAccountId),138139 /// Address was remove from allow list140 ///141 /// # Arguments142 ///143 /// * collection_id: Globally unique collection identifier.144 ///145 /// * user: Address.146 AllowListAddressRemoved(CollectionId, CrossAccountId),147148 /// Address was add to allow list149 ///150 /// # Arguments151 ///152 /// * collection_id: Globally unique collection identifier.153 ///154 /// * user: Address.155 AllowListAddressAdded(CollectionId, CrossAccountId),156157 /// Collection limits was set158 ///159 /// # Arguments160 ///161 /// * collection_id: Globally unique collection identifier.162 CollectionLimitSet(CollectionId),163164 CollectionPermissionSet(CollectionId),165 }166}167168type SelfWeightOf<T> = <T as Config>::WeightInfo;169170// # Used definitions171//172// ## User control levels173//174// chain-controlled - key is uncontrolled by user175// i.e autoincrementing index176// can use non-cryptographic hash177// real - key is controlled by user178// but it is hard to generate enough colliding values, i.e owner of signed txs179// can use non-cryptographic hash180// controlled - key is completly controlled by users181// i.e maps with mutable keys182// should use cryptographic hash183//184// ## User control level downgrade reasons185//186// ?1 - chain-controlled -> controlled187// collections/tokens can be destroyed, resulting in massive holes188// ?2 - chain-controlled -> controlled189// same as ?1, but can be only added, resulting in easier exploitation190// ?3 - real -> controlled191// no confirmation required, so addresses can be easily generated192decl_storage! {193 trait Store for Module<T: Config> as Unique {194195 //#region Private members196 /// Used for migrations197 ChainVersion: u64;198 //#endregion199200 //#region Tokens transfer rate limit baskets201 /// (Collection id (controlled?2), who created (real))202 /// TODO: Off chain worker should remove from this map when collection gets removed203 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;204 /// Collection id (controlled?2), token id (controlled?2)205 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;206 /// Collection id (controlled?2), owning user (real)207 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;208 /// Collection id (controlled?2), token id (controlled?2)209 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>;210 //#endregion211212 /// Variable metadata sponsoring213 /// Collection id (controlled?2), token id (controlled?2)214 #[deprecated]215 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;216 pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;217218 /// Approval sponsoring219 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;220 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;221 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>;222 }223}224225decl_module! {226 pub struct Module<T: Config> for enum Call227 where228 origin: T::Origin229 {230 type Error = Error<T>;231232 fn deposit_event() = default;233234 fn on_initialize(_now: T::BlockNumber) -> Weight {235 0236 }237238 fn on_runtime_upgrade() -> Weight {239 let limit = None;240241 <VariableMetaDataBasket<T>>::remove_all(limit);242243 0244 }245246 /// 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.247 ///248 /// # Permissions249 ///250 /// * Anyone.251 ///252 /// # Arguments253 ///254 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.255 ///256 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.257 ///258 /// * token_prefix: UTF-8 string with token prefix.259 ///260 /// * mode: [CollectionMode] collection type and type dependent data.261 // returns collection ID262 #[weight = <SelfWeightOf<T>>::create_collection()]263 #[transactional]264 #[deprecated]265 pub fn create_collection(origin,266 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,267 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,268 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,269 mode: CollectionMode) -> DispatchResult {270 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {271 name: collection_name,272 description: collection_description,273 token_prefix,274 mode,275 ..Default::default()276 };277 Self::create_collection_ex(origin, data)278 }279280 /// This method creates a collection281 ///282 /// Prefer it to deprecated [`created_collection`] method283 #[weight = <SelfWeightOf<T>>::create_collection()]284 #[transactional]285 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {286 let sender = ensure_signed(origin)?;287288 // =========289290 T::CollectionDispatch::create(sender, data)?;291292 Ok(())293 }294295 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.296 ///297 /// # Permissions298 ///299 /// * Collection Owner.300 ///301 /// # Arguments302 ///303 /// * collection_id: collection to destroy.304 #[weight = <SelfWeightOf<T>>::destroy_collection()]305 #[transactional]306 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {307 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);308 let collection = <CollectionHandle<T>>::try_get(collection_id)?;309310 // =========311312 T::CollectionDispatch::destroy(sender, collection)?;313314 <NftTransferBasket<T>>::remove_prefix(collection_id, None);315 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);316 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);317318 <NftApproveBasket<T>>::remove_prefix(collection_id, None);319 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);320 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);321322 Ok(())323 }324325 /// Add an address to allow list.326 ///327 /// # Permissions328 ///329 /// * Collection Owner330 /// * Collection Admin331 ///332 /// # Arguments333 ///334 /// * collection_id.335 ///336 /// * address.337 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]338 #[transactional]339 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{340341 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);342 let collection = <CollectionHandle<T>>::try_get(collection_id)?;343344 <PalletCommon<T>>::toggle_allowlist(345 &collection,346 &sender,347 &address,348 true,349 )?;350351 Self::deposit_event(Event::<T>::AllowListAddressAdded(352 collection_id,353 address354 ));355356 Ok(())357 }358359 /// Remove an address from allow list.360 ///361 /// # Permissions362 ///363 /// * Collection Owner364 /// * Collection Admin365 ///366 /// # Arguments367 ///368 /// * collection_id.369 ///370 /// * address.371 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]372 #[transactional]373 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{374375 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);376 let collection = <CollectionHandle<T>>::try_get(collection_id)?;377378 <PalletCommon<T>>::toggle_allowlist(379 &collection,380 &sender,381 &address,382 false,383 )?;384385 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(386 collection_id,387 address388 ));389390 Ok(())391 }392393 /// Change the owner of the collection.394 ///395 /// # Permissions396 ///397 /// * Collection Owner.398 ///399 /// # Arguments400 ///401 /// * collection_id.402 ///403 /// * new_owner.404 #[weight = <SelfWeightOf<T>>::change_collection_owner()]405 #[transactional]406 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {407408 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);409410 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;411 target_collection.check_is_owner(&sender)?;412413 target_collection.owner = new_owner.clone();414 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(415 collection_id,416 new_owner417 ));418419 target_collection.save()420 }421422 /// Adds an admin of the Collection.423 /// 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.424 ///425 /// # Permissions426 ///427 /// * Collection Owner.428 /// * Collection Admin.429 ///430 /// # Arguments431 ///432 /// * collection_id: ID of the Collection to add admin for.433 ///434 /// * new_admin_id: Address of new admin to add.435 #[weight = <SelfWeightOf<T>>::add_collection_admin()]436 #[transactional]437 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {438 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);439 let collection = <CollectionHandle<T>>::try_get(collection_id)?;440441 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(442 collection_id,443 new_admin_id.clone()444 ));445446 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)447 }448449 /// 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.450 ///451 /// # Permissions452 ///453 /// * Collection Owner.454 /// * Collection Admin.455 ///456 /// # Arguments457 ///458 /// * collection_id: ID of the Collection to remove admin for.459 ///460 /// * account_id: Address of admin to remove.461 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]462 #[transactional]463 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {464 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);465 let collection = <CollectionHandle<T>>::try_get(collection_id)?;466467 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(468 collection_id,469 account_id.clone()470 ));471472 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)473 }474475 /// # Permissions476 ///477 /// * Collection Owner478 ///479 /// # Arguments480 ///481 /// * collection_id.482 ///483 /// * new_sponsor.484 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]485 #[transactional]486 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {487 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);488489 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;490 target_collection.check_is_owner(&sender)?;491492 target_collection.set_sponsor(new_sponsor.clone());493494 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(495 collection_id,496 new_sponsor497 ));498499 target_collection.save()500 }501502 /// # Permissions503 ///504 /// * Sponsor.505 ///506 /// # Arguments507 ///508 /// * collection_id.509 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]510 #[transactional]511 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {512 let sender = ensure_signed(origin)?;513514 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;515 ensure!(516 target_collection.confirm_sponsorship(&sender),517 Error::<T>::ConfirmUnsetSponsorFail518 );519520 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(521 collection_id,522 sender523 ));524525 target_collection.save()526 }527528 /// Switch back to pay-per-own-transaction model.529 ///530 /// # Permissions531 ///532 /// * Collection owner.533 ///534 /// # Arguments535 ///536 /// * collection_id.537 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]538 #[transactional]539 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {540 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);541542 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;543 target_collection.check_is_owner(&sender)?;544545 target_collection.sponsorship = SponsorshipState::Disabled;546547 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(548 collection_id549 ));550 target_collection.save()551 }552553 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.554 ///555 /// # Permissions556 ///557 /// * Collection Owner.558 /// * Collection Admin.559 /// * Anyone if560 /// * Allow List is enabled, and561 /// * Address is added to allow list, and562 /// * MintPermission is enabled (see SetMintPermission method)563 ///564 /// # Arguments565 ///566 /// * collection_id: ID of the collection.567 ///568 /// * owner: Address, initial owner of the NFT.569 ///570 /// * data: Token data to store on chain.571 #[weight = T::CommonWeightInfo::create_item()]572 #[transactional]573 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {574 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);575 let budget = budget::Value::new(NESTING_BUDGET);576577 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))578 }579580 /// This method creates multiple items in a collection created with CreateCollection method.581 ///582 /// # Permissions583 ///584 /// * Collection Owner.585 /// * Collection Admin.586 /// * Anyone if587 /// * Allow List is enabled, and588 /// * Address is added to allow list, and589 /// * MintPermission is enabled (see SetMintPermission method)590 ///591 /// # Arguments592 ///593 /// * collection_id: ID of the collection.594 ///595 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].596 ///597 /// * owner: Address, initial owner of the NFT.598 #[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]599 #[transactional]600 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {601 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);602 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);603 let budget = budget::Value::new(NESTING_BUDGET);604605 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))606 }607608 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]609 #[transactional]610 pub fn set_collection_properties(611 origin,612 collection_id: CollectionId,613 properties: Vec<Property>614 ) -> DispatchResultWithPostInfo {615 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);616617 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);618619 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))620 }621622 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]623 #[transactional]624 pub fn delete_collection_properties(625 origin,626 collection_id: CollectionId,627 property_keys: Vec<PropertyKey>,628 ) -> DispatchResultWithPostInfo {629 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);630631 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);632633 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))634 }635636 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]637 #[transactional]638 pub fn set_token_properties(639 origin,640 collection_id: CollectionId,641 token_id: TokenId,642 properties: Vec<Property>643 ) -> DispatchResultWithPostInfo {644 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);645646 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);647648 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))649 }650651 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]652 #[transactional]653 pub fn delete_token_properties(654 origin,655 collection_id: CollectionId,656 token_id: TokenId,657 property_keys: Vec<PropertyKey>658 ) -> DispatchResultWithPostInfo {659 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);660661 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);662663 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))664 }665666 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]667 #[transactional]668 pub fn set_property_permissions(669 origin,670 collection_id: CollectionId,671 property_permissions: Vec<PropertyKeyPermission>,672 ) -> DispatchResultWithPostInfo {673 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);674675 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);676677 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))678 }679680 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]681 #[transactional]682 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {683 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);684 let budget = budget::Value::new(NESTING_BUDGET);685686 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))687 }688689 // TODO! transaction weight690691 /// Set transfers_enabled value for particular collection692 ///693 /// # Permissions694 ///695 /// * Collection Owner.696 ///697 /// # Arguments698 ///699 /// * collection_id: ID of the collection.700 ///701 /// * value: New flag value.702 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]703 #[transactional]704 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {705 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);706 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;707 target_collection.check_is_owner(&sender)?;708709 // =========710711 target_collection.limits.transfers_enabled = Some(value);712 target_collection.save()713 }714715 /// Destroys a concrete instance of NFT.716 ///717 /// # Permissions718 ///719 /// * Collection Owner.720 /// * Collection Admin.721 /// * Current NFT Owner.722 ///723 /// # Arguments724 ///725 /// * collection_id: ID of the collection.726 ///727 /// * item_id: ID of NFT to burn.728 #[weight = T::CommonWeightInfo::burn_item()]729 #[transactional]730 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {731 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);732733 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;734 if value == 1 {735 <NftTransferBasket<T>>::remove(collection_id, item_id);736 <NftApproveBasket<T>>::remove(collection_id, item_id);737 }738 // Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?739 // <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());740 // <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));741 Ok(post_info)742 }743744 /// Destroys a concrete instance of NFT on behalf of the owner745 /// See also: [`approve`]746 ///747 /// # Permissions748 ///749 /// * Collection Owner.750 /// * Collection Admin.751 /// * Current NFT Owner.752 ///753 /// # Arguments754 ///755 /// * collection_id: ID of the collection.756 ///757 /// * item_id: ID of NFT to burn.758 ///759 /// * from: owner of item760 #[weight = T::CommonWeightInfo::burn_from()]761 #[transactional]762 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {763 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);764 let budget = budget::Value::new(NESTING_BUDGET);765766 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))767 }768769 /// Change ownership of the token.770 ///771 /// # Permissions772 ///773 /// * Collection Owner774 /// * Collection Admin775 /// * Current NFT owner776 ///777 /// # Arguments778 ///779 /// * recipient: Address of token recipient.780 ///781 /// * collection_id.782 ///783 /// * item_id: ID of the item784 /// * Non-Fungible Mode: Required.785 /// * Fungible Mode: Ignored.786 /// * Re-Fungible Mode: Required.787 ///788 /// * value: Amount to transfer.789 /// * Non-Fungible Mode: Ignored790 /// * Fungible Mode: Must specify transferred amount791 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)792 #[weight = T::CommonWeightInfo::transfer()]793 #[transactional]794 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {795 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);796 let budget = budget::Value::new(NESTING_BUDGET);797798 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))799 }800801 /// Set, change, or remove approved address to transfer the ownership of the NFT.802 ///803 /// # Permissions804 ///805 /// * Collection Owner806 /// * Collection Admin807 /// * Current NFT owner808 ///809 /// # Arguments810 ///811 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).812 ///813 /// * collection_id.814 ///815 /// * item_id: ID of the item.816 #[weight = T::CommonWeightInfo::approve()]817 #[transactional]818 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {819 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);820821 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))822 }823824 /// 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.825 ///826 /// # Permissions827 /// * Collection Owner828 /// * Collection Admin829 /// * Current NFT owner830 /// * Address approved by current NFT owner831 ///832 /// # Arguments833 ///834 /// * from: Address that owns token.835 ///836 /// * recipient: Address of token recipient.837 ///838 /// * collection_id.839 ///840 /// * item_id: ID of the item.841 ///842 /// * value: Amount to transfer.843 #[weight = T::CommonWeightInfo::transfer_from()]844 #[transactional]845 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {846 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);847 let budget = budget::Value::new(NESTING_BUDGET);848849 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))850 }851852 #[weight = <SelfWeightOf<T>>::set_collection_limits()]853 #[transactional]854 pub fn set_collection_limits(855 origin,856 collection_id: CollectionId,857 new_limit: CollectionLimits,858 ) -> DispatchResult {859 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);860 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;861 target_collection.check_is_owner(&sender)?;862 let old_limit = &target_collection.limits;863864 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;865866 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(867 collection_id868 ));869870 target_collection.save()871 }872873 #[weight = <SelfWeightOf<T>>::set_collection_limits()]874 #[transactional]875 pub fn set_collection_permissions(876 origin,877 collection_id: CollectionId,878 new_limit: CollectionPermissions,879 ) -> DispatchResult {880 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);881 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;882 target_collection.check_is_owner(&sender)?;883 let old_limit = &target_collection.permissions;884885 target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_limit)?;886887 <Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(888 collection_id889 ));890891 target_collection.save()892 }893 }894}runtime/opal/src/lib.rsdiffbeforeafterboth--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -917,6 +917,7 @@
type Event = Event;
type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
type CommonWeightInfo = CommonWeights<Self>;
+ type ContractAddress = EvmCollectionHelperAddress;
}
parameter_types! {
@@ -987,10 +988,6 @@
impl pallet_evm_contract_helpers::Config for Runtime {
type ContractAddress = HelpersContractAddress;
type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-impl pallet_unique::eth::Config for Runtime {
- type ContractAddress = EvmCollectionHelperAddress;
}
construct_runtime!(
runtime/quartz/src/lib.rsdiffbeforeafterboth--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -900,6 +900,7 @@
type Event = Event;
type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
type CommonWeightInfo = CommonWeights<Self>;
+ type ContractAddress = EvmCollectionHelperAddress;
}
parameter_types! {
@@ -970,10 +971,6 @@
impl pallet_evm_contract_helpers::Config for Runtime {
type ContractAddress = HelpersContractAddress;
type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-impl pallet_unique::eth::Config for Runtime {
- type ContractAddress = EvmCollectionHelperAddress;
}
construct_runtime!(
runtime/tests/src/lib.rsdiffbeforeafterboth--- a/runtime/tests/src/lib.rs
+++ b/runtime/tests/src/lib.rs
@@ -16,7 +16,7 @@
#![allow(clippy::from_over_into)]
-use sp_core::{H256, U256};
+use sp_core::{H160, H256, U256};
use frame_support::{
parameter_types,
traits::{Everything, ConstU32, ConstU64},
@@ -245,10 +245,18 @@
type WeightInfo = ();
}
+parameter_types! {
+ // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
+ pub const EvmCollectionHelperAddress: H160 = H160([
+ 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
+ ]);
+}
+
impl pallet_unique::Config for Test {
type Event = ();
type WeightInfo = ();
type CommonWeightInfo = CommonWeights<Self>;
+ type ContractAddress = EvmCollectionHelperAddress;
}
// Build genesis storage according to the mock runtime.
runtime/unique/src/lib.rsdiffbeforeafterboth--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -905,6 +905,7 @@
type Event = Event;
type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
type CommonWeightInfo = CommonWeights<Self>;
+ type ContractAddress = EvmCollectionHelperAddress;
}
parameter_types! {
@@ -975,10 +976,6 @@
impl pallet_evm_contract_helpers::Config for Runtime {
type ContractAddress = HelpersContractAddress;
type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-impl pallet_unique::eth::Config for Runtime {
- type ContractAddress = EvmCollectionHelperAddress;
}
construct_runtime!(