difftreelog
fix clippy warnings
in: master
36 files changed
node/cli/src/chain_spec.rsdiffbeforeafterboth--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -110,7 +110,7 @@
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
- TPublic::Pair::from_string(&format!("//{}", seed), None)
+ TPublic::Pair::from_string(&format!("//{seed}"), None)
.expect("static values are valid; qed")
.public()
}
node/cli/src/command.rsdiffbeforeafterboth--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -83,7 +83,7 @@
"" | "local" => Box::new(chain_spec::local_testnet_config()),
path => {
let path = std::path::PathBuf::from(path);
- let chain_spec = Box::new(chain_spec::OpalChainSpec::from_json_file(path.clone())?)
+ let chain_spec = Box::new(chain_spec::OpalChainSpec::from_json_file(path)?)
as Box<dyn sc_service::ChainSpec>;
match chain_spec.runtime_id() {
@@ -352,7 +352,7 @@
&polkadot_cli,
config.tokio_handle.clone(),
)
- .map_err(|err| format!("Relay chain argument error: {}", err))?;
+ .map_err(|err| format!("Relay chain argument error: {err}"))?;
cmd.run(config, polkadot_config)
})
@@ -464,7 +464,7 @@
runner.run_node_until_exit(|config| async move {
let hwbench = if !cli.no_hardware_benchmarks {
config.database.path().map(|database_path| {
- let _ = std::fs::create_dir_all(&database_path);
+ let _ = std::fs::create_dir_all(database_path);
sc_sysinfo::gather_hwbench(Some(database_path))
})
} else {
@@ -513,7 +513,7 @@
let state_version =
RelayChainCli::native_runtime_version(&config.chain_spec).state_version();
let block: Block = generate_genesis_block(&*config.chain_spec, state_version)
- .map_err(|e| format!("{:?}", e))?;
+ .map_err(|e| format!("{e:?}"))?;
let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode()));
let genesis_hash = format!("0x{:?}", HexDisplay::from(&block.header().hash().0));
@@ -522,7 +522,7 @@
&polkadot_cli,
config.tokio_handle.clone(),
)
- .map_err(|err| format!("Relay chain argument error: {}", err))?;
+ .map_err(|err| format!("Relay chain argument error: {err}"))?;
info!("Parachain id: {:?}", para_id);
info!("Parachain Account: {}", parachain_account);
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -698,7 +698,7 @@
{
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
- let block_import = ParachainBlockImport::new(client.clone(), backend.clone());
+ let block_import = ParachainBlockImport::new(client.clone(), backend);
cumulus_client_consensus_aura::import_queue::<
sp_consensus_aura::sr25519::AuthorityPair,
@@ -709,7 +709,7 @@
_,
>(cumulus_client_consensus_aura::ImportQueueParams {
block_import,
- client: client.clone(),
+ client,
create_inherent_data_providers: move |_, _| async move {
let time = sp_timestamp::InherentDataProvider::from_system_time();
@@ -787,7 +787,7 @@
telemetry.clone(),
);
- let block_import = ParachainBlockImport::new(client.clone(), backend.clone());
+ let block_import = ParachainBlockImport::new(client.clone(), backend);
Ok(AuraConsensus::build::<
sp_consensus_aura::sr25519::AuthorityPair,
@@ -864,7 +864,7 @@
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
Ok(sc_consensus_manual_seal::import_queue(
- Box::new(client.clone()),
+ Box::new(client),
&task_manager.spawn_essential_handle(),
config.prometheus_registry(),
))
@@ -956,7 +956,7 @@
let collator = config.role.is_authority();
- let select_chain = maybe_select_chain.clone();
+ let select_chain = maybe_select_chain;
if collator {
let block_import =
node/rpc/src/lib.rsdiffbeforeafterboth--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -289,7 +289,7 @@
io.merge(
Net::new(
client.clone(),
- network.clone(),
+ network,
// Whether to format the `peer_count` response as Hex (default) or not.
true,
)
pallets/app-promotion/src/lib.rsdiffbeforeafterboth--- a/pallets/app-promotion/src/lib.rs
+++ b/pallets/app-promotion/src/lib.rs
@@ -296,7 +296,7 @@
if !block_pending.is_empty() {
block_pending.into_iter().for_each(|(staker, amount)| {
- Self::get_frozen_balance(&staker).map(|b| {
+ if let Some(b) = Self::get_frozen_balance(&staker) {
let new_state = b.checked_sub(&amount).unwrap_or_default();
// In this case, setting a new state for the frozen funds cannot fail
@@ -305,7 +305,7 @@
// that we cannot (in the current implementation) unfreeze more funds
// than were originally frozen by the pallet. Either way, `on_initialize()` cannot fail.
Self::set_freeze_unchecked(&staker, new_state);
- });
+ };
});
}
@@ -598,8 +598,8 @@
// this value is set for the stakers to whom the recalculation will be performed
let next_recalc_block = current_recalc_block + config.recalculation_interval;
- let mut storage_iterator = Self::get_next_calculated_key()
- .map_or(Staked::<T>::iter(), |key| Staked::<T>::iter_from(key));
+ let storage_iterator =
+ Self::get_next_calculated_key().map_or(Staked::<T>::iter(), Staked::<T>::iter_from);
PreviousCalculatedRecord::<T>::set(None);
@@ -658,10 +658,8 @@
// stakers_number - keeps the remaining number of iterations (staker addresses to handle)
// next_recalc_block_for_stake - is taken from the state and stores the starting relay block from which reward should be paid out
// income_acc - stores the reward amount to pay to the staker address (accumulates over all address stake records)
- while let Some((
- (current_id, staked_block),
- (amount, next_recalc_block_for_stake),
- )) = storage_iterator.next()
+ for ((current_id, staked_block), (amount, next_recalc_block_for_stake)) in
+ storage_iterator
{
// last_id is not equal current_id when we switch to handling a new staker address
// or just start handling the very first address. In the latter case last_id will be None and
@@ -859,11 +857,11 @@
if acc_amount < balance_per_block {
let res = (block, balance_per_block - acc_amount);
acc_amount = <BalanceOf<T>>::default();
- return Some(res);
+ Some(res)
} else {
acc_amount -= balance_per_block;
will_deleted_stakes_count += 1;
- return Some((block, <BalanceOf<T>>::default()));
+ Some((block, <BalanceOf<T>>::default()))
}
})
.collect::<Vec<_>>();
@@ -926,7 +924,7 @@
if amount.is_zero() {
<<T as Config>::Currency as MutateFreeze<T::AccountId>>::thaw(
&T::FreezeIdentifier::get(),
- &staker,
+ staker,
)
} else {
<<T as Config>::Currency as MutateFreeze<T::AccountId>>::set_freeze(
@@ -1026,10 +1024,10 @@
) {
let income = Self::calculate_income(base, iters);
- base.checked_add(&income).map(|res| {
+ if let Some(res) = base.checked_add(&income) {
<Staked<T>>::insert((staker, staked_block), (res, next_recalc_block));
*income_acc += income;
- });
+ };
}
fn calculate_income<I>(base: I, iters: u32) -> I
pallets/app-promotion/src/types.rsdiffbeforeafterboth--- a/pallets/app-promotion/src/types.rs
+++ b/pallets/app-promotion/src/types.rs
@@ -149,16 +149,16 @@
Self {
recalculation_interval: config
.recalculation_interval
- .unwrap_or_else(|| T::RecalculationInterval::get()),
+ .unwrap_or_else(T::RecalculationInterval::get),
pending_interval: config
.pending_interval
- .unwrap_or_else(|| T::PendingInterval::get()),
+ .unwrap_or_else(T::PendingInterval::get),
interval_income: config
.interval_income
- .unwrap_or_else(|| T::IntervalIncome::get()),
+ .unwrap_or_else(T::IntervalIncome::get),
max_stakers_per_calculation: config
.max_stakers_per_calculation
- .unwrap_or_else(|| MAX_NUMBER_PAYOUTS),
+ .unwrap_or(MAX_NUMBER_PAYOUTS),
}
}
}
pallets/balances-adapter/src/lib.rsdiffbeforeafterboth--- a/pallets/balances-adapter/src/lib.rs
+++ b/pallets/balances-adapter/src/lib.rs
@@ -31,6 +31,12 @@
}
}
+impl<T: Config> Default for NativeFungibleHandle<T> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
impl<T: Config> WithRecorder<T> for NativeFungibleHandle<T> {
fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
&self.0
pallets/common/src/eth.rsdiffbeforeafterboth--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -136,7 +136,7 @@
fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {
let key = evm_coder::types::String::from_utf8(from.key.into())
- .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;
+ .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {e}")))?;
let value = evm_coder::types::Bytes(from.value.to_vec());
Ok(Property { key, value })
}
@@ -201,10 +201,7 @@
pub fn new(field: CollectionLimitField, value: Option<u32>) -> Self {
Self {
field,
- value: match value {
- Some(value) => Some(value.into()),
- None => None,
- },
+ value: value.map(|value| value.into()),
}
}
/// Whether the field contains a value.
@@ -222,8 +219,7 @@
.ok_or::<Self::Error>("can't convert `None` value to boolean".into())?;
let value = Some(value.try_into().map_err(|error| {
Self::Error::Revert(format!(
- "can't convert value to u32 \"{}\" because: \"{error}\"",
- value
+ "can't convert value to u32 \"{value}\" because: \"{error}\""
))
})?);
@@ -249,10 +245,8 @@
limits.sponsored_data_size = value;
}
CollectionLimitField::SponsoredDataRateLimit => {
- limits.sponsored_data_rate_limit = match value {
- Some(value) => Some(up_data_structs::SponsoringRateLimit::Blocks(value)),
- None => None,
- };
+ limits.sponsored_data_rate_limit =
+ value.map(up_data_structs::SponsoringRateLimit::Blocks);
}
CollectionLimitField::TokenLimit => {
limits.token_limit = value;
@@ -454,9 +448,9 @@
}
}
-impl Into<up_data_structs::AccessMode> for AccessMode {
- fn into(self) -> up_data_structs::AccessMode {
- match self {
+impl From<AccessMode> for up_data_structs::AccessMode {
+ fn from(value: AccessMode) -> Self {
+ match value {
AccessMode::Normal => up_data_structs::AccessMode::Normal,
AccessMode::AllowList => up_data_structs::AccessMode::AllowList,
}
pallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-coder-substrate/src/lib.rs
+++ b/pallets/evm-coder-substrate/src/lib.rs
@@ -260,9 +260,9 @@
message: Some(msg), ..
}) => ExError::Revert(msg.into()),
DispatchError::Module(ModuleError { index, error, .. }) => {
- ExError::Revert(format!("error {:?} in pallet {}", error, index))
+ ExError::Revert(format!("error {error:?} in pallet {index}"))
}
- e => ExError::Revert(format!("substrate error: {:?}", e)),
+ e => ExError::Revert(format!("substrate error: {e:?}")),
}
}
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -184,10 +184,9 @@
/// @param contractAddress The contract for which a sponsor is requested.
/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
fn sponsor(&self, contract_address: Address) -> Result<Option<eth::CrossAddress>> {
- Ok(match Pallet::<T>::get_sponsor(contract_address) {
- Some(ref value) => Some(eth::CrossAddress::from_sub_cross_account::<T>(value)),
- None => None,
- })
+ Ok(Pallet::<T>::get_sponsor(contract_address)
+ .as_ref()
+ .map(eth::CrossAddress::from_sub_cross_account::<T>))
}
/// Check tat contract has confirmed sponsor.
@@ -275,7 +274,7 @@
self.recorder().consume_sstore()?;
<Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;
- <Pallet<T>>::set_sponsoring_fee_limit(contract_address, fee_limit.into())
+ <Pallet<T>>::set_sponsoring_fee_limit(contract_address, fee_limit)
.map_err(dispatch_to_evm::<T>)?;
Ok(())
}
pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -376,7 +376,7 @@
<SponsoringMode<T>>::get(contract)
.or_else(|| {
#[allow(deprecated)]
- <SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)
+ <SelfSponsoring<T>>::get(contract).then_some(SponsoringModeT::Allowlisted)
})
.unwrap_or_default()
}
@@ -410,7 +410,7 @@
/// Is user added to allowlist, or he is owner of specified contract
pub fn allowed(contract: H160, user: H160) -> bool {
- <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user
+ <Allowlist<T>>::get(contract, user) || <Owner<T>>::get(contract) == user
}
/// Toggle contract allowlist access
@@ -425,7 +425,7 @@
/// Throw error if user is not allowed to reconfigure target contract
pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {
- ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);
+ ensure!(<Owner<T>>::get(contract) == user, Error::<T>::NoPermission);
Ok(())
}
}
pallets/evm-migration/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-migration/src/lib.rs
+++ b/pallets/evm-migration/src/lib.rs
@@ -78,7 +78,7 @@
pub fn begin(origin: OriginFor<T>, address: H160) -> DispatchResult {
ensure_root(origin)?;
ensure!(
- <PalletEvm<T>>::is_account_empty(&address) && !<MigrationPending<T>>::get(&address),
+ <PalletEvm<T>>::is_account_empty(&address) && !<MigrationPending<T>>::get(address),
<Error<T>>::AccountNotEmpty,
);
@@ -97,12 +97,12 @@
) -> DispatchResult {
ensure_root(origin)?;
ensure!(
- <MigrationPending<T>>::get(&address),
+ <MigrationPending<T>>::get(address),
<Error<T>>::AccountIsNotMigrating,
);
for (k, v) in data {
- <pallet_evm::AccountStorages<T>>::insert(&address, k, v);
+ <pallet_evm::AccountStorages<T>>::insert(address, k, v);
}
Ok(())
}
@@ -115,11 +115,11 @@
pub fn finish(origin: OriginFor<T>, address: H160, code: Vec<u8>) -> DispatchResult {
ensure_root(origin)?;
ensure!(
- <MigrationPending<T>>::get(&address),
+ <MigrationPending<T>>::get(address),
<Error<T>>::AccountIsNotMigrating,
);
- <pallet_evm::AccountCodes<T>>::insert(&address, code);
+ <pallet_evm::AccountCodes<T>>::insert(address, code);
<MigrationPending<T>>::remove(address);
Ok(())
}
@@ -166,7 +166,7 @@
pub struct OnMethodCall<T>(PhantomData<T>);
impl<T: Config> pallet_evm::OnMethodCall<T> for OnMethodCall<T> {
fn is_reserved(contract: &H160) -> bool {
- <MigrationPending<T>>::get(&contract)
+ <MigrationPending<T>>::get(contract)
}
fn is_used(_contract: &H160) -> bool {
pallets/foreign-assets/src/impl_fungibles.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/impl_fungibles.rs
+++ b/pallets/foreign-assets/src/impl_fungibles.rs
@@ -333,7 +333,7 @@
&Value::new(0),
)?;
- Ok(amount.into())
+ Ok(amount)
}
}
}
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/lib.rs
+++ b/pallets/foreign-assets/src/lib.rs
@@ -161,7 +161,7 @@
fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {
log::trace!(target: "fassets::get_currency_id", "call");
- Pallet::<T>::location_to_currency_ids(multi_location).map(|id| AssetIds::ForeignAssetId(id))
+ Pallet::<T>::location_to_currency_ids(multi_location).map(AssetIds::ForeignAssetId)
}
}
@@ -378,7 +378,7 @@
foreign_asset_id,
|maybe_location| -> DispatchResult {
ensure!(maybe_location.is_none(), Error::<T>::MultiLocationExisted);
- *maybe_location = Some(location.clone());
+ *maybe_location = Some(*location);
AssetMetadatas::<T>::try_mutate(
AssetIds::ForeignAssetId(foreign_asset_id),
@@ -422,7 +422,7 @@
// modify location
if location != old_multi_locations {
- LocationToCurrencyIds::<T>::remove(old_multi_locations.clone());
+ LocationToCurrencyIds::<T>::remove(*old_multi_locations);
LocationToCurrencyIds::<T>::try_mutate(
location,
|maybe_currency_ids| -> DispatchResult {
@@ -437,7 +437,7 @@
)?;
}
*maybe_asset_metadatas = Some(metadata.clone());
- *old_multi_locations = location.clone();
+ *old_multi_locations = *location;
Ok(())
},
)
pallets/identity/src/types.rsdiffbeforeafterboth--- a/pallets/identity/src/types.rs
+++ b/pallets/identity/src/types.rs
@@ -104,7 +104,7 @@
Data::Raw(ref x) => {
let l = x.len().min(32);
let mut r = vec![l as u8 + 1; l + 1];
- r[1..].copy_from_slice(&x[..l as usize]);
+ r[1..].copy_from_slice(&x[..l]);
r
}
Data::BlakeTwo256(ref h) => once(34u8).chain(h.iter().cloned()).collect(),
@@ -287,7 +287,7 @@
fn decode<I: codec::Input>(input: &mut I) -> sp_std::result::Result<Self, codec::Error> {
let field = u64::decode(input)?;
Ok(Self(
- <BitFlags<IdentityField>>::from_bits(field as u64).map_err(|_| "invalid value")?,
+ <BitFlags<IdentityField>>::from_bits(field).map_err(|_| "invalid value")?,
))
}
}
pallets/nonfungible/src/erc.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//! # Nonfungible Pallet EVM API18//!19//! Provides ERC-721 standart support implementation and EVM API for unique extensions for Nonfungible Pallet.20//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.2122extern crate alloc;23use core::{24 char::{REPLACEMENT_CHARACTER, decode_utf16},25 convert::TryInto,26};27use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};28use frame_support::BoundedVec;29use up_data_structs::{30 TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,31 CollectionPropertiesVec,32};33use pallet_evm_coder_substrate::{34 dispatch_to_evm, frontier_contract,35 execution::{Result, PreDispatch, Error},36};37use sp_std::{vec::Vec, vec};38use pallet_common::{39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},41 eth::{self, TokenUri},42 CommonWeightInfo,43};44use pallet_evm::{account::CrossAccountId, PrecompileHandle};45use pallet_evm_coder_substrate::call;46use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};47use sp_core::{U256, Get};4849use crate::{50 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,51 TokenProperties, SelfWeightOf, weights::WeightInfo, common::CommonWeights,52};5354/// Nft events.55#[derive(ToLog)]56pub enum ERC721TokenEvent {57 /// The token has been changed.58 TokenChanged {59 /// Token ID.60 #[indexed]61 token_id: U256,62 },63}6465frontier_contract! {66 macro_rules! NonfungibleHandle_result {...}67 impl<T: Config> Contract for NonfungibleHandle<T> {...}68}6970/// @title A contract that allows to set and delete token properties and change token property permissions.71#[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))]72impl<T: Config> NonfungibleHandle<T> {73 /// @notice Set permissions for token property.74 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.75 /// @param key Property key.76 /// @param isMutable Permission to mutate property.77 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.78 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.79 #[solidity(hide)]80 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]81 fn set_token_property_permission(82 &mut self,83 caller: Caller,84 key: String,85 is_mutable: bool,86 collection_admin: bool,87 token_owner: bool,88 ) -> Result<()> {89 let caller = T::CrossAccountId::from_eth(caller);90 <Pallet<T>>::set_token_property_permissions(91 self,92 &caller,93 vec![PropertyKeyPermission {94 key: <Vec<u8>>::from(key)95 .try_into()96 .map_err(|_| "too long key")?,97 permission: PropertyPermission {98 mutable: is_mutable,99 collection_admin,100 token_owner,101 },102 }],103 )104 .map_err(dispatch_to_evm::<T>)105 }106107 /// @notice Set permissions for token property.108 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.109 /// @param permissions Permissions for keys.110 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]111 fn set_token_property_permissions(112 &mut self,113 caller: Caller,114 permissions: Vec<eth::TokenPropertyPermission>,115 ) -> Result<()> {116 let caller = T::CrossAccountId::from_eth(caller);117 let perms = eth::TokenPropertyPermission::into_property_key_permissions(permissions)?;118119 <Pallet<T>>::set_token_property_permissions(self, &caller, perms)120 .map_err(dispatch_to_evm::<T>)121 }122123 /// @notice Get permissions for token properties.124 fn token_property_permissions(&self) -> Result<Vec<eth::TokenPropertyPermission>> {125 let perms = <Pallet<T>>::token_property_permission(self.id);126 Ok(perms127 .into_iter()128 .map(eth::TokenPropertyPermission::from)129 .collect())130 }131132 /// @notice Set token property value.133 /// @dev Throws error if `msg.sender` has no permission to edit the property.134 /// @param tokenId ID of the token.135 /// @param key Property key.136 /// @param value Property value.137 #[solidity(hide)]138 #[weight(<SelfWeightOf<T>>::set_token_properties(1))]139 fn set_property(140 &mut self,141 caller: Caller,142 token_id: U256,143 key: String,144 value: Bytes,145 ) -> Result<()> {146 let caller = T::CrossAccountId::from_eth(caller);147 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;148 let key = <Vec<u8>>::from(key)149 .try_into()150 .map_err(|_| "key too long")?;151 let value = value.0.try_into().map_err(|_| "value too long")?;152153 let nesting_budget = self154 .recorder155 .weight_calls_budget(<StructureWeight<T>>::find_parent());156157 <Pallet<T>>::set_token_property(158 self,159 &caller,160 TokenId(token_id),161 Property { key, value },162 &nesting_budget,163 )164 .map_err(dispatch_to_evm::<T>)165 }166167 /// @notice Set token properties value.168 /// @dev Throws error if `msg.sender` has no permission to edit the property.169 /// @param tokenId ID of the token.170 /// @param properties settable properties171 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]172 fn set_properties(173 &mut self,174 caller: Caller,175 token_id: U256,176 properties: Vec<eth::Property>,177 ) -> Result<()> {178 let caller = T::CrossAccountId::from_eth(caller);179 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;180181 let nesting_budget = self182 .recorder183 .weight_calls_budget(<StructureWeight<T>>::find_parent());184185 let properties = properties186 .into_iter()187 .map(eth::Property::try_into)188 .collect::<Result<Vec<_>>>()?;189190 <Pallet<T>>::set_token_properties(191 self,192 &caller,193 TokenId(token_id),194 properties.into_iter(),195 false,196 &nesting_budget,197 )198 .map_err(dispatch_to_evm::<T>)199 }200201 /// @notice Delete token property value.202 /// @dev Throws error if `msg.sender` has no permission to edit the property.203 /// @param tokenId ID of the token.204 /// @param key Property key.205 #[solidity(hide)]206 #[weight(<SelfWeightOf<T>>::delete_token_properties(1))]207 fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> {208 let caller = T::CrossAccountId::from_eth(caller);209 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;210 let key = <Vec<u8>>::from(key)211 .try_into()212 .map_err(|_| "key too long")?;213214 let nesting_budget = self215 .recorder216 .weight_calls_budget(<StructureWeight<T>>::find_parent());217218 <Pallet<T>>::delete_token_property(self, &caller, TokenId(token_id), key, &nesting_budget)219 .map_err(dispatch_to_evm::<T>)220 }221222 /// @notice Delete token properties value.223 /// @dev Throws error if `msg.sender` has no permission to edit the property.224 /// @param tokenId ID of the token.225 /// @param keys Properties key.226 #[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]227 fn delete_properties(228 &mut self,229 token_id: U256,230 caller: Caller,231 keys: Vec<String>,232 ) -> Result<()> {233 let caller = T::CrossAccountId::from_eth(caller);234 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;235 let keys = keys236 .into_iter()237 .map(|k| Ok(<Vec<u8>>::from(k).try_into().map_err(|_| "key too long")?))238 .collect::<Result<Vec<_>>>()?;239240 let nesting_budget = self241 .recorder242 .weight_calls_budget(<StructureWeight<T>>::find_parent());243244 <Pallet<T>>::delete_token_properties(245 self,246 &caller,247 TokenId(token_id),248 keys.into_iter(),249 &nesting_budget,250 )251 .map_err(dispatch_to_evm::<T>)252 }253254 /// @notice Get token property value.255 /// @dev Throws error if key not found256 /// @param tokenId ID of the token.257 /// @param key Property key.258 /// @return Property value bytes259 fn property(&self, token_id: U256, key: String) -> Result<Bytes> {260 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;261 let key = <Vec<u8>>::from(key)262 .try_into()263 .map_err(|_| "key too long")?;264265 let props = <TokenProperties<T>>::get((self.id, token_id));266 let prop = props.get(&key).ok_or("key not found")?;267268 Ok(prop.to_vec().into())269 }270}271272#[derive(ToLog)]273pub enum ERC721Events {274 /// @dev This emits when ownership of any NFT changes by any mechanism.275 /// This event emits when NFTs are created (`from` == 0) and destroyed276 /// (`to` == 0). Exception: during contract creation, any number of NFTs277 /// may be created and assigned without emitting Transfer. At the time of278 /// any transfer, the approved address for that NFT (if any) is reset to none.279 Transfer {280 #[indexed]281 from: Address,282 #[indexed]283 to: Address,284 #[indexed]285 token_id: U256,286 },287 /// @dev This emits when the approved address for an NFT is changed or288 /// reaffirmed. The zero address indicates there is no approved address.289 /// When a Transfer event emits, this also indicates that the approved290 /// address for that NFT (if any) is reset to none.291 Approval {292 #[indexed]293 owner: Address,294 #[indexed]295 approved: Address,296 #[indexed]297 token_id: U256,298 },299 /// @dev This emits when an operator is enabled or disabled for an owner.300 /// The operator can manage all NFTs of the owner.301 #[allow(dead_code)]302 ApprovalForAll {303 #[indexed]304 owner: Address,305 #[indexed]306 operator: Address,307 approved: bool,308 },309}310311/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension312/// @dev See https://eips.ethereum.org/EIPS/eip-721313#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f, enum(derive(PreDispatch)), enum_attr(weight))]314impl<T: Config> NonfungibleHandle<T>315where316 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,317{318 /// @notice A descriptive name for a collection of NFTs in this contract319 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`320 #[solidity(hide, rename_selector = "name")]321 fn name_proxy(&self) -> String {322 self.name()323 }324325 /// @notice An abbreviated name for NFTs in this contract326 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`327 #[solidity(hide, rename_selector = "symbol")]328 fn symbol_proxy(&self) -> String {329 self.symbol()330 }331332 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.333 ///334 /// @dev If the token has a `url` property and it is not empty, it is returned.335 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.336 /// If the collection property `baseURI` is empty or absent, return "" (empty string)337 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix338 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).339 ///340 /// @return token's const_metadata341 #[solidity(rename_selector = "tokenURI")]342 fn token_uri(&self, token_id: U256) -> Result<String> {343 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;344345 match get_token_property(self, token_id_u32, &key::url()).as_deref() {346 Err(_) | Ok("") => (),347 Ok(url) => {348 return Ok(url.into());349 }350 };351352 let base_uri =353 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())354 .map(BoundedVec::into_inner)355 .map(String::from_utf8)356 .transpose()357 .map_err(|e| {358 Error::Revert(alloc::format!(359 "Can not convert value \"baseURI\" to string with error \"{}\"",360 e361 ))362 })?;363364 let base_uri = match base_uri.as_deref() {365 None | Some("") => {366 return Ok("".into());367 }368 Some(base_uri) => base_uri.into(),369 };370371 Ok(372 match get_token_property(self, token_id_u32, &key::suffix()).as_deref() {373 Err(_) | Ok("") => base_uri,374 Ok(suffix) => base_uri + suffix,375 },376 )377 }378}379380/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension381/// @dev See https://eips.ethereum.org/EIPS/eip-721382#[solidity_interface(name = ERC721Enumerable, expect_selector = 0x780e9d63, enum(derive(PreDispatch)), enum_attr(weight))]383impl<T: Config> NonfungibleHandle<T> {384 /// @notice Enumerate valid NFTs385 /// @param index A counter less than `totalSupply()`386 /// @return The token identifier for the `index`th NFT,387 /// (sort order not specified)388 fn token_by_index(&self, index: U256) -> U256 {389 index390 }391392 /// @dev Not implemented393 fn token_of_owner_by_index(&self, _owner: Address, _index: U256) -> Result<U256> {394 // TODO: Not implemetable395 Err("not implemented".into())396 }397398 /// @notice Count NFTs tracked by this contract399 /// @return A count of valid NFTs tracked by this contract, where each one of400 /// them has an assigned and queryable owner not equal to the zero address401 fn total_supply(&self) -> Result<U256> {402 self.consume_store_reads(1)?;403 Ok(<Pallet<T>>::total_supply(self).into())404 }405}406407/// @title ERC-721 Non-Fungible Token Standard408/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md409#[solidity_interface(name = ERC721, events(ERC721Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x80ac58cd)]410impl<T: Config> NonfungibleHandle<T> {411 /// @notice Count all NFTs assigned to an owner412 /// @dev NFTs assigned to the zero address are considered invalid, and this413 /// function throws for queries about the zero address.414 /// @param owner An address for whom to query the balance415 /// @return The number of NFTs owned by `owner`, possibly zero416 fn balance_of(&self, owner: Address) -> Result<U256> {417 self.consume_store_reads(1)?;418 let owner = T::CrossAccountId::from_eth(owner);419 let balance = <AccountBalance<T>>::get((self.id, owner));420 Ok(balance.into())421 }422 /// @notice Find the owner of an NFT423 /// @dev NFTs assigned to zero address are considered invalid, and queries424 /// about them do throw.425 /// @param tokenId The identifier for an NFT426 /// @return The address of the owner of the NFT427 fn owner_of(&self, token_id: U256) -> Result<Address> {428 self.consume_store_reads(1)?;429 let token: TokenId = token_id.try_into()?;430 Ok(*<TokenData<T>>::get((self.id, token))431 .ok_or("token not found")?432 .owner433 .as_eth())434 }435 /// @dev Not implemented436 #[solidity(rename_selector = "safeTransferFrom")]437 fn safe_transfer_from_with_data(438 &mut self,439 _from: Address,440 _to: Address,441 _token_id: U256,442 _data: Bytes,443 ) -> Result<()> {444 // TODO: Not implemetable445 Err("not implemented".into())446 }447 /// @dev Not implemented448 fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {449 // TODO: Not implemetable450 Err("not implemented".into())451 }452453 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE454 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE455 /// THEY MAY BE PERMANENTLY LOST456 /// @dev Throws unless `msg.sender` is the current owner or an authorized457 /// operator for this NFT. Throws if `from` is not the current owner. Throws458 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.459 /// @param from The current owner of the NFT460 /// @param to The new owner461 /// @param tokenId The NFT to transfer462 #[weight(<CommonWeights<T>>::transfer_from())]463 fn transfer_from(464 &mut self,465 caller: Caller,466 from: Address,467 to: Address,468 token_id: U256,469 ) -> Result<()> {470 let caller = T::CrossAccountId::from_eth(caller);471 let from = T::CrossAccountId::from_eth(from);472 let to = T::CrossAccountId::from_eth(to);473 let token = token_id.try_into()?;474 let budget = self475 .recorder476 .weight_calls_budget(<StructureWeight<T>>::find_parent());477478 <Pallet<T>>::transfer_from(self, &caller, &from, &to, token, &budget)479 .map_err(|e| dispatch_to_evm::<T>(e.error))?;480 Ok(())481 }482483 /// @notice Set or reaffirm the approved address for an NFT484 /// @dev The zero address indicates there is no approved address.485 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized486 /// operator of the current owner.487 /// @param approved The new approved NFT controller488 /// @param tokenId The NFT to approve489 #[weight(<SelfWeightOf<T>>::approve())]490 fn approve(&mut self, caller: Caller, approved: Address, token_id: U256) -> Result<()> {491 let caller = T::CrossAccountId::from_eth(caller);492 let approved = T::CrossAccountId::from_eth(approved);493 let token = token_id.try_into()?;494495 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))496 .map_err(dispatch_to_evm::<T>)?;497 Ok(())498 }499500 /// @notice Sets or unsets the approval of a given operator.501 /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf.502 /// @param operator Operator503 /// @param approved Should operator status be granted or revoked?504 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]505 fn set_approval_for_all(506 &mut self,507 caller: Caller,508 operator: Address,509 approved: bool,510 ) -> Result<()> {511 let caller = T::CrossAccountId::from_eth(caller);512 let operator = T::CrossAccountId::from_eth(operator);513514 <Pallet<T>>::set_allowance_for_all(self, &caller, &operator, approved)515 .map_err(dispatch_to_evm::<T>)?;516 Ok(())517 }518519 /// @notice Get the approved address for a single NFT520 /// @dev Throws if `tokenId` is not a valid NFT521 /// @param tokenId The NFT to find the approved address for522 /// @return The approved address for this NFT, or the zero address if there is none523 fn get_approved(&self, token_id: U256) -> Result<Address> {524 let token_id = token_id.try_into()?;525 let operator = <Pallet<T>>::get_allowance(self, token_id).map_err(dispatch_to_evm::<T>)?;526 Ok(if let Some(operator) = operator {527 *operator.as_eth()528 } else {529 Address::zero()530 })531 }532533 /// @notice Tells whether the given `owner` approves the `operator`.534 #[weight(<SelfWeightOf<T>>::allowance_for_all())]535 fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {536 let owner = T::CrossAccountId::from_eth(owner);537 let operator = T::CrossAccountId::from_eth(operator);538539 Ok(<Pallet<T>>::allowance_for_all(self, &owner, &operator))540 }541}542543/// @title ERC721 Token that can be irreversibly burned (destroyed).544#[solidity_interface(name = ERC721Burnable, enum(derive(PreDispatch)), enum_attr(weight))]545impl<T: Config> NonfungibleHandle<T> {546 /// @notice Burns a specific ERC721 token.547 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized548 /// operator of the current owner.549 /// @param tokenId The NFT to approve550 #[weight(<SelfWeightOf<T>>::burn_item())]551 fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {552 let caller = T::CrossAccountId::from_eth(caller);553 let token = token_id.try_into()?;554555 <Pallet<T>>::burn(self, &caller, token).map_err(dispatch_to_evm::<T>)?;556 Ok(())557 }558}559560/// @title ERC721 minting logic.561#[solidity_interface(name = ERC721UniqueMintable, enum(derive(PreDispatch)), enum_attr(weight))]562impl<T: Config> NonfungibleHandle<T> {563 /// @notice Function to mint a token.564 /// @param to The new owner565 /// @return uint256 The id of the newly minted token566 #[weight(<SelfWeightOf<T>>::create_item())]567 fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {568 let token_id: U256 = <TokensMinted<T>>::get(self.id)569 .checked_add(1)570 .ok_or("item id overflow")?571 .into();572 self.mint_check_id(caller, to, token_id)?;573 Ok(token_id)574 }575576 /// @notice Function to mint a token.577 /// @dev `tokenId` should be obtained with `nextTokenId` method,578 /// unlike standard, you can't specify it manually579 /// @param to The new owner580 /// @param tokenId ID of the minted NFT581 #[solidity(hide, rename_selector = "mint")]582 #[weight(<SelfWeightOf<T>>::create_item())]583 fn mint_check_id(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<bool> {584 let caller = T::CrossAccountId::from_eth(caller);585 let to = T::CrossAccountId::from_eth(to);586 let token_id: u32 = token_id.try_into()?;587 let budget = self588 .recorder589 .weight_calls_budget(<StructureWeight<T>>::find_parent());590591 if <TokensMinted<T>>::get(self.id)592 .checked_add(1)593 .ok_or("item id overflow")?594 != token_id595 {596 return Err("item id should be next".into());597 }598599 <Pallet<T>>::create_item(600 self,601 &caller,602 CreateItemData::<T> {603 properties: BoundedVec::default(),604 owner: to,605 },606 &budget,607 )608 .map_err(dispatch_to_evm::<T>)?;609610 Ok(true)611 }612613 /// @notice Function to mint token with the given tokenUri.614 /// @param to The new owner615 /// @param tokenUri Token URI that would be stored in the NFT properties616 /// @return uint256 The id of the newly minted token617 #[solidity(rename_selector = "mintWithTokenURI")]618 #[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]619 fn mint_with_token_uri(620 &mut self,621 caller: Caller,622 to: Address,623 token_uri: String,624 ) -> Result<U256> {625 let token_id: U256 = <TokensMinted<T>>::get(self.id)626 .checked_add(1)627 .ok_or("item id overflow")?628 .into();629 self.mint_with_token_uri_check_id(caller, to, token_id, token_uri)?;630 Ok(token_id)631 }632633 /// @notice Function to mint token with the given tokenUri.634 /// @dev `tokenId` should be obtained with `nextTokenId` method,635 /// unlike standard, you can't specify it manually636 /// @param to The new owner637 /// @param tokenId ID of the minted NFT638 /// @param tokenUri Token URI that would be stored in the NFT properties639 #[solidity(hide, rename_selector = "mintWithTokenURI")]640 #[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]641 fn mint_with_token_uri_check_id(642 &mut self,643 caller: Caller,644 to: Address,645 token_id: U256,646 token_uri: String,647 ) -> Result<bool> {648 let key = key::url();649 let permission = get_token_permission::<T>(self.id, &key)?;650 if !permission.collection_admin {651 return Err("Operation is not allowed".into());652 }653654 let caller = T::CrossAccountId::from_eth(caller);655 let to = T::CrossAccountId::from_eth(to);656 let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;657 let budget = self658 .recorder659 .weight_calls_budget(<StructureWeight<T>>::find_parent());660661 if <TokensMinted<T>>::get(self.id)662 .checked_add(1)663 .ok_or("item id overflow")?664 != token_id665 {666 return Err("item id should be next".into());667 }668669 let mut properties = CollectionPropertiesVec::default();670 properties671 .try_push(Property {672 key,673 value: token_uri674 .into_bytes()675 .try_into()676 .map_err(|_| "token uri is too long")?,677 })678 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;679680 <Pallet<T>>::create_item(681 self,682 &caller,683 CreateItemData::<T> {684 properties,685 owner: to,686 },687 &budget,688 )689 .map_err(dispatch_to_evm::<T>)?;690 Ok(true)691 }692}693694fn get_token_property<T: Config>(695 collection: &CollectionHandle<T>,696 token_id: u32,697 key: &up_data_structs::PropertyKey,698) -> Result<String> {699 collection.consume_store_reads(1)?;700 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))701 .map_err(|_| Error::Revert("Token properties not found".into()))?;702 if let Some(property) = properties.get(key) {703 return Ok(String::from_utf8_lossy(property).into());704 }705706 Err("Property tokenURI not found".into())707}708709fn get_token_permission<T: Config>(710 collection_id: CollectionId,711 key: &PropertyKey,712) -> Result<PropertyPermission> {713 let token_property_permissions = CollectionPropertyPermissions::<T>::try_get(collection_id)714 .map_err(|_| Error::Revert("No permissions for collection".into()))?;715 let a = token_property_permissions716 .get(key)717 .map(Clone::clone)718 .ok_or_else(|| {719 let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();720 Error::Revert(alloc::format!("No permission for key {}", key))721 })?;722 Ok(a)723}724725/// @title Unique extensions for ERC721.726#[solidity_interface(name = ERC721UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]727impl<T: Config> NonfungibleHandle<T>728where729 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,730{731 /// @notice A descriptive name for a collection of NFTs in this contract732 fn name(&self) -> String {733 decode_utf16(self.name.iter().copied())734 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))735 .collect::<String>()736 }737738 /// @notice An abbreviated name for NFTs in this contract739 fn symbol(&self) -> String {740 String::from_utf8_lossy(&self.token_prefix).into()741 }742743 /// @notice A description for the collection.744 fn description(&self) -> String {745 decode_utf16(self.description.iter().copied())746 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))747 .collect::<String>()748 }749750 /// Returns the owner (in cross format) of the token.751 ///752 /// @param tokenId Id for the token.753 #[solidity(hide)]754 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {755 Self::owner_of_cross(&self, token_id)756 }757758 /// Returns the owner (in cross format) of the token.759 ///760 /// @param tokenId Id for the token.761 fn owner_of_cross(&self, token_id: U256) -> Result<eth::CrossAddress> {762 Self::token_owner(&self, token_id.try_into()?)763 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))764 .map_err(|_| Error::Revert("token not found".into()))765 }766767 /// @notice Count all NFTs assigned to an owner768 /// @param owner An cross address for whom to query the balance769 /// @return The number of NFTs owned by `owner`, possibly zero770 fn balance_of_cross(&self, owner: eth::CrossAddress) -> Result<U256> {771 self.consume_store_reads(1)?;772 let balance = <AccountBalance<T>>::get((self.id, owner.into_sub_cross_account::<T>()?));773 Ok(balance.into())774 }775776 /// Returns the token properties.777 ///778 /// @param tokenId Id for the token.779 /// @param keys Properties keys. Empty keys for all propertyes.780 /// @return Vector of properties key/value pairs.781 fn properties(&self, token_id: U256, keys: Vec<String>) -> Result<Vec<eth::Property>> {782 let keys = keys783 .into_iter()784 .map(|key| {785 <Vec<u8>>::from(key)786 .try_into()787 .map_err(|_| Error::Revert("key too large".into()))788 })789 .collect::<Result<Vec<_>>>()?;790791 <Self as CommonCollectionOperations<T>>::token_properties(792 &self,793 token_id.try_into()?,794 if keys.is_empty() { None } else { Some(keys) },795 )796 .into_iter()797 .map(eth::Property::try_from)798 .collect::<Result<Vec<_>>>()799 }800801 /// @notice Set or reaffirm the approved address for an NFT802 /// @dev The zero address indicates there is no approved address.803 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized804 /// operator of the current owner.805 /// @param approved The new substrate address approved NFT controller806 /// @param tokenId The NFT to approve807 #[weight(<SelfWeightOf<T>>::approve())]808 fn approve_cross(809 &mut self,810 caller: Caller,811 approved: eth::CrossAddress,812 token_id: U256,813 ) -> Result<()> {814 let caller = T::CrossAccountId::from_eth(caller);815 let approved = approved.into_sub_cross_account::<T>()?;816 let token = token_id.try_into()?;817818 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))819 .map_err(dispatch_to_evm::<T>)?;820 Ok(())821 }822823 /// @notice Transfer ownership of an NFT824 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`825 /// is the zero address. Throws if `tokenId` is not a valid NFT.826 /// @param to The new owner827 /// @param tokenId The NFT to transfer828 #[weight(<CommonWeights<T>>::transfer())]829 fn transfer(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<()> {830 let caller = T::CrossAccountId::from_eth(caller);831 let to = T::CrossAccountId::from_eth(to);832 let token = token_id.try_into()?;833 let budget = self834 .recorder835 .weight_calls_budget(<StructureWeight<T>>::find_parent());836837 <Pallet<T>>::transfer(self, &caller, &to, token, &budget)838 .map_err(|e| dispatch_to_evm::<T>(e.error))?;839 Ok(())840 }841842 /// @notice Transfer ownership of an NFT843 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`844 /// is the zero address. Throws if `tokenId` is not a valid NFT.845 /// @param to The new owner846 /// @param tokenId The NFT to transfer847 #[weight(<CommonWeights<T>>::transfer())]848 fn transfer_cross(849 &mut self,850 caller: Caller,851 to: eth::CrossAddress,852 token_id: U256,853 ) -> Result<()> {854 let caller = T::CrossAccountId::from_eth(caller);855 let to = to.into_sub_cross_account::<T>()?;856 let token = token_id.try_into()?;857 let budget = self858 .recorder859 .weight_calls_budget(<StructureWeight<T>>::find_parent());860861 <Pallet<T>>::transfer(self, &caller, &to, token, &budget)862 .map_err(|e| dispatch_to_evm::<T>(e.error))?;863 Ok(())864 }865866 /// @notice Transfer ownership of an NFT from cross account address to cross account address867 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`868 /// is the zero address. Throws if `tokenId` is not a valid NFT.869 /// @param from Cross acccount address of current owner870 /// @param to Cross acccount address of new owner871 /// @param tokenId The NFT to transfer872 #[weight(<CommonWeights<T>>::transfer_from())]873 fn transfer_from_cross(874 &mut self,875 caller: Caller,876 from: eth::CrossAddress,877 to: eth::CrossAddress,878 token_id: U256,879 ) -> Result<()> {880 let caller = T::CrossAccountId::from_eth(caller);881 let from = from.into_sub_cross_account::<T>()?;882 let to = to.into_sub_cross_account::<T>()?;883 let token_id = token_id.try_into()?;884 let budget = self885 .recorder886 .weight_calls_budget(<StructureWeight<T>>::find_parent());887 Pallet::<T>::transfer_from(self, &caller, &from, &to, token_id, &budget)888 .map_err(|e| dispatch_to_evm::<T>(e.error))?;889 Ok(())890 }891892 /// @notice Burns a specific ERC721 token.893 /// @dev Throws unless `msg.sender` is the current owner or an authorized894 /// operator for this NFT. Throws if `from` is not the current owner. Throws895 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.896 /// @param from The current owner of the NFT897 /// @param tokenId The NFT to transfer898 #[solidity(hide)]899 #[weight(<SelfWeightOf<T>>::burn_from())]900 fn burn_from(&mut self, caller: Caller, from: Address, token_id: U256) -> Result<()> {901 let caller = T::CrossAccountId::from_eth(caller);902 let from = T::CrossAccountId::from_eth(from);903 let token = token_id.try_into()?;904 let budget = self905 .recorder906 .weight_calls_budget(<StructureWeight<T>>::find_parent());907908 <Pallet<T>>::burn_from(self, &caller, &from, token, &budget)909 .map_err(dispatch_to_evm::<T>)?;910 Ok(())911 }912913 /// @notice Burns a specific ERC721 token.914 /// @dev Throws unless `msg.sender` is the current owner or an authorized915 /// operator for this NFT. Throws if `from` is not the current owner. Throws916 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.917 /// @param from The current owner of the NFT918 /// @param tokenId The NFT to transfer919 #[weight(<SelfWeightOf<T>>::burn_from())]920 fn burn_from_cross(921 &mut self,922 caller: Caller,923 from: eth::CrossAddress,924 token_id: U256,925 ) -> Result<()> {926 let caller = T::CrossAccountId::from_eth(caller);927 let from = from.into_sub_cross_account::<T>()?;928 let token = token_id.try_into()?;929 let budget = self930 .recorder931 .weight_calls_budget(<StructureWeight<T>>::find_parent());932933 <Pallet<T>>::burn_from(self, &caller, &from, token, &budget)934 .map_err(dispatch_to_evm::<T>)?;935 Ok(())936 }937938 /// @notice Returns next free NFT ID.939 fn next_token_id(&self) -> Result<U256> {940 self.consume_store_reads(1)?;941 Ok(<TokensMinted<T>>::get(self.id)942 .checked_add(1)943 .ok_or("item id overflow")?944 .into())945 }946947 /// @notice Function to mint multiple tokens.948 /// @dev `tokenIds` should be an array of consecutive numbers and first number949 /// should be obtained with `nextTokenId` method950 /// @param to The new owner951 /// @param tokenIds IDs of the minted NFTs952 #[solidity(hide)]953 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]954 fn mint_bulk(&mut self, caller: Caller, to: Address, token_ids: Vec<U256>) -> Result<bool> {955 let caller = T::CrossAccountId::from_eth(caller);956 let to = T::CrossAccountId::from_eth(to);957 let mut expected_index = <TokensMinted<T>>::get(self.id)958 .checked_add(1)959 .ok_or("item id overflow")?;960 let budget = self961 .recorder962 .weight_calls_budget(<StructureWeight<T>>::find_parent());963964 let total_tokens = token_ids.len();965 for id in token_ids.into_iter() {966 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;967 if id != expected_index {968 return Err("item id should be next".into());969 }970 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;971 }972 let data = (0..total_tokens)973 .map(|_| CreateItemData::<T> {974 properties: BoundedVec::default(),975 owner: to.clone(),976 })977 .collect();978979 <Pallet<T>>::create_multiple_items(self, &caller, data, &budget)980 .map_err(dispatch_to_evm::<T>)?;981 Ok(true)982 }983984 /// @notice Function to mint multiple tokens with the given tokenUris.985 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive986 /// numbers and first number should be obtained with `nextTokenId` method987 /// @param to The new owner988 /// @param tokens array of pairs of token ID and token URI for minted tokens989 #[solidity(hide, rename_selector = "mintBulkWithTokenURI")]990 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32) + <SelfWeightOf<T>>::set_token_properties(tokens.len() as u32))]991 fn mint_bulk_with_token_uri(992 &mut self,993 caller: Caller,994 to: Address,995 tokens: Vec<TokenUri>,996 ) -> Result<bool> {997 let key = key::url();998 let caller = T::CrossAccountId::from_eth(caller);999 let to = T::CrossAccountId::from_eth(to);1000 let mut expected_index = <TokensMinted<T>>::get(self.id)1001 .checked_add(1)1002 .ok_or("item id overflow")?;1003 let budget = self1004 .recorder1005 .weight_calls_budget(<StructureWeight<T>>::find_parent());10061007 let mut data = Vec::with_capacity(tokens.len());1008 for TokenUri { id, uri } in tokens {1009 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;1010 if id != expected_index {1011 return Err("item id should be next".into());1012 }1013 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;10141015 let mut properties = CollectionPropertiesVec::default();1016 properties1017 .try_push(Property {1018 key: key.clone(),1019 value: uri1020 .into_bytes()1021 .try_into()1022 .map_err(|_| "token uri is too long")?,1023 })1024 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;10251026 data.push(CreateItemData::<T> {1027 properties,1028 owner: to.clone(),1029 });1030 }10311032 <Pallet<T>>::create_multiple_items(self, &caller, data, &budget)1033 .map_err(dispatch_to_evm::<T>)?;1034 Ok(true)1035 }10361037 /// @notice Function to mint a token.1038 /// @param to The new owner crossAccountId1039 /// @param properties Properties of minted token1040 /// @return uint256 The id of the newly minted token1041 #[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]1042 fn mint_cross(1043 &mut self,1044 caller: Caller,1045 to: eth::CrossAddress,1046 properties: Vec<eth::Property>,1047 ) -> Result<U256> {1048 let token_id = <TokensMinted<T>>::get(self.id)1049 .checked_add(1)1050 .ok_or("item id overflow")?;10511052 let to = to.into_sub_cross_account::<T>()?;10531054 let properties = properties1055 .into_iter()1056 .map(eth::Property::try_into)1057 .collect::<Result<Vec<_>>>()?1058 .try_into()1059 .map_err(|_| Error::Revert(alloc::format!("too many properties")))?;10601061 let caller = T::CrossAccountId::from_eth(caller);10621063 let budget = self1064 .recorder1065 .weight_calls_budget(<StructureWeight<T>>::find_parent());10661067 <Pallet<T>>::create_item(1068 self,1069 &caller,1070 CreateItemData::<T> {1071 properties,1072 owner: to,1073 },1074 &budget,1075 )1076 .map_err(dispatch_to_evm::<T>)?;10771078 Ok(token_id.into())1079 }10801081 /// @notice Returns collection helper contract address1082 fn collection_helper_address(&self) -> Address {1083 T::ContractAddress::get()1084 }1085}10861087#[solidity_interface(1088 name = UniqueNFT,1089 is(1090 ERC721,1091 ERC721Enumerable,1092 ERC721UniqueExtensions,1093 ERC721UniqueMintable,1094 ERC721Burnable,1095 ERC721Metadata(if(this.flags.erc721metadata)),1096 Collection(via(common_mut returns CollectionHandle<T>)),1097 TokenProperties,1098 ),1099 enum(derive(PreDispatch)),1100)]1101impl<T: Config> NonfungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}11021103// Not a tests, but code generators1104generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);1105generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);11061107impl<T: Config> CommonEvmHandler for NonfungibleHandle<T>1108where1109 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,1110{1111 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");11121113 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {1114 call::<T, UniqueNFTCall<T>, _, _>(handle, self)1115 }1116}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//! # Nonfungible Pallet EVM API18//!19//! Provides ERC-721 standart support implementation and EVM API for unique extensions for Nonfungible Pallet.20//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.2122extern crate alloc;2324use alloc::string::ToString;25use core::{26 char::{REPLACEMENT_CHARACTER, decode_utf16},27 convert::TryInto,28};29use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};30use frame_support::BoundedVec;31use up_data_structs::{32 TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,33 CollectionPropertiesVec,34};35use pallet_evm_coder_substrate::{36 dispatch_to_evm, frontier_contract,37 execution::{Result, PreDispatch, Error},38};39use sp_std::{vec::Vec, vec};40use pallet_common::{41 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,42 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},43 eth::{self, TokenUri},44 CommonWeightInfo,45};46use pallet_evm::{account::CrossAccountId, PrecompileHandle};47use pallet_evm_coder_substrate::call;48use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};49use sp_core::{U256, Get};5051use crate::{52 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,53 TokenProperties, SelfWeightOf, weights::WeightInfo, common::CommonWeights,54};5556/// Nft events.57#[derive(ToLog)]58pub enum ERC721TokenEvent {59 /// The token has been changed.60 TokenChanged {61 /// Token ID.62 #[indexed]63 token_id: U256,64 },65}6667frontier_contract! {68 macro_rules! NonfungibleHandle_result {...}69 impl<T: Config> Contract for NonfungibleHandle<T> {...}70}7172/// @title A contract that allows to set and delete token properties and change token property permissions.73#[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))]74impl<T: Config> NonfungibleHandle<T> {75 /// @notice Set permissions for token property.76 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.77 /// @param key Property key.78 /// @param isMutable Permission to mutate property.79 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.80 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.81 #[solidity(hide)]82 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]83 fn set_token_property_permission(84 &mut self,85 caller: Caller,86 key: String,87 is_mutable: bool,88 collection_admin: bool,89 token_owner: bool,90 ) -> Result<()> {91 let caller = T::CrossAccountId::from_eth(caller);92 <Pallet<T>>::set_token_property_permissions(93 self,94 &caller,95 vec![PropertyKeyPermission {96 key: <Vec<u8>>::from(key)97 .try_into()98 .map_err(|_| "too long key")?,99 permission: PropertyPermission {100 mutable: is_mutable,101 collection_admin,102 token_owner,103 },104 }],105 )106 .map_err(dispatch_to_evm::<T>)107 }108109 /// @notice Set permissions for token property.110 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.111 /// @param permissions Permissions for keys.112 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]113 fn set_token_property_permissions(114 &mut self,115 caller: Caller,116 permissions: Vec<eth::TokenPropertyPermission>,117 ) -> Result<()> {118 let caller = T::CrossAccountId::from_eth(caller);119 let perms = eth::TokenPropertyPermission::into_property_key_permissions(permissions)?;120121 <Pallet<T>>::set_token_property_permissions(self, &caller, perms)122 .map_err(dispatch_to_evm::<T>)123 }124125 /// @notice Get permissions for token properties.126 fn token_property_permissions(&self) -> Result<Vec<eth::TokenPropertyPermission>> {127 let perms = <Pallet<T>>::token_property_permission(self.id);128 Ok(perms129 .into_iter()130 .map(eth::TokenPropertyPermission::from)131 .collect())132 }133134 /// @notice Set token property value.135 /// @dev Throws error if `msg.sender` has no permission to edit the property.136 /// @param tokenId ID of the token.137 /// @param key Property key.138 /// @param value Property value.139 #[solidity(hide)]140 #[weight(<SelfWeightOf<T>>::set_token_properties(1))]141 fn set_property(142 &mut self,143 caller: Caller,144 token_id: U256,145 key: String,146 value: Bytes,147 ) -> Result<()> {148 let caller = T::CrossAccountId::from_eth(caller);149 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;150 let key = <Vec<u8>>::from(key)151 .try_into()152 .map_err(|_| "key too long")?;153 let value = value.0.try_into().map_err(|_| "value too long")?;154155 let nesting_budget = self156 .recorder157 .weight_calls_budget(<StructureWeight<T>>::find_parent());158159 <Pallet<T>>::set_token_property(160 self,161 &caller,162 TokenId(token_id),163 Property { key, value },164 &nesting_budget,165 )166 .map_err(dispatch_to_evm::<T>)167 }168169 /// @notice Set token properties value.170 /// @dev Throws error if `msg.sender` has no permission to edit the property.171 /// @param tokenId ID of the token.172 /// @param properties settable properties173 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]174 fn set_properties(175 &mut self,176 caller: Caller,177 token_id: U256,178 properties: Vec<eth::Property>,179 ) -> Result<()> {180 let caller = T::CrossAccountId::from_eth(caller);181 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;182183 let nesting_budget = self184 .recorder185 .weight_calls_budget(<StructureWeight<T>>::find_parent());186187 let properties = properties188 .into_iter()189 .map(eth::Property::try_into)190 .collect::<Result<Vec<_>>>()?;191192 <Pallet<T>>::set_token_properties(193 self,194 &caller,195 TokenId(token_id),196 properties.into_iter(),197 false,198 &nesting_budget,199 )200 .map_err(dispatch_to_evm::<T>)201 }202203 /// @notice Delete token property value.204 /// @dev Throws error if `msg.sender` has no permission to edit the property.205 /// @param tokenId ID of the token.206 /// @param key Property key.207 #[solidity(hide)]208 #[weight(<SelfWeightOf<T>>::delete_token_properties(1))]209 fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> {210 let caller = T::CrossAccountId::from_eth(caller);211 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;212 let key = <Vec<u8>>::from(key)213 .try_into()214 .map_err(|_| "key too long")?;215216 let nesting_budget = self217 .recorder218 .weight_calls_budget(<StructureWeight<T>>::find_parent());219220 <Pallet<T>>::delete_token_property(self, &caller, TokenId(token_id), key, &nesting_budget)221 .map_err(dispatch_to_evm::<T>)222 }223224 /// @notice Delete token properties value.225 /// @dev Throws error if `msg.sender` has no permission to edit the property.226 /// @param tokenId ID of the token.227 /// @param keys Properties key.228 #[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]229 fn delete_properties(230 &mut self,231 token_id: U256,232 caller: Caller,233 keys: Vec<String>,234 ) -> Result<()> {235 let caller = T::CrossAccountId::from_eth(caller);236 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;237 let keys = keys238 .into_iter()239 .map(|k| Ok(<Vec<u8>>::from(k).try_into().map_err(|_| "key too long")?))240 .collect::<Result<Vec<_>>>()?;241242 let nesting_budget = self243 .recorder244 .weight_calls_budget(<StructureWeight<T>>::find_parent());245246 <Pallet<T>>::delete_token_properties(247 self,248 &caller,249 TokenId(token_id),250 keys.into_iter(),251 &nesting_budget,252 )253 .map_err(dispatch_to_evm::<T>)254 }255256 /// @notice Get token property value.257 /// @dev Throws error if key not found258 /// @param tokenId ID of the token.259 /// @param key Property key.260 /// @return Property value bytes261 fn property(&self, token_id: U256, key: String) -> Result<Bytes> {262 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;263 let key = <Vec<u8>>::from(key)264 .try_into()265 .map_err(|_| "key too long")?;266267 let props = <TokenProperties<T>>::get((self.id, token_id));268 let prop = props.get(&key).ok_or("key not found")?;269270 Ok(prop.to_vec().into())271 }272}273274#[derive(ToLog)]275pub enum ERC721Events {276 /// @dev This emits when ownership of any NFT changes by any mechanism.277 /// This event emits when NFTs are created (`from` == 0) and destroyed278 /// (`to` == 0). Exception: during contract creation, any number of NFTs279 /// may be created and assigned without emitting Transfer. At the time of280 /// any transfer, the approved address for that NFT (if any) is reset to none.281 Transfer {282 #[indexed]283 from: Address,284 #[indexed]285 to: Address,286 #[indexed]287 token_id: U256,288 },289 /// @dev This emits when the approved address for an NFT is changed or290 /// reaffirmed. The zero address indicates there is no approved address.291 /// When a Transfer event emits, this also indicates that the approved292 /// address for that NFT (if any) is reset to none.293 Approval {294 #[indexed]295 owner: Address,296 #[indexed]297 approved: Address,298 #[indexed]299 token_id: U256,300 },301 /// @dev This emits when an operator is enabled or disabled for an owner.302 /// The operator can manage all NFTs of the owner.303 #[allow(dead_code)]304 ApprovalForAll {305 #[indexed]306 owner: Address,307 #[indexed]308 operator: Address,309 approved: bool,310 },311}312313/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension314/// @dev See https://eips.ethereum.org/EIPS/eip-721315#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f, enum(derive(PreDispatch)), enum_attr(weight))]316impl<T: Config> NonfungibleHandle<T>317where318 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,319{320 /// @notice A descriptive name for a collection of NFTs in this contract321 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`322 #[solidity(hide, rename_selector = "name")]323 fn name_proxy(&self) -> String {324 self.name()325 }326327 /// @notice An abbreviated name for NFTs in this contract328 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`329 #[solidity(hide, rename_selector = "symbol")]330 fn symbol_proxy(&self) -> String {331 self.symbol()332 }333334 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.335 ///336 /// @dev If the token has a `url` property and it is not empty, it is returned.337 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.338 /// If the collection property `baseURI` is empty or absent, return "" (empty string)339 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix340 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).341 ///342 /// @return token's const_metadata343 #[solidity(rename_selector = "tokenURI")]344 fn token_uri(&self, token_id: U256) -> Result<String> {345 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;346347 match get_token_property(self, token_id_u32, &key::url()).as_deref() {348 Err(_) | Ok("") => (),349 Ok(url) => {350 return Ok(url.into());351 }352 };353354 let base_uri =355 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())356 .map(BoundedVec::into_inner)357 .map(String::from_utf8)358 .transpose()359 .map_err(|e| {360 Error::Revert(alloc::format!(361 "Can not convert value \"baseURI\" to string with error \"{e}\""362 ))363 })?;364365 let base_uri = match base_uri.as_deref() {366 None | Some("") => {367 return Ok("".into());368 }369 Some(base_uri) => base_uri.into(),370 };371372 Ok(373 match get_token_property(self, token_id_u32, &key::suffix()).as_deref() {374 Err(_) | Ok("") => base_uri,375 Ok(suffix) => base_uri + suffix,376 },377 )378 }379}380381/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension382/// @dev See https://eips.ethereum.org/EIPS/eip-721383#[solidity_interface(name = ERC721Enumerable, expect_selector = 0x780e9d63, enum(derive(PreDispatch)), enum_attr(weight))]384impl<T: Config> NonfungibleHandle<T> {385 /// @notice Enumerate valid NFTs386 /// @param index A counter less than `totalSupply()`387 /// @return The token identifier for the `index`th NFT,388 /// (sort order not specified)389 fn token_by_index(&self, index: U256) -> U256 {390 index391 }392393 /// @dev Not implemented394 fn token_of_owner_by_index(&self, _owner: Address, _index: U256) -> Result<U256> {395 // TODO: Not implemetable396 Err("not implemented".into())397 }398399 /// @notice Count NFTs tracked by this contract400 /// @return A count of valid NFTs tracked by this contract, where each one of401 /// them has an assigned and queryable owner not equal to the zero address402 fn total_supply(&self) -> Result<U256> {403 self.consume_store_reads(1)?;404 Ok(<Pallet<T>>::total_supply(self).into())405 }406}407408/// @title ERC-721 Non-Fungible Token Standard409/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md410#[solidity_interface(name = ERC721, events(ERC721Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x80ac58cd)]411impl<T: Config> NonfungibleHandle<T> {412 /// @notice Count all NFTs assigned to an owner413 /// @dev NFTs assigned to the zero address are considered invalid, and this414 /// function throws for queries about the zero address.415 /// @param owner An address for whom to query the balance416 /// @return The number of NFTs owned by `owner`, possibly zero417 fn balance_of(&self, owner: Address) -> Result<U256> {418 self.consume_store_reads(1)?;419 let owner = T::CrossAccountId::from_eth(owner);420 let balance = <AccountBalance<T>>::get((self.id, owner));421 Ok(balance.into())422 }423 /// @notice Find the owner of an NFT424 /// @dev NFTs assigned to zero address are considered invalid, and queries425 /// about them do throw.426 /// @param tokenId The identifier for an NFT427 /// @return The address of the owner of the NFT428 fn owner_of(&self, token_id: U256) -> Result<Address> {429 self.consume_store_reads(1)?;430 let token: TokenId = token_id.try_into()?;431 Ok(*<TokenData<T>>::get((self.id, token))432 .ok_or("token not found")?433 .owner434 .as_eth())435 }436 /// @dev Not implemented437 #[solidity(rename_selector = "safeTransferFrom")]438 fn safe_transfer_from_with_data(439 &mut self,440 _from: Address,441 _to: Address,442 _token_id: U256,443 _data: Bytes,444 ) -> Result<()> {445 // TODO: Not implemetable446 Err("not implemented".into())447 }448 /// @dev Not implemented449 fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {450 // TODO: Not implemetable451 Err("not implemented".into())452 }453454 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE455 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE456 /// THEY MAY BE PERMANENTLY LOST457 /// @dev Throws unless `msg.sender` is the current owner or an authorized458 /// operator for this NFT. Throws if `from` is not the current owner. Throws459 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.460 /// @param from The current owner of the NFT461 /// @param to The new owner462 /// @param tokenId The NFT to transfer463 #[weight(<CommonWeights<T>>::transfer_from())]464 fn transfer_from(465 &mut self,466 caller: Caller,467 from: Address,468 to: Address,469 token_id: U256,470 ) -> Result<()> {471 let caller = T::CrossAccountId::from_eth(caller);472 let from = T::CrossAccountId::from_eth(from);473 let to = T::CrossAccountId::from_eth(to);474 let token = token_id.try_into()?;475 let budget = self476 .recorder477 .weight_calls_budget(<StructureWeight<T>>::find_parent());478479 <Pallet<T>>::transfer_from(self, &caller, &from, &to, token, &budget)480 .map_err(|e| dispatch_to_evm::<T>(e.error))?;481 Ok(())482 }483484 /// @notice Set or reaffirm the approved address for an NFT485 /// @dev The zero address indicates there is no approved address.486 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized487 /// operator of the current owner.488 /// @param approved The new approved NFT controller489 /// @param tokenId The NFT to approve490 #[weight(<SelfWeightOf<T>>::approve())]491 fn approve(&mut self, caller: Caller, approved: Address, token_id: U256) -> Result<()> {492 let caller = T::CrossAccountId::from_eth(caller);493 let approved = T::CrossAccountId::from_eth(approved);494 let token = token_id.try_into()?;495496 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))497 .map_err(dispatch_to_evm::<T>)?;498 Ok(())499 }500501 /// @notice Sets or unsets the approval of a given operator.502 /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf.503 /// @param operator Operator504 /// @param approved Should operator status be granted or revoked?505 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]506 fn set_approval_for_all(507 &mut self,508 caller: Caller,509 operator: Address,510 approved: bool,511 ) -> Result<()> {512 let caller = T::CrossAccountId::from_eth(caller);513 let operator = T::CrossAccountId::from_eth(operator);514515 <Pallet<T>>::set_allowance_for_all(self, &caller, &operator, approved)516 .map_err(dispatch_to_evm::<T>)?;517 Ok(())518 }519520 /// @notice Get the approved address for a single NFT521 /// @dev Throws if `tokenId` is not a valid NFT522 /// @param tokenId The NFT to find the approved address for523 /// @return The approved address for this NFT, or the zero address if there is none524 fn get_approved(&self, token_id: U256) -> Result<Address> {525 let token_id = token_id.try_into()?;526 let operator = <Pallet<T>>::get_allowance(self, token_id).map_err(dispatch_to_evm::<T>)?;527 Ok(if let Some(operator) = operator {528 *operator.as_eth()529 } else {530 Address::zero()531 })532 }533534 /// @notice Tells whether the given `owner` approves the `operator`.535 #[weight(<SelfWeightOf<T>>::allowance_for_all())]536 fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {537 let owner = T::CrossAccountId::from_eth(owner);538 let operator = T::CrossAccountId::from_eth(operator);539540 Ok(<Pallet<T>>::allowance_for_all(self, &owner, &operator))541 }542}543544/// @title ERC721 Token that can be irreversibly burned (destroyed).545#[solidity_interface(name = ERC721Burnable, enum(derive(PreDispatch)), enum_attr(weight))]546impl<T: Config> NonfungibleHandle<T> {547 /// @notice Burns a specific ERC721 token.548 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized549 /// operator of the current owner.550 /// @param tokenId The NFT to approve551 #[weight(<SelfWeightOf<T>>::burn_item())]552 fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {553 let caller = T::CrossAccountId::from_eth(caller);554 let token = token_id.try_into()?;555556 <Pallet<T>>::burn(self, &caller, token).map_err(dispatch_to_evm::<T>)?;557 Ok(())558 }559}560561/// @title ERC721 minting logic.562#[solidity_interface(name = ERC721UniqueMintable, enum(derive(PreDispatch)), enum_attr(weight))]563impl<T: Config> NonfungibleHandle<T> {564 /// @notice Function to mint a token.565 /// @param to The new owner566 /// @return uint256 The id of the newly minted token567 #[weight(<SelfWeightOf<T>>::create_item())]568 fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {569 let token_id: U256 = <TokensMinted<T>>::get(self.id)570 .checked_add(1)571 .ok_or("item id overflow")?572 .into();573 self.mint_check_id(caller, to, token_id)?;574 Ok(token_id)575 }576577 /// @notice Function to mint a token.578 /// @dev `tokenId` should be obtained with `nextTokenId` method,579 /// unlike standard, you can't specify it manually580 /// @param to The new owner581 /// @param tokenId ID of the minted NFT582 #[solidity(hide, rename_selector = "mint")]583 #[weight(<SelfWeightOf<T>>::create_item())]584 fn mint_check_id(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<bool> {585 let caller = T::CrossAccountId::from_eth(caller);586 let to = T::CrossAccountId::from_eth(to);587 let token_id: u32 = token_id.try_into()?;588 let budget = self589 .recorder590 .weight_calls_budget(<StructureWeight<T>>::find_parent());591592 if <TokensMinted<T>>::get(self.id)593 .checked_add(1)594 .ok_or("item id overflow")?595 != token_id596 {597 return Err("item id should be next".into());598 }599600 <Pallet<T>>::create_item(601 self,602 &caller,603 CreateItemData::<T> {604 properties: BoundedVec::default(),605 owner: to,606 },607 &budget,608 )609 .map_err(dispatch_to_evm::<T>)?;610611 Ok(true)612 }613614 /// @notice Function to mint token with the given tokenUri.615 /// @param to The new owner616 /// @param tokenUri Token URI that would be stored in the NFT properties617 /// @return uint256 The id of the newly minted token618 #[solidity(rename_selector = "mintWithTokenURI")]619 #[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]620 fn mint_with_token_uri(621 &mut self,622 caller: Caller,623 to: Address,624 token_uri: String,625 ) -> Result<U256> {626 let token_id: U256 = <TokensMinted<T>>::get(self.id)627 .checked_add(1)628 .ok_or("item id overflow")?629 .into();630 self.mint_with_token_uri_check_id(caller, to, token_id, token_uri)?;631 Ok(token_id)632 }633634 /// @notice Function to mint token with the given tokenUri.635 /// @dev `tokenId` should be obtained with `nextTokenId` method,636 /// unlike standard, you can't specify it manually637 /// @param to The new owner638 /// @param tokenId ID of the minted NFT639 /// @param tokenUri Token URI that would be stored in the NFT properties640 #[solidity(hide, rename_selector = "mintWithTokenURI")]641 #[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]642 fn mint_with_token_uri_check_id(643 &mut self,644 caller: Caller,645 to: Address,646 token_id: U256,647 token_uri: String,648 ) -> Result<bool> {649 let key = key::url();650 let permission = get_token_permission::<T>(self.id, &key)?;651 if !permission.collection_admin {652 return Err("Operation is not allowed".into());653 }654655 let caller = T::CrossAccountId::from_eth(caller);656 let to = T::CrossAccountId::from_eth(to);657 let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;658 let budget = self659 .recorder660 .weight_calls_budget(<StructureWeight<T>>::find_parent());661662 if <TokensMinted<T>>::get(self.id)663 .checked_add(1)664 .ok_or("item id overflow")?665 != token_id666 {667 return Err("item id should be next".into());668 }669670 let mut properties = CollectionPropertiesVec::default();671 properties672 .try_push(Property {673 key,674 value: token_uri675 .into_bytes()676 .try_into()677 .map_err(|_| "token uri is too long")?,678 })679 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {e:?}")))?;680681 <Pallet<T>>::create_item(682 self,683 &caller,684 CreateItemData::<T> {685 properties,686 owner: to,687 },688 &budget,689 )690 .map_err(dispatch_to_evm::<T>)?;691 Ok(true)692 }693}694695fn get_token_property<T: Config>(696 collection: &CollectionHandle<T>,697 token_id: u32,698 key: &up_data_structs::PropertyKey,699) -> Result<String> {700 collection.consume_store_reads(1)?;701 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))702 .map_err(|_| Error::Revert("Token properties not found".into()))?;703 if let Some(property) = properties.get(key) {704 return Ok(String::from_utf8_lossy(property).into());705 }706707 Err("Property tokenURI not found".into())708}709710fn get_token_permission<T: Config>(711 collection_id: CollectionId,712 key: &PropertyKey,713) -> Result<PropertyPermission> {714 let token_property_permissions = CollectionPropertyPermissions::<T>::try_get(collection_id)715 .map_err(|_| Error::Revert("No permissions for collection".into()))?;716 let a = token_property_permissions717 .get(key)718 .map(Clone::clone)719 .ok_or_else(|| {720 let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();721 Error::Revert(alloc::format!("No permission for key {key}"))722 })?;723 Ok(a)724}725726/// @title Unique extensions for ERC721.727#[solidity_interface(name = ERC721UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]728impl<T: Config> NonfungibleHandle<T>729where730 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,731{732 /// @notice A descriptive name for a collection of NFTs in this contract733 fn name(&self) -> String {734 decode_utf16(self.name.iter().copied())735 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))736 .collect::<String>()737 }738739 /// @notice An abbreviated name for NFTs in this contract740 fn symbol(&self) -> String {741 String::from_utf8_lossy(&self.token_prefix).into()742 }743744 /// @notice A description for the collection.745 fn description(&self) -> String {746 decode_utf16(self.description.iter().copied())747 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))748 .collect::<String>()749 }750751 /// Returns the owner (in cross format) of the token.752 ///753 /// @param tokenId Id for the token.754 #[solidity(hide)]755 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {756 Self::owner_of_cross(self, token_id)757 }758759 /// Returns the owner (in cross format) of the token.760 ///761 /// @param tokenId Id for the token.762 fn owner_of_cross(&self, token_id: U256) -> Result<eth::CrossAddress> {763 Self::token_owner(self, token_id.try_into()?)764 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))765 .map_err(|_| Error::Revert("token not found".into()))766 }767768 /// @notice Count all NFTs assigned to an owner769 /// @param owner An cross address for whom to query the balance770 /// @return The number of NFTs owned by `owner`, possibly zero771 fn balance_of_cross(&self, owner: eth::CrossAddress) -> Result<U256> {772 self.consume_store_reads(1)?;773 let balance = <AccountBalance<T>>::get((self.id, owner.into_sub_cross_account::<T>()?));774 Ok(balance.into())775 }776777 /// Returns the token properties.778 ///779 /// @param tokenId Id for the token.780 /// @param keys Properties keys. Empty keys for all propertyes.781 /// @return Vector of properties key/value pairs.782 fn properties(&self, token_id: U256, keys: Vec<String>) -> Result<Vec<eth::Property>> {783 let keys = keys784 .into_iter()785 .map(|key| {786 <Vec<u8>>::from(key)787 .try_into()788 .map_err(|_| Error::Revert("key too large".into()))789 })790 .collect::<Result<Vec<_>>>()?;791792 <Self as CommonCollectionOperations<T>>::token_properties(793 self,794 token_id.try_into()?,795 if keys.is_empty() { None } else { Some(keys) },796 )797 .into_iter()798 .map(eth::Property::try_from)799 .collect::<Result<Vec<_>>>()800 }801802 /// @notice Set or reaffirm the approved address for an NFT803 /// @dev The zero address indicates there is no approved address.804 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized805 /// operator of the current owner.806 /// @param approved The new substrate address approved NFT controller807 /// @param tokenId The NFT to approve808 #[weight(<SelfWeightOf<T>>::approve())]809 fn approve_cross(810 &mut self,811 caller: Caller,812 approved: eth::CrossAddress,813 token_id: U256,814 ) -> Result<()> {815 let caller = T::CrossAccountId::from_eth(caller);816 let approved = approved.into_sub_cross_account::<T>()?;817 let token = token_id.try_into()?;818819 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))820 .map_err(dispatch_to_evm::<T>)?;821 Ok(())822 }823824 /// @notice Transfer ownership of an NFT825 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`826 /// is the zero address. Throws if `tokenId` is not a valid NFT.827 /// @param to The new owner828 /// @param tokenId The NFT to transfer829 #[weight(<CommonWeights<T>>::transfer())]830 fn transfer(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<()> {831 let caller = T::CrossAccountId::from_eth(caller);832 let to = T::CrossAccountId::from_eth(to);833 let token = token_id.try_into()?;834 let budget = self835 .recorder836 .weight_calls_budget(<StructureWeight<T>>::find_parent());837838 <Pallet<T>>::transfer(self, &caller, &to, token, &budget)839 .map_err(|e| dispatch_to_evm::<T>(e.error))?;840 Ok(())841 }842843 /// @notice Transfer ownership of an NFT844 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`845 /// is the zero address. Throws if `tokenId` is not a valid NFT.846 /// @param to The new owner847 /// @param tokenId The NFT to transfer848 #[weight(<CommonWeights<T>>::transfer())]849 fn transfer_cross(850 &mut self,851 caller: Caller,852 to: eth::CrossAddress,853 token_id: U256,854 ) -> Result<()> {855 let caller = T::CrossAccountId::from_eth(caller);856 let to = to.into_sub_cross_account::<T>()?;857 let token = token_id.try_into()?;858 let budget = self859 .recorder860 .weight_calls_budget(<StructureWeight<T>>::find_parent());861862 <Pallet<T>>::transfer(self, &caller, &to, token, &budget)863 .map_err(|e| dispatch_to_evm::<T>(e.error))?;864 Ok(())865 }866867 /// @notice Transfer ownership of an NFT from cross account address to cross account address868 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`869 /// is the zero address. Throws if `tokenId` is not a valid NFT.870 /// @param from Cross acccount address of current owner871 /// @param to Cross acccount address of new owner872 /// @param tokenId The NFT to transfer873 #[weight(<CommonWeights<T>>::transfer_from())]874 fn transfer_from_cross(875 &mut self,876 caller: Caller,877 from: eth::CrossAddress,878 to: eth::CrossAddress,879 token_id: U256,880 ) -> Result<()> {881 let caller = T::CrossAccountId::from_eth(caller);882 let from = from.into_sub_cross_account::<T>()?;883 let to = to.into_sub_cross_account::<T>()?;884 let token_id = token_id.try_into()?;885 let budget = self886 .recorder887 .weight_calls_budget(<StructureWeight<T>>::find_parent());888 Pallet::<T>::transfer_from(self, &caller, &from, &to, token_id, &budget)889 .map_err(|e| dispatch_to_evm::<T>(e.error))?;890 Ok(())891 }892893 /// @notice Burns a specific ERC721 token.894 /// @dev Throws unless `msg.sender` is the current owner or an authorized895 /// operator for this NFT. Throws if `from` is not the current owner. Throws896 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.897 /// @param from The current owner of the NFT898 /// @param tokenId The NFT to transfer899 #[solidity(hide)]900 #[weight(<SelfWeightOf<T>>::burn_from())]901 fn burn_from(&mut self, caller: Caller, from: Address, token_id: U256) -> Result<()> {902 let caller = T::CrossAccountId::from_eth(caller);903 let from = T::CrossAccountId::from_eth(from);904 let token = token_id.try_into()?;905 let budget = self906 .recorder907 .weight_calls_budget(<StructureWeight<T>>::find_parent());908909 <Pallet<T>>::burn_from(self, &caller, &from, token, &budget)910 .map_err(dispatch_to_evm::<T>)?;911 Ok(())912 }913914 /// @notice Burns a specific ERC721 token.915 /// @dev Throws unless `msg.sender` is the current owner or an authorized916 /// operator for this NFT. Throws if `from` is not the current owner. Throws917 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.918 /// @param from The current owner of the NFT919 /// @param tokenId The NFT to transfer920 #[weight(<SelfWeightOf<T>>::burn_from())]921 fn burn_from_cross(922 &mut self,923 caller: Caller,924 from: eth::CrossAddress,925 token_id: U256,926 ) -> Result<()> {927 let caller = T::CrossAccountId::from_eth(caller);928 let from = from.into_sub_cross_account::<T>()?;929 let token = token_id.try_into()?;930 let budget = self931 .recorder932 .weight_calls_budget(<StructureWeight<T>>::find_parent());933934 <Pallet<T>>::burn_from(self, &caller, &from, token, &budget)935 .map_err(dispatch_to_evm::<T>)?;936 Ok(())937 }938939 /// @notice Returns next free NFT ID.940 fn next_token_id(&self) -> Result<U256> {941 self.consume_store_reads(1)?;942 Ok(<TokensMinted<T>>::get(self.id)943 .checked_add(1)944 .ok_or("item id overflow")?945 .into())946 }947948 /// @notice Function to mint multiple tokens.949 /// @dev `tokenIds` should be an array of consecutive numbers and first number950 /// should be obtained with `nextTokenId` method951 /// @param to The new owner952 /// @param tokenIds IDs of the minted NFTs953 #[solidity(hide)]954 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]955 fn mint_bulk(&mut self, caller: Caller, to: Address, token_ids: Vec<U256>) -> Result<bool> {956 let caller = T::CrossAccountId::from_eth(caller);957 let to = T::CrossAccountId::from_eth(to);958 let mut expected_index = <TokensMinted<T>>::get(self.id)959 .checked_add(1)960 .ok_or("item id overflow")?;961 let budget = self962 .recorder963 .weight_calls_budget(<StructureWeight<T>>::find_parent());964965 let total_tokens = token_ids.len();966 for id in token_ids.into_iter() {967 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;968 if id != expected_index {969 return Err("item id should be next".into());970 }971 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;972 }973 let data = (0..total_tokens)974 .map(|_| CreateItemData::<T> {975 properties: BoundedVec::default(),976 owner: to.clone(),977 })978 .collect();979980 <Pallet<T>>::create_multiple_items(self, &caller, data, &budget)981 .map_err(dispatch_to_evm::<T>)?;982 Ok(true)983 }984985 /// @notice Function to mint multiple tokens with the given tokenUris.986 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive987 /// numbers and first number should be obtained with `nextTokenId` method988 /// @param to The new owner989 /// @param tokens array of pairs of token ID and token URI for minted tokens990 #[solidity(hide, rename_selector = "mintBulkWithTokenURI")]991 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32) + <SelfWeightOf<T>>::set_token_properties(tokens.len() as u32))]992 fn mint_bulk_with_token_uri(993 &mut self,994 caller: Caller,995 to: Address,996 tokens: Vec<TokenUri>,997 ) -> Result<bool> {998 let key = key::url();999 let caller = T::CrossAccountId::from_eth(caller);1000 let to = T::CrossAccountId::from_eth(to);1001 let mut expected_index = <TokensMinted<T>>::get(self.id)1002 .checked_add(1)1003 .ok_or("item id overflow")?;1004 let budget = self1005 .recorder1006 .weight_calls_budget(<StructureWeight<T>>::find_parent());10071008 let mut data = Vec::with_capacity(tokens.len());1009 for TokenUri { id, uri } in tokens {1010 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;1011 if id != expected_index {1012 return Err("item id should be next".into());1013 }1014 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;10151016 let mut properties = CollectionPropertiesVec::default();1017 properties1018 .try_push(Property {1019 key: key.clone(),1020 value: uri1021 .into_bytes()1022 .try_into()1023 .map_err(|_| "token uri is too long")?,1024 })1025 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {e:?}")))?;10261027 data.push(CreateItemData::<T> {1028 properties,1029 owner: to.clone(),1030 });1031 }10321033 <Pallet<T>>::create_multiple_items(self, &caller, data, &budget)1034 .map_err(dispatch_to_evm::<T>)?;1035 Ok(true)1036 }10371038 /// @notice Function to mint a token.1039 /// @param to The new owner crossAccountId1040 /// @param properties Properties of minted token1041 /// @return uint256 The id of the newly minted token1042 #[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]1043 fn mint_cross(1044 &mut self,1045 caller: Caller,1046 to: eth::CrossAddress,1047 properties: Vec<eth::Property>,1048 ) -> Result<U256> {1049 let token_id = <TokensMinted<T>>::get(self.id)1050 .checked_add(1)1051 .ok_or("item id overflow")?;10521053 let to = to.into_sub_cross_account::<T>()?;10541055 let properties = properties1056 .into_iter()1057 .map(eth::Property::try_into)1058 .collect::<Result<Vec<_>>>()?1059 .try_into()1060 .map_err(|_| Error::Revert("too many properties".to_string()))?;10611062 let caller = T::CrossAccountId::from_eth(caller);10631064 let budget = self1065 .recorder1066 .weight_calls_budget(<StructureWeight<T>>::find_parent());10671068 <Pallet<T>>::create_item(1069 self,1070 &caller,1071 CreateItemData::<T> {1072 properties,1073 owner: to,1074 },1075 &budget,1076 )1077 .map_err(dispatch_to_evm::<T>)?;10781079 Ok(token_id.into())1080 }10811082 /// @notice Returns collection helper contract address1083 fn collection_helper_address(&self) -> Address {1084 T::ContractAddress::get()1085 }1086}10871088#[solidity_interface(1089 name = UniqueNFT,1090 is(1091 ERC721,1092 ERC721Enumerable,1093 ERC721UniqueExtensions,1094 ERC721UniqueMintable,1095 ERC721Burnable,1096 ERC721Metadata(if(this.flags.erc721metadata)),1097 Collection(via(common_mut returns CollectionHandle<T>)),1098 TokenProperties,1099 ),1100 enum(derive(PreDispatch)),1101)]1102impl<T: Config> NonfungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}11031104// Not a tests, but code generators1105generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);1106generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);11071108impl<T: Config> CommonEvmHandler for NonfungibleHandle<T>1109where1110 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,1111{1112 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");11131114 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {1115 call::<T, UniqueNFTCall<T>, _, _>(handle, self)1116 }1117}pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -166,10 +166,7 @@
#[pallet::config]
pub trait Config:
- frame_system::Config
- + pallet_common::Config
- + pallet_structure::Config
- + pallet_evm::Config
+ frame_system::Config + pallet_common::Config + pallet_structure::Config + pallet_evm::Config
{
type WeightInfo: WeightInfo;
}
@@ -860,13 +857,7 @@
<PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);
- <TokenData<T>>::insert(
- (collection.id, token),
- ItemData {
- owner: to.clone(),
- ..token_data
- },
- );
+ <TokenData<T>>::insert((collection.id, token), ItemData { owner: to.clone() });
if let Some(balance_to) = balance_to {
// from != to
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -21,6 +21,7 @@
extern crate alloc;
+use alloc::string::ToString;
use core::{
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
@@ -353,8 +354,7 @@
.transpose()
.map_err(|e| {
Error::Revert(alloc::format!(
- "Can not convert value \"baseURI\" to string with error \"{}\"",
- e
+ "Can not convert value \"baseURI\" to string with error \"{e}\""
))
})?;
@@ -482,8 +482,8 @@
.recorder
.weight_calls_budget(<StructureWeight<T>>::find_parent());
- let balance = balance(&self, token, &from)?;
- ensure_single_owner(&self, token, balance)?;
+ let balance = balance(self, token, &from)?;
+ ensure_single_owner(self, token, balance)?;
<Pallet<T>>::transfer_from(self, &caller, &from, &to, token, balance, &budget)
.map_err(dispatch_to_evm::<T>)?;
@@ -575,8 +575,8 @@
let caller = T::CrossAccountId::from_eth(caller);
let token = token_id.try_into()?;
- let balance = balance(&self, token, &caller)?;
- ensure_single_owner(&self, token, balance)?;
+ let balance = balance(self, token, &caller)?;
+ ensure_single_owner(self, token, balance)?;
<Pallet<T>>::burn(self, &caller, token, balance).map_err(dispatch_to_evm::<T>)?;
Ok(())
@@ -622,7 +622,7 @@
return Err("item id should be next".into());
}
- let users = [(to.clone(), 1)]
+ let users = [(to, 1)]
.into_iter()
.collect::<BTreeMap<_, _>>()
.try_into()
@@ -706,9 +706,9 @@
.try_into()
.map_err(|_| "token uri is too long")?,
})
- .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;
+ .map_err(|e| Error::Revert(alloc::format!("Can't add property: {e:?}")))?;
- let users = [(to.clone(), 1)]
+ let users = [(to, 1)]
.into_iter()
.collect::<BTreeMap<_, _>>()
.try_into()
@@ -750,7 +750,7 @@
.map(Clone::clone)
.ok_or_else(|| {
let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();
- Error::Revert(alloc::format!("No permission for key {}", key))
+ Error::Revert(alloc::format!("No permission for key {key}"))
})?;
Ok(a)
}
@@ -785,14 +785,14 @@
/// @param tokenId Id for the token.
#[solidity(hide)]
fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {
- Self::owner_of_cross(&self, token_id)
+ Self::owner_of_cross(self, token_id)
}
/// Returns the owner (in cross format) of the token.
///
/// @param tokenId Id for the token.
fn owner_of_cross(&self, token_id: U256) -> Result<eth::CrossAddress> {
- Self::token_owner(&self, token_id.try_into()?)
+ Self::token_owner(self, token_id.try_into()?)
.map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))
.or_else(|err| match err {
TokenOwnerError::NotFound => Err(Error::Revert("token not found".into())),
@@ -827,7 +827,7 @@
.collect::<Result<Vec<_>>>()?;
<Self as CommonCollectionOperations<T>>::token_properties(
- &self,
+ self,
token_id.try_into()?,
if keys.is_empty() { None } else { Some(keys) },
)
@@ -1004,7 +1004,7 @@
}
expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
}
- let users = [(to.clone(), 1)]
+ let users = [(to, 1)]
.into_iter()
.collect::<BTreeMap<_, _>>()
.try_into()
@@ -1046,7 +1046,7 @@
.weight_calls_budget(<StructureWeight<T>>::find_parent());
let mut data = Vec::with_capacity(tokens.len());
- let users: BoundedBTreeMap<_, _, _> = [(to.clone(), 1)]
+ let users: BoundedBTreeMap<_, _, _> = [(to, 1)]
.into_iter()
.collect::<BTreeMap<_, _>>()
.try_into()
@@ -1067,7 +1067,7 @@
.try_into()
.map_err(|_| "token uri is too long")?,
})
- .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;
+ .map_err(|e| Error::Revert(alloc::format!("Can't add property: {e:?}")))?;
let create_item_data = CreateItemData::<T> {
users: users.clone(),
@@ -1103,7 +1103,7 @@
.map(eth::Property::try_into)
.collect::<Result<Vec<_>>>()?
.try_into()
- .map_err(|_| Error::Revert(alloc::format!("too many properties")))?;
+ .map_err(|_| Error::Revert("too many properties".to_string()))?;
let caller = T::CrossAccountId::from_eth(caller);
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -1124,7 +1124,7 @@
if collection.ignores_token_restrictions(spender) {
return Ok(Self::compute_allowance_decrease(
- collection, token, from, &spender, amount,
+ collection, token, from, spender, amount,
));
}
@@ -1143,7 +1143,7 @@
return Ok(None);
}
- let allowance = Self::compute_allowance_decrease(collection, token, from, &spender, amount);
+ let allowance = Self::compute_allowance_decrease(collection, token, from, spender, amount);
if allowance.is_some() {
return Ok(allowance);
}
pallets/scheduler-v2/src/lib.rsdiffbeforeafterboth--- a/pallets/scheduler-v2/src/lib.rs
+++ b/pallets/scheduler-v2/src/lib.rs
@@ -969,7 +969,7 @@
call: ScheduledCall<T>,
) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
// ensure id it is unique
- if Lookup::<T>::contains_key(&id) {
+ if Lookup::<T>::contains_key(id) {
return Err(Error::<T>::FailedToSchedule.into());
}
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -280,7 +280,7 @@
) -> DispatchResultWithPostInfo {
let dispatch = T::CollectionDispatch::dispatch(collection)?;
let dispatch = dispatch.as_dyn();
- dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)
+ dispatch.burn_item_recursively(from, token, self_budget, breadth_budget)
}
/// Check if `token` indirectly owned by `user`
@@ -396,7 +396,7 @@
account: &T::CrossAccountId,
action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult,
) -> DispatchResult {
- if is_collection(&account.as_eth()) {
+ if is_collection(account.as_eth()) {
fail!(<Error<T>>::CantNestTokenUnderCollection);
}
let Some((collection, token)) = T::CrossTokenAddressMapping::address_to_token(account) else {
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -113,13 +113,9 @@
let collection_helpers_address =
T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
- let collection_id = T::CollectionDispatch::create(
- caller.clone(),
- collection_helpers_address,
- data,
- Default::default(),
- )
- .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+ let collection_id =
+ T::CollectionDispatch::create(caller, collection_helpers_address, data, Default::default())
+ .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
Ok(address)
}
@@ -132,8 +128,7 @@
.expect("Collection creation price should be convertible to u128");
if value != creation_price {
return Err(format!(
- "Sent amount not equals to collection creation price ({0})",
- creation_price
+ "Sent amount not equals to collection creation price ({creation_price})",
)
.into());
}
@@ -383,8 +378,7 @@
map_eth_to_id(&collection_address)
.map(|id| id.0)
.ok_or(Error::Revert(format!(
- "failed to convert address {} into collectionId.",
- collection_address
+ "failed to convert address {collection_address} into collectionId."
)))
}
}
@@ -422,5 +416,5 @@
generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);
fn error_field_too_long(feild: &str, bound: usize) -> Error {
- Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))
+ Error::Revert(format!("{feild} is too long. Max length is {bound}."))
}
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -507,7 +507,7 @@
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
let new_owner = T::CrossAccountId::from_sub(new_owner);
let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.change_owner(sender, new_owner.clone())
+ target_collection.change_owner(sender, new_owner)
}
/// Add an admin to a collection.
@@ -667,7 +667,7 @@
/// * `owner`: Address of the initial owner of the item.
/// * `data`: Token data describing the item to store on chain.
#[pallet::call_index(11)]
- #[pallet::weight(T::CommonWeightInfo::create_item(&data))]
+ #[pallet::weight(T::CommonWeightInfo::create_item(data))]
pub fn create_item(
origin: OriginFor<T>,
collection_id: CollectionId,
@@ -701,7 +701,7 @@
/// * `owner`: Address of the initial owner of the tokens.
/// * `items_data`: Vector of data describing each item to be created.
#[pallet::call_index(12)]
- #[pallet::weight(T::CommonWeightInfo::create_multiple_items(&items_data))]
+ #[pallet::weight(T::CommonWeightInfo::create_multiple_items(items_data))]
pub fn create_multiple_items(
origin: OriginFor<T>,
collection_id: CollectionId,
@@ -889,7 +889,7 @@
/// * `collection_id`: ID of the collection to which the tokens would belong.
/// * `data`: Explicit item creation data.
#[pallet::call_index(18)]
- #[pallet::weight(T::CommonWeightInfo::create_multiple_items_ex(&data))]
+ #[pallet::weight(T::CommonWeightInfo::create_multiple_items_ex(data))]
pub fn create_multiple_items_ex(
origin: OriginFor<T>,
collection_id: CollectionId,
@@ -1313,7 +1313,7 @@
collection_id: CollectionId,
) -> DispatchResult {
let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
- target_collection.force_set_sponsor(sponsor.clone())
+ target_collection.force_set_sponsor(sponsor)
}
/// Force remove `sponsor` for `collection`.
primitives/data-structs/src/bounded.rsdiffbeforeafterboth--- a/primitives/data-structs/src/bounded.rs
+++ b/primitives/data-structs/src/bounded.rs
@@ -63,7 +63,7 @@
V: fmt::Debug,
{
use core::fmt::Debug;
- (&v as &Vec<V>).fmt(f)
+ (v as &Vec<V>).fmt(f)
}
#[cfg(feature = "serde1")]
@@ -114,7 +114,7 @@
V: fmt::Debug,
{
use core::fmt::Debug;
- (&v as &BTreeMap<K, V>).fmt(f)
+ (v as &BTreeMap<K, V>).fmt(f)
}
#[cfg(feature = "serde1")]
@@ -157,5 +157,5 @@
K: fmt::Debug + Ord,
{
use core::fmt::Debug;
- (&v as &BTreeSet<K>).fmt(f)
+ (v as &BTreeSet<K>).fmt(f)
}
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -536,7 +536,7 @@
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
- return &self.0;
+ &self.0
}
}
@@ -816,6 +816,11 @@
Self(Default::default())
}
}
+impl Default for OwnerRestrictedSet {
+ fn default() -> Self {
+ Self::new()
+ }
+}
impl core::ops::Deref for OwnerRestrictedSet {
type Target = OwnerRestrictedSetInner;
fn deref(&self) -> &Self::Target {
@@ -1098,9 +1103,9 @@
pub value: PropertyValue,
}
-impl Into<(PropertyKey, PropertyValue)> for Property {
- fn into(self) -> (PropertyKey, PropertyValue) {
- (self.key, self.value)
+impl From<Property> for (PropertyKey, PropertyValue) {
+ fn from(value: Property) -> Self {
+ (value.key, value.value)
}
}
@@ -1116,9 +1121,9 @@
pub permission: PropertyPermission,
}
-impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {
- fn into(self) -> (PropertyKey, PropertyPermission) {
- (self.key, self.permission)
+impl From<PropertyKeyPermission> for (PropertyKey, PropertyPermission) {
+ fn from(value: PropertyKeyPermission) -> Self {
+ (value.key, value.permission)
}
}
@@ -1415,7 +1420,7 @@
value: Self::Value,
) -> Result<Option<Self::Value>, PropertiesError> {
let key_size = scoped_slice_size(scope, &key);
- let value_size = slice_size(&value) as u32;
+ let value_size = slice_size(&value);
if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")
{
@@ -1425,7 +1430,7 @@
let old_value = self.map.try_scoped_set(scope, key, value)?;
if let Some(old_value) = old_value.as_ref() {
- let old_value_size = slice_size(&old_value);
+ let old_value_size = slice_size(old_value);
self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;
} else {
self.consumed_space += key_size + value_size;
runtime/common/config/xcm/foreignassets.rsdiffbeforeafterboth--- a/runtime/common/config/xcm/foreignassets.rs
+++ b/runtime/common/config/xcm/foreignassets.rs
@@ -65,7 +65,7 @@
return ConvertAssetId::convert_ref(AssetIds::NativeAssetId(NativeCurrency::Here));
}
- match XcmForeignAssetIdMapping::<Runtime>::get_currency_id(id.clone()) {
+ match XcmForeignAssetIdMapping::<Runtime>::get_currency_id(*id) {
Some(AssetIds::ForeignAssetId(foreign_asset_id)) => {
ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(foreign_asset_id))
}
@@ -206,9 +206,7 @@
return Some(AssetIds::NativeAssetId(NativeCurrency::Parent));
}
- if let Some(currency_id) =
- XcmForeignAssetIdMapping::<Runtime>::get_currency_id(location.clone())
- {
+ if let Some(currency_id) = XcmForeignAssetIdMapping::<Runtime>::get_currency_id(location) {
return Some(currency_id);
}
runtime/common/ethereum/precompiles/mod.rsdiffbeforeafterboth--- a/runtime/common/ethereum/precompiles/mod.rs
+++ b/runtime/common/ethereum/precompiles/mod.rs
@@ -37,6 +37,16 @@
[hash(1), hash(20482)]
}
}
+
+impl<R> Default for UniquePrecompiles<R>
+where
+ R: pallet_evm::Config,
+{
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
impl<R> PrecompileSet for UniquePrecompiles<R>
where
R: pallet_evm::Config,
runtime/common/ethereum/precompiles/sr25519.rsdiffbeforeafterboth--- a/runtime/common/ethereum/precompiles/sr25519.rs
+++ b/runtime/common/ethereum/precompiles/sr25519.rs
@@ -64,7 +64,7 @@
// Parse arguments
let public: sr25519::Public =
- sr25519::Public::unchecked_from(input.read::<H256>(gasometer)?).into();
+ sr25519::Public::unchecked_from(input.read::<H256>(gasometer)?);
let signature_bytes: Vec<u8> = input.read::<Bytes>(gasometer)?.into();
let message: Vec<u8> = input.read::<Bytes>(gasometer)?.into();
runtime/common/ethereum/precompiles/utils/data.rsdiffbeforeafterboth--- a/runtime/common/ethereum/precompiles/utils/data.rs
+++ b/runtime/common/ethereum/precompiles/utils/data.rs
@@ -60,7 +60,7 @@
}
impl Into<Vec<u8>> for Bytes {
- fn into(self: Self) -> Vec<u8> {
+ fn into(self) -> Vec<u8> {
self.0
}
}
runtime/common/ethereum/precompiles/utils/mod.rsdiffbeforeafterboth--- a/runtime/common/ethereum/precompiles/utils/mod.rs
+++ b/runtime/common/ethereum/precompiles/utils/mod.rs
@@ -73,7 +73,6 @@
}
}
- #[must_use]
/// Check that a function call is compatible with the context it is
/// called into.
pub fn check_function_modifier(
runtime/common/ethereum/sponsoring.rsdiffbeforeafterboth--- a/runtime/common/ethereum/sponsoring.rs
+++ b/runtime/common/ethereum/sponsoring.rs
@@ -78,7 +78,7 @@
let token_id: TokenId = token_id.try_into().ok()?;
withdraw_set_token_property::<T>(
&collection,
- &who,
+ who,
&token_id,
key.len() + value.len(),
)
@@ -88,7 +88,7 @@
ERC721UniqueExtensionsCall::Transfer { token_id, .. },
) => {
let token_id: TokenId = token_id.try_into().ok()?;
- withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)
+ withdraw_transfer::<T>(&collection, who, &token_id).map(|()| sponsor)
}
UniqueNFTCall::ERC721UniqueMintable(
ERC721UniqueMintableCall::Mint { .. }
@@ -97,7 +97,7 @@
| ERC721UniqueMintableCall::MintWithTokenUriCheckId { .. },
) => withdraw_create_item::<T>(
&collection,
- &who,
+ who,
&CreateItemData::NFT(CreateNftData::default()),
)
.map(|()| sponsor),
runtime/common/ethereum/sponsoring/refungible.rsdiffbeforeafterboth--- a/runtime/common/ethereum/sponsoring/refungible.rs
+++ b/runtime/common/ethereum/sponsoring/refungible.rs
@@ -16,7 +16,6 @@
//! Implements EVM sponsoring logic via TransactionValidityHack
-use core::convert::TryInto;
use pallet_common::CollectionHandle;
use pallet_evm::account::CrossAccountId;
use pallet_fungible::Config as FungibleConfig;
@@ -95,7 +94,7 @@
..
} => {
let token_id = TokenId::try_from(token_id).ok()?;
- withdraw_set_token_property::<T>(&collection, &who, &token_id, key.len() + value.len())
+ withdraw_set_token_property::<T>(&collection, who, &token_id, key.len() + value.len())
}
}
}
@@ -242,7 +241,7 @@
MintCross { .. } => withdraw_create_item::<T>(
&collection,
- &who,
+ who,
&CreateItemData::NFT(CreateNftData::default()),
),
@@ -250,7 +249,7 @@
| TransferFromCross { token_id, .. }
| Transfer { token_id, .. } => {
let token_id = TokenId::try_from(token_id).ok()?;
- withdraw_transfer::<T>(&collection, &who, &token_id)
+ withdraw_transfer::<T>(&collection, who, &token_id)
}
}
}
@@ -275,7 +274,7 @@
| MintWithTokenUri { .. }
| MintWithTokenUriCheckId { .. } => withdraw_create_item::<T>(
&collection,
- &who,
+ who,
&CreateItemData::NFT(CreateNftData::default()),
),
}
@@ -311,18 +310,15 @@
Transfer { .. } => {
let RefungibleTokenHandle(handle, token_id) = token;
- let token_id = token_id.try_into().ok()?;
- withdraw_transfer::<T>(&handle, &who, &token_id)
+ withdraw_transfer::<T>(&handle, who, &token_id)
}
TransferFrom { from, .. } => {
let RefungibleTokenHandle(handle, token_id) = token;
- let token_id = token_id.try_into().ok()?;
let from = T::CrossAccountId::from_eth(from);
withdraw_transfer::<T>(&handle, &from, &token_id)
}
Approve { .. } => {
let RefungibleTokenHandle(handle, token_id) = token;
- let token_id = token_id.try_into().ok()?;
withdraw_approve::<T>(&handle, who.as_sub(), &token_id)
}
}
@@ -351,13 +347,11 @@
TransferCross { .. } | TransferFromCross { .. } => {
let RefungibleTokenHandle(handle, token_id) = token;
- let token_id = token_id.try_into().ok()?;
- withdraw_transfer::<T>(&handle, &who, &token_id)
+ withdraw_transfer::<T>(&handle, who, &token_id)
}
ApproveCross { .. } => {
let RefungibleTokenHandle(handle, token_id) = token;
- let token_id = token_id.try_into().ok()?;
withdraw_approve::<T>(&handle, who.as_sub(), &token_id)
}
}
runtime/common/mod.rsdiffbeforeafterboth--- a/runtime/common/mod.rs
+++ b/runtime/common/mod.rs
@@ -204,10 +204,7 @@
&[],
);
- let should_upgrade = match version {
- None => true,
- Some(_) => false,
- };
+ let should_upgrade = version.is_none();
if should_upgrade {
log::info!(
@@ -220,7 +217,7 @@
.cloned()
.filter_map(|authority_id| {
weight.saturating_accrue(<Runtime as frame_system::Config>::DbWeight::get().reads_writes(1, 1));
- let vec = authority_id.clone().to_raw_vec();
+ let vec = authority_id.to_raw_vec();
let slice = vec.as_slice();
let array: Option<[u8; 32]> = match slice.try_into() {
Ok(a) => Some(a),
@@ -248,20 +245,20 @@
.into_iter()
.map(|(acc, aura)| {
(
- acc.clone(), // account id
- acc, // validator id
- SessionKeys { aura: aura.clone() }, // session keys
+ acc.clone(), // account id
+ acc, // validator id
+ SessionKeys { aura }, // session keys
)
})
.collect::<Vec<_>>();
- for (account, val, keys) in keys.iter().cloned() {
+ for (account, val, keys) in keys.iter() {
for id in <Runtime as pallet_session::Config>::Keys::key_ids() {
- <pallet_session::KeyOwner<Runtime>>::insert((*id, keys.get_raw(*id)), &val)
+ <pallet_session::KeyOwner<Runtime>>::insert((*id, keys.get_raw(*id)), val)
}
- <pallet_session::NextKeys<Runtime>>::insert(&val, &keys);
+ <pallet_session::NextKeys<Runtime>>::insert(val, keys);
// todo exercise caution, the following is taken from genesis
- if frame_system::Pallet::<Runtime>::inc_consumers_without_limit(&account)
+ if frame_system::Pallet::<Runtime>::inc_consumers_without_limit(account)
.is_err()
{
log::warn!(
@@ -271,7 +268,7 @@
// genesis) so it's really not a big deal and we assume that the user wants to
// do this since it's the only way a non-endowed account can contain a session
// key.
- frame_system::Pallet::<Runtime>::inc_providers(&account);
+ frame_system::Pallet::<Runtime>::inc_providers(account);
}
}
runtime/common/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -84,7 +84,7 @@
fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
let budget = up_data_structs::budget::Value::new(10);
- Ok(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?)
+ <pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)
}
fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))
runtime/common/sponsoring.rsdiffbeforeafterboth--- a/runtime/common/sponsoring.rs
+++ b/runtime/common/sponsoring.rs
@@ -240,7 +240,7 @@
withdraw_set_token_property(
&collection,
&T::CrossAccountId::from_sub(who.clone()),
- &token_id,
+ token_id,
// No overflow may happen, as data larger than usize can't reach here
properties.iter().map(|p| p.key.len() + p.value.len()).sum(),
)
test-pallets/utils/src/lib.rsdiffbeforeafterboth--- a/test-pallets/utils/src/lib.rs
+++ b/test-pallets/utils/src/lib.rs
@@ -170,7 +170,7 @@
fn ensure_origin_and_enabled(origin: OriginFor<T>) -> DispatchResult {
ensure_signed(origin)?;
<Enabled<T>>::get()
- .then(|| ())
+ .then_some(())
.ok_or(<Error<T>>::TestPalletDisabled.into())
}
}