difftreelog
fix revert set_allowance
in: master
8 files changed
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1298,7 +1298,6 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo;
fn transfer_from(
&self,
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -226,7 +226,6 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- _nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
ensure!(
token == TokenId::default(),
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -308,15 +308,14 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
with_weight(
if amount == 1 {
- <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender), nesting_budget)
+ <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))
} else {
- <Pallet<T>>::set_allowance(self, &sender, token, None, nesting_budget)
+ <Pallet<T>>::set_allowance(self, &sender, token, None)
},
<CommonWeights<T>>::approve(),
)
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/>.1617extern crate alloc;18use core::{19 char::{REPLACEMENT_CHARACTER, decode_utf16},20 convert::TryInto,21};22use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};23use frame_support::BoundedVec;24use up_data_structs::{25 TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey,26 CollectionPropertiesVec,27};28use pallet_evm_coder_substrate::dispatch_to_evm;29use sp_std::vec::Vec;30use pallet_common::{31 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, token_uri_key},32 CollectionHandle, CollectionPropertyPermissions,33};34use pallet_evm::{account::CrossAccountId, PrecompileHandle};35use pallet_evm_coder_substrate::call;36use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};3738use crate::{39 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,40 SelfWeightOf, weights::WeightInfo, TokenProperties,41};4243#[solidity_interface(name = "TokenProperties")]44impl<T: Config> NonfungibleHandle<T> {45 fn set_token_property_permission(46 &mut self,47 caller: caller,48 key: string,49 is_mutable: bool,50 collection_admin: bool,51 token_owner: bool,52 ) -> Result<()> {53 let caller = T::CrossAccountId::from_eth(caller);54 <Pallet<T>>::set_property_permission(55 self,56 &caller,57 PropertyKeyPermission {58 key: <Vec<u8>>::from(key)59 .try_into()60 .map_err(|_| "too long key")?,61 permission: PropertyPermission {62 mutable: is_mutable,63 collection_admin,64 token_owner,65 },66 },67 )68 .map_err(dispatch_to_evm::<T>)69 }7071 fn set_property(72 &mut self,73 caller: caller,74 token_id: uint256,75 key: string,76 value: bytes,77 ) -> Result<()> {78 let caller = T::CrossAccountId::from_eth(caller);79 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;80 let key = <Vec<u8>>::from(key)81 .try_into()82 .map_err(|_| "key too long")?;83 let value = value.try_into().map_err(|_| "value too long")?;8485 <Pallet<T>>::set_token_property(self, &caller, TokenId(token_id), Property { key, value })86 .map_err(dispatch_to_evm::<T>)87 }8889 fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {90 let caller = T::CrossAccountId::from_eth(caller);91 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;92 let key = <Vec<u8>>::from(key)93 .try_into()94 .map_err(|_| "key too long")?;9596 <Pallet<T>>::delete_token_property(self, &caller, TokenId(token_id), key)97 .map_err(dispatch_to_evm::<T>)98 }99100 /// Throws error if key not found101 fn property(&self, token_id: uint256, key: string) -> Result<bytes> {102 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;103 let key = <Vec<u8>>::from(key)104 .try_into()105 .map_err(|_| "key too long")?;106107 let props = <TokenProperties<T>>::get((self.id, token_id));108 let prop = props.get(&key).ok_or("key not found")?;109110 Ok(prop.to_vec())111 }112}113114#[derive(ToLog)]115pub enum ERC721Events {116 Transfer {117 #[indexed]118 from: address,119 #[indexed]120 to: address,121 #[indexed]122 token_id: uint256,123 },124 Approval {125 #[indexed]126 owner: address,127 #[indexed]128 approved: address,129 #[indexed]130 token_id: uint256,131 },132 #[allow(dead_code)]133 ApprovalForAll {134 #[indexed]135 owner: address,136 #[indexed]137 operator: address,138 approved: bool,139 },140}141142#[derive(ToLog)]143pub enum ERC721MintableEvents {144 #[allow(dead_code)]145 MintingFinished {},146}147148#[solidity_interface(name = "ERC721Metadata")]149impl<T: Config> NonfungibleHandle<T> {150 fn name(&self) -> Result<string> {151 Ok(decode_utf16(self.name.iter().copied())152 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))153 .collect::<string>())154 }155156 fn symbol(&self) -> Result<string> {157 Ok(string::from_utf8_lossy(&self.token_prefix).into())158 }159160 /// Returns token's const_metadata161 #[solidity(rename_selector = "tokenURI")]162 fn token_uri(&self, token_id: uint256) -> Result<string> {163 let key = token_uri_key();164 if !has_token_permission::<T>(self.id, &key) {165 return Err("No tokenURI permission".into());166 }167168 self.consume_store_reads(1)?;169 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;170171 let properties = <TokenProperties<T>>::try_get((self.id, token_id))172 .map_err(|_| Error::Revert("Token properties not found".into()))?;173 if let Some(property) = properties.get(&key) {174 return Ok(string::from_utf8_lossy(property).into());175 }176177 Err("Property tokenURI not found".into())178 }179}180181#[solidity_interface(name = "ERC721Enumerable")]182impl<T: Config> NonfungibleHandle<T> {183 fn token_by_index(&self, index: uint256) -> Result<uint256> {184 Ok(index)185 }186187 /// Not implemented188 fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {189 // TODO: Not implemetable190 Err("not implemented".into())191 }192193 fn total_supply(&self) -> Result<uint256> {194 self.consume_store_reads(1)?;195 Ok(<Pallet<T>>::total_supply(self).into())196 }197}198199#[solidity_interface(name = "ERC721", events(ERC721Events))]200impl<T: Config> NonfungibleHandle<T> {201 fn balance_of(&self, owner: address) -> Result<uint256> {202 self.consume_store_reads(1)?;203 let owner = T::CrossAccountId::from_eth(owner);204 let balance = <AccountBalance<T>>::get((self.id, owner));205 Ok(balance.into())206 }207 fn owner_of(&self, token_id: uint256) -> Result<address> {208 self.consume_store_reads(1)?;209 let token: TokenId = token_id.try_into()?;210 Ok(*<TokenData<T>>::get((self.id, token))211 .ok_or("token not found")?212 .owner213 .as_eth())214 }215 /// Not implemented216 fn safe_transfer_from_with_data(217 &mut self,218 _from: address,219 _to: address,220 _token_id: uint256,221 _data: bytes,222 _value: value,223 ) -> Result<void> {224 // TODO: Not implemetable225 Err("not implemented".into())226 }227 /// Not implemented228 fn safe_transfer_from(229 &mut self,230 _from: address,231 _to: address,232 _token_id: uint256,233 _value: value,234 ) -> Result<void> {235 // TODO: Not implemetable236 Err("not implemented".into())237 }238239 #[weight(<SelfWeightOf<T>>::transfer_from())]240 fn transfer_from(241 &mut self,242 caller: caller,243 from: address,244 to: address,245 token_id: uint256,246 _value: value,247 ) -> Result<void> {248 let caller = T::CrossAccountId::from_eth(caller);249 let from = T::CrossAccountId::from_eth(from);250 let to = T::CrossAccountId::from_eth(to);251 let token = token_id.try_into()?;252 let budget = self253 .recorder254 .weight_calls_budget(<StructureWeight<T>>::find_parent());255256 <Pallet<T>>::transfer_from(self, &caller, &from, &to, token, &budget)257 .map_err(dispatch_to_evm::<T>)?;258 Ok(())259 }260261 #[weight(<SelfWeightOf<T>>::approve())]262 fn approve(263 &mut self,264 caller: caller,265 approved: address,266 token_id: uint256,267 _value: value,268 ) -> Result<void> {269 let caller = T::CrossAccountId::from_eth(caller);270 let approved = T::CrossAccountId::from_eth(approved);271 let token = token_id.try_into()?;272273 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))274 .map_err(dispatch_to_evm::<T>)?;275 Ok(())276 }277278 /// Not implemented279 fn set_approval_for_all(280 &mut self,281 _caller: caller,282 _operator: address,283 _approved: bool,284 ) -> Result<void> {285 // TODO: Not implemetable286 Err("not implemented".into())287 }288289 /// Not implemented290 fn get_approved(&self, _token_id: uint256) -> Result<address> {291 // TODO: Not implemetable292 Err("not implemented".into())293 }294295 /// Not implemented296 fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {297 // TODO: Not implemetable298 Err("not implemented".into())299 }300}301302#[solidity_interface(name = "ERC721Burnable")]303impl<T: Config> NonfungibleHandle<T> {304 #[weight(<SelfWeightOf<T>>::burn_item())]305 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {306 let caller = T::CrossAccountId::from_eth(caller);307 let token = token_id.try_into()?;308309 <Pallet<T>>::burn(self, &caller, token).map_err(dispatch_to_evm::<T>)?;310 Ok(())311 }312}313314#[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]315impl<T: Config> NonfungibleHandle<T> {316 fn minting_finished(&self) -> Result<bool> {317 Ok(false)318 }319320 /// `token_id` should be obtained with `next_token_id` method,321 /// unlike standard, you can't specify it manually322 #[weight(<SelfWeightOf<T>>::create_item())]323 fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {324 let caller = T::CrossAccountId::from_eth(caller);325 let to = T::CrossAccountId::from_eth(to);326 let token_id: u32 = token_id.try_into()?;327 let budget = self328 .recorder329 .weight_calls_budget(<StructureWeight<T>>::find_parent());330331 if <TokensMinted<T>>::get(self.id)332 .checked_add(1)333 .ok_or("item id overflow")?334 != token_id335 {336 return Err("item id should be next".into());337 }338339 <Pallet<T>>::create_item(340 self,341 &caller,342 CreateItemData::<T> {343 properties: BoundedVec::default(),344 owner: to,345 },346 &budget,347 )348 .map_err(dispatch_to_evm::<T>)?;349350 Ok(true)351 }352353 /// `token_id` should be obtained with `next_token_id` method,354 /// unlike standard, you can't specify it manually355 #[solidity(rename_selector = "mintWithTokenURI")]356 #[weight(<SelfWeightOf<T>>::create_item())]357 fn mint_with_token_uri(358 &mut self,359 caller: caller,360 to: address,361 token_id: uint256,362 token_uri: string,363 ) -> Result<bool> {364 let key = token_uri_key();365 let permission = get_token_permission::<T>(self.id, &key)?;366 if !permission.collection_admin {367 return Err("Operation is not allowed".into());368 }369370 let caller = T::CrossAccountId::from_eth(caller);371 let to = T::CrossAccountId::from_eth(to);372 let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;373 let budget = self374 .recorder375 .weight_calls_budget(<StructureWeight<T>>::find_parent());376377 if <TokensMinted<T>>::get(self.id)378 .checked_add(1)379 .ok_or("item id overflow")?380 != token_id381 {382 return Err("item id should be next".into());383 }384385 let mut properties = CollectionPropertiesVec::default();386 properties387 .try_push(Property {388 key,389 value: token_uri390 .into_bytes()391 .try_into()392 .map_err(|_| "token uri is too long")?,393 })394 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;395396 <Pallet<T>>::create_item(397 self,398 &caller,399 CreateItemData::<T> {400 properties,401 owner: to,402 },403 &budget,404 )405 .map_err(dispatch_to_evm::<T>)?;406 Ok(true)407 }408409 /// Not implemented410 fn finish_minting(&mut self, _caller: caller) -> Result<bool> {411 Err("not implementable".into())412 }413}414415fn get_token_permission<T: Config>(416 collection_id: CollectionId,417 key: &PropertyKey,418) -> Result<PropertyPermission> {419 let token_property_permissions = CollectionPropertyPermissions::<T>::try_get(collection_id)420 .map_err(|_| Error::Revert("No permissions for collection".into()))?;421 let a = token_property_permissions422 .get(key)423 .map(|p| p.clone())424 .ok_or_else(|| Error::Revert("No permission".into()))?;425 Ok(a)426}427428fn has_token_permission<T: Config>(collection_id: CollectionId, key: &PropertyKey) -> bool {429 if let Ok(token_property_permissions) =430 CollectionPropertyPermissions::<T>::try_get(collection_id)431 {432 return token_property_permissions.contains_key(key);433 }434435 false436}437438#[solidity_interface(name = "ERC721UniqueExtensions")]439impl<T: Config> NonfungibleHandle<T> {440 #[weight(<SelfWeightOf<T>>::transfer())]441 fn transfer(442 &mut self,443 caller: caller,444 to: address,445 token_id: uint256,446 _value: value,447 ) -> Result<void> {448 let caller = T::CrossAccountId::from_eth(caller);449 let to = T::CrossAccountId::from_eth(to);450 let token = token_id.try_into()?;451 let budget = self452 .recorder453 .weight_calls_budget(<StructureWeight<T>>::find_parent());454455 <Pallet<T>>::transfer(self, &caller, &to, token, &budget).map_err(dispatch_to_evm::<T>)?;456 Ok(())457 }458459 #[weight(<SelfWeightOf<T>>::burn_from())]460 fn burn_from(461 &mut self,462 caller: caller,463 from: address,464 token_id: uint256,465 _value: value,466 ) -> Result<void> {467 let caller = T::CrossAccountId::from_eth(caller);468 let from = T::CrossAccountId::from_eth(from);469 let token = token_id.try_into()?;470 let budget = self471 .recorder472 .weight_calls_budget(<StructureWeight<T>>::find_parent());473474 <Pallet<T>>::burn_from(self, &caller, &from, token, &budget)475 .map_err(dispatch_to_evm::<T>)?;476 Ok(())477 }478479 fn next_token_id(&self) -> Result<uint256> {480 self.consume_store_reads(1)?;481 Ok(<TokensMinted<T>>::get(self.id)482 .checked_add(1)483 .ok_or("item id overflow")?484 .into())485 }486487 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]488 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {489 let caller = T::CrossAccountId::from_eth(caller);490 let to = T::CrossAccountId::from_eth(to);491 let mut expected_index = <TokensMinted<T>>::get(self.id)492 .checked_add(1)493 .ok_or("item id overflow")?;494 let budget = self495 .recorder496 .weight_calls_budget(<StructureWeight<T>>::find_parent());497498 let total_tokens = token_ids.len();499 for id in token_ids.into_iter() {500 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;501 if id != expected_index {502 return Err("item id should be next".into());503 }504 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;505 }506 let data = (0..total_tokens)507 .map(|_| CreateItemData::<T> {508 properties: BoundedVec::default(),509 owner: to.clone(),510 })511 .collect();512513 <Pallet<T>>::create_multiple_items(self, &caller, data, &budget)514 .map_err(dispatch_to_evm::<T>)?;515 Ok(true)516 }517518 #[solidity(rename_selector = "mintBulkWithTokenURI")]519 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]520 fn mint_bulk_with_token_uri(521 &mut self,522 caller: caller,523 to: address,524 tokens: Vec<(uint256, string)>,525 ) -> Result<bool> {526 let key = token_uri_key();527 let caller = T::CrossAccountId::from_eth(caller);528 let to = T::CrossAccountId::from_eth(to);529 let mut expected_index = <TokensMinted<T>>::get(self.id)530 .checked_add(1)531 .ok_or("item id overflow")?;532 let budget = self533 .recorder534 .weight_calls_budget(<StructureWeight<T>>::find_parent());535536 let mut data = Vec::with_capacity(tokens.len());537 for (id, token_uri) in tokens {538 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;539 if id != expected_index {540 return Err("item id should be next".into());541 }542 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;543544 let mut properties = CollectionPropertiesVec::default();545 properties546 .try_push(Property {547 key: key.clone(),548 value: token_uri549 .into_bytes()550 .try_into()551 .map_err(|_| "token uri is too long")?,552 })553 .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;554555 data.push(CreateItemData::<T> {556 properties,557 owner: to.clone(),558 });559 }560561 <Pallet<T>>::create_multiple_items(self, &caller, data, &budget)562 .map_err(dispatch_to_evm::<T>)?;563 Ok(true)564 }565}566567#[solidity_interface(568 name = "UniqueNFT",569 is(570 ERC721,571 ERC721Metadata,572 ERC721Enumerable,573 ERC721UniqueExtensions,574 ERC721Mintable,575 ERC721Burnable,576 via("CollectionHandle<T>", common_mut, Collection),577 TokenProperties,578 )579)]580impl<T: Config> NonfungibleHandle<T> {}581582// Not a tests, but code generators583generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);584generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);585586impl<T: Config> CommonEvmHandler for NonfungibleHandle<T> {587 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");588589 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {590 call::<T, UniqueNFTCall<T>, _, _>(handle, self)591 }592}pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -878,7 +878,6 @@
sender: &T::CrossAccountId,
token: TokenId,
spender: Option<&T::CrossAccountId>,
- nesting_budget: &dyn Budget,
) -> DispatchResult {
if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(sender)?;
@@ -890,16 +889,10 @@
if let Some(spender) = spender {
<PalletCommon<T>>::ensure_correct_receiver(spender)?;
}
-
- let is_owned = <PalletStructure<T>>::check_indirectly_owned(
- sender.clone(),
- collection.id,
- token,
- None,
- nesting_budget
- )?;
- if !is_owned {
+ let token_data =
+ <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
+ if &token_data.owner != sender {
ensure!(
collection.ignores_owned_amount(sender),
<CommonError<T>>::CantApproveMoreThanOwned
@@ -926,9 +919,6 @@
// `from`, `to` checked in [`transfer`]
collection.check_allowlist(spender)?;
}
- if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {
- return Ok(());
- }
if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {
// TODO: should collection owner be allowed to perform this transfer?
ensure!(
@@ -943,6 +933,9 @@
);
return Ok(());
}
+ if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {
+ return Ok(());
+ }
ensure!(
collection.ignores_allowance(spender),
<CommonError<T>>::ApprovedValueTooLow
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -414,13 +414,14 @@
let is_approval_required = cross_sender != spender;
if is_approval_required {
- <PalletNft<T>>::set_allowance(
- &collection,
- &cross_sender,
- nft_id,
- Some(&spender),
- &budget
- ).map_err(Self::map_common_err_to_proxy)?;
+ // FIXME
+ // <PalletNft<T>>::set_allowance(
+ // &collection,
+ // &cross_sender,
+ // nft_id,
+ // Some(&spender),
+ // &budget
+ // ).map_err(Self::map_common_err_to_proxy)?;
return Ok(());
}
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -254,7 +254,6 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- _nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
with_weight(
<Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -815,9 +815,8 @@
#[transactional]
pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
- let budget = budget::Value::new(NESTING_BUDGET);
- dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount, &budget))
+ dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))
}
/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.