git.delta.rocks / unique-network / refs/commits / 8dd063b578e3

difftreelog

Merge pull request #869 from UniqueNetwork/feature/generalize_2_methods

Yaroslav Bolyukin2023-02-03parents: #f1a5ba7 #ccafa37.patch.diff
in: master
Feature/generalize_2_methods

34 files changed

modifiedCargo.lockdiffbeforeafterboth
63616361
6362[[package]]6362[[package]]
6363name = "pallet-fungible"6363name = "pallet-fungible"
6364version = "0.1.9"6364version = "0.1.10"
6365dependencies = [6365dependencies = [
6366 "evm-coder",6366 "evm-coder",
6367 "frame-benchmarking",6367 "frame-benchmarking",
67746774
6775[[package]]6775[[package]]
6776name = "pallet-refungible"6776name = "pallet-refungible"
6777version = "0.2.12"6777version = "0.2.13"
6778dependencies = [6778dependencies = [
6779 "evm-coder",6779 "evm-coder",
6780 "frame-benchmarking",6780 "frame-benchmarking",
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
20use sp_std::{vec, vec::Vec};20use sp_std::{vec, vec::Vec};
21use evm_coder::{AbiCoder, types::Address};21use evm_coder::{
22 AbiCoder,
23 types::{Address, String},
24};
22pub use pallet_evm::{Config, account::CrossAccountId};25pub use pallet_evm::{Config, account::CrossAccountId};
23use sp_core::{H160, U256};26use sp_core::{H160, U256};
390 }393 }
391}394}
395
396/// Data for creation token with uri.
397#[derive(Debug, AbiCoder)]
398pub struct TokenUri {
399 /// Id of new token.
400 pub id: U256,
401
402 /// Uri of new token.
403 pub uri: String,
404}
392405
393/// Nested collections.406/// Nested collections.
394#[derive(Debug, Default, AbiCoder)]407#[derive(Debug, Default, AbiCoder)]
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
66 ensure,66 ensure,
67 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},67 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},
68 dispatch::Pays,68 dispatch::Pays,
69 transactional,69 transactional, fail,
70};70};
71use pallet_evm::GasWeightMapping;71use pallet_evm::GasWeightMapping;
72use up_data_structs::{72use up_data_structs::{
73 AccessMode,
73 COLLECTION_NUMBER_LIMIT,74 COLLECTION_NUMBER_LIMIT,
74 Collection,75 Collection,
75 RpcCollection,76 RpcCollection,
125use sp_core::H160;126use sp_core::H160;
126use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};127use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
128
129use crate::erc::CollectionHelpersEvents;
127#[cfg(feature = "runtime-benchmarks")]130#[cfg(feature = "runtime-benchmarks")]
128pub mod benchmarking;131pub mod benchmarking;
129pub mod dispatch;132pub mod dispatch;
1264 Ok(())1267 Ok(())
1265 }1268 }
1269
1270 /// A batch operation to add, edit or remove properties for a token.
1271 /// It sets or removes a token's properties according to
1272 /// `properties_updates` contents:
1273 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`
1274 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.
1275 ///
1276 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.
1277 /// - `is_token_create`: Indicates that method is called during token initialization.
1278 /// Allows to bypass ownership check.
1279 ///
1280 /// All affected properties should have `mutable` permission
1281 /// to be **deleted** or to be **set more than once**,
1282 /// and the sender should have permission to edit those properties.
1283 ///
1284 /// This function fires an event for each property change.
1285 /// In case of an error, all the changes (including the events) will be reverted
1286 /// since the function is transactional.
1287 pub fn modify_token_properties(
1288 collection: &CollectionHandle<T>,
1289 sender: &T::CrossAccountId,
1290 token_id: TokenId,
1291 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
1292 is_token_create: bool,
1293 mut stored_properties: Properties,
1294 is_token_owner: impl Fn() -> Result<bool, DispatchError>,
1295 set_token_properties: impl FnOnce(Properties),
1296 ) -> DispatchResult {
1297 let is_collection_admin = collection.is_owner_or_admin(sender);
1298 let permissions = Self::property_permissions(collection.id);
1299
1300 let mut token_owner_result = None;
1301 let mut is_token_owner = || -> Result<bool, DispatchError> {
1302 *token_owner_result.get_or_insert_with(&is_token_owner)
1303 };
1304
1305 for (key, value) in properties_updates {
1306 let permission = permissions
1307 .get(&key)
1308 .cloned()
1309 .unwrap_or_else(PropertyPermission::none);
1310
1311 let is_property_exists = stored_properties.get(&key).is_some();
1312
1313 match permission {
1314 PropertyPermission { mutable: false, .. } if is_property_exists => {
1315 return Err(<Error<T>>::NoPermission.into());
1316 }
1317
1318 PropertyPermission {
1319 collection_admin,
1320 token_owner,
1321 ..
1322 } => {
1323 //TODO: investigate threats during public minting.
1324 let is_token_create =
1325 is_token_create && (collection_admin || token_owner) && value.is_some();
1326 if !(is_token_create
1327 || (collection_admin && is_collection_admin)
1328 || (token_owner && is_token_owner()?))
1329 {
1330 fail!(<Error<T>>::NoPermission);
1331 }
1332 }
1333 }
1334
1335 match value {
1336 Some(value) => {
1337 stored_properties
1338 .try_set(key.clone(), value)
1339 .map_err(<Error<T>>::from)?;
1340
1341 Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));
1342 }
1343 None => {
1344 stored_properties.remove(&key).map_err(<Error<T>>::from)?;
1345
1346 Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));
1347 }
1348 }
1349
1350 <PalletEvm<T>>::deposit_log(
1351 CollectionHelpersEvents::TokenChanged {
1352 collection_id: eth::collection_id_to_address(collection.id),
1353 token_id: token_id.into(),
1354 }
1355 .to_log(T::ContractAddress::get()),
1356 );
1357 }
1358
1359 set_token_properties(stored_properties);
1360
1361 Ok(())
1362 }
1363
1364 /// Sets or unsets the approval of a given operator.
1365 ///
1366 /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.
1367 /// - `owner`: Token owner
1368 /// - `operator`: Operator
1369 /// - `approve`: Should operator status be granted or revoked?
1370 pub fn set_allowance_for_all(
1371 collection: &CollectionHandle<T>,
1372 owner: &T::CrossAccountId,
1373 operator: &T::CrossAccountId,
1374 approve: bool,
1375 set_allowance: impl FnOnce(),
1376 log: evm_coder::ethereum::Log,
1377 ) -> DispatchResult {
1378 if collection.permissions.access() == AccessMode::AllowList {
1379 collection.check_allowlist(owner)?;
1380 collection.check_allowlist(operator)?;
1381 }
1382
1383 Self::ensure_correct_receiver(operator)?;
1384
1385 set_allowance();
1386
1387 <PalletEvm<T>>::deposit_log(log);
1388 Self::deposit_event(Event::ApprovedForAll(
1389 collection.id,
1390 owner.clone(),
1391 operator.clone(),
1392 approve,
1393 ));
1394 Ok(())
1395 }
12661396
1267 /// Set collection property.1397 /// Set collection property.
1268 ///1398 ///
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/CHANGELOG.mddiffbeforeafterboth
44
5<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->
66
7## [0.1.10] - 2023-02-01
8
9### Added
10
11- The functions `allowanceCross` to `ERC20UniqueExtensions` interface.
12
7## [0.1.9] - 2022-12-0113## [0.1.9] - 2022-12-01
814
9### Added15### Added
modifiedpallets/fungible/Cargo.tomldiffbeforeafterboth
2edition = "2021"2edition = "2021"
3license = "GPLv3"3license = "GPLv3"
4name = "pallet-fungible"4name = "pallet-fungible"
5version = "0.1.9"5version = "0.1.10"
66
7[dependencies]7[dependencies]
8# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.8# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
19extern crate alloc;19extern crate alloc;
20use core::char::{REPLACEMENT_CHARACTER, decode_utf16};20use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
21use core::convert::TryInto;21use core::convert::TryInto;
22use evm_coder::AbiCoder;
22use evm_coder::{23use evm_coder::{
23 abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,24 abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*,
24 weight,25 weight,
27use pallet_common::{28use pallet_common::{
28 CollectionHandle,29 CollectionHandle,
29 erc::{CommonEvmHandler, PrecompileResult, CollectionCall},30 erc::{CommonEvmHandler, PrecompileResult, CollectionCall},
31 eth::CrossAddress,
30};32};
31use sp_std::vec::Vec;33use sp_std::vec::Vec;
32use pallet_evm::{account::CrossAccountId, PrecompileHandle};34use pallet_evm::{account::CrossAccountId, PrecompileHandle};
57 },59 },
58}60}
61
62#[derive(AbiCoder, Debug)]
63pub struct AmountForAddress {
64 to: Address,
65 amount: U256,
66}
5967
60#[solidity_interface(name = ERC20, events(ERC20Events), expect_selector = 0x942e8b22)]68#[solidity_interface(name = ERC20, events(ERC20Events), expect_selector = 0x942e8b22)]
61impl<T: Config> FungibleHandle<T> {69impl<T: Config> FungibleHandle<T> {
161where169where
162 T::AccountId: From<[u8; 32]>,170 T::AccountId: From<[u8; 32]>,
163{171{
172 /// @dev Function to check the amount of tokens that an owner allowed to a spender.
173 /// @param owner crossAddress The address which owns the funds.
174 /// @param spender crossAddress The address which will spend the funds.
175 /// @return A uint256 specifying the amount of tokens still available for the spender.
176 fn allowance_cross(&self, owner: CrossAddress, spender: CrossAddress) -> Result<U256> {
177 let owner = owner.into_sub_cross_account::<T>()?;
178 let spender = spender.into_sub_cross_account::<T>()?;
179
180 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())
181 }
182
164 /// @notice A description for the collection.183 /// @notice A description for the collection.
165 fn description(&self) -> Result<String> {184 fn description(&self) -> Result<String> {
172 fn mint_cross(191 fn mint_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {
173 &mut self,
174 caller: Caller,
175 to: pallet_common::eth::CrossAddress,
176 amount: U256,
177 ) -> Result<bool> {
178 let caller = T::CrossAccountId::from_eth(caller);192 let caller = T::CrossAccountId::from_eth(caller);
179 let to = to.into_sub_cross_account::<T>()?;193 let to = to.into_sub_cross_account::<T>()?;
190 fn approve_cross(204 fn approve_cross(
191 &mut self,205 &mut self,
192 caller: Caller,206 caller: Caller,
193 spender: pallet_common::eth::CrossAddress,207 spender: CrossAddress,
194 amount: U256,208 amount: U256,
195 ) -> Result<bool> {209 ) -> Result<bool> {
196 let caller = T::CrossAccountId::from_eth(caller);210 let caller = T::CrossAccountId::from_eth(caller);
231 fn burn_from_cross(245 fn burn_from_cross(
232 &mut self,246 &mut self,
233 caller: Caller,247 caller: Caller,
234 from: pallet_common::eth::CrossAddress,248 from: CrossAddress,
235 amount: U256,249 amount: U256,
236 ) -> Result<bool> {250 ) -> Result<bool> {
237 let caller = T::CrossAccountId::from_eth(caller);251 let caller = T::CrossAccountId::from_eth(caller);
249 /// Mint tokens for multiple accounts.263 /// Mint tokens for multiple accounts.
250 /// @param amounts array of pairs of account address and amount264 /// @param amounts array of pairs of account address and amount
251 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]265 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]
252 fn mint_bulk(&mut self, caller: Caller, amounts: Vec<(Address, U256)>) -> Result<bool> {266 fn mint_bulk(&mut self, caller: Caller, amounts: Vec<AmountForAddress>) -> Result<bool> {
253 let caller = T::CrossAccountId::from_eth(caller);267 let caller = T::CrossAccountId::from_eth(caller);
254 let budget = self268 let budget = self
255 .recorder269 .recorder
256 .weight_calls_budget(<StructureWeight<T>>::find_parent());270 .weight_calls_budget(<StructureWeight<T>>::find_parent());
257 let amounts = amounts271 let amounts = amounts
258 .into_iter()272 .into_iter()
259 .map(|(to, amount)| {273 .map(|AmountForAddress { to, amount }| {
260 Ok((274 Ok((
261 T::CrossAccountId::from_eth(to),275 T::CrossAccountId::from_eth(to),
262 amount.try_into().map_err(|_| "amount overflow")?,276 amount.try_into().map_err(|_| "amount overflow")?,
273 fn transfer_cross(287 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {
274 &mut self,
275 caller: Caller,
276 to: pallet_common::eth::CrossAddress,
277 amount: U256,
278 ) -> Result<bool> {
279 let caller = T::CrossAccountId::from_eth(caller);288 let caller = T::CrossAccountId::from_eth(caller);
280 let to = to.into_sub_cross_account::<T>()?;289 let to = to.into_sub_cross_account::<T>()?;
291 fn transfer_from_cross(300 fn transfer_from_cross(
292 &mut self,301 &mut self,
293 caller: Caller,302 caller: Caller,
294 from: pallet_common::eth::CrossAddress,303 from: CrossAddress,
295 to: pallet_common::eth::CrossAddress,304 to: CrossAddress,
296 amount: U256,305 amount: U256,
297 ) -> Result<bool> {306 ) -> Result<bool> {
298 let caller = T::CrossAccountId::from_eth(caller);307 let caller = T::CrossAccountId::from_eth(caller);
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
165 pub type Allowance<T: Config> = StorageNMap<165 pub type Allowance<T: Config> = StorageNMap<
166 Key = (166 Key = (
167 Key<Twox64Concat, CollectionId>,167 Key<Twox64Concat, CollectionId>,
168 Key<Blake2_128, T::CrossAccountId>,168 Key<Blake2_128, T::CrossAccountId>, // Owner
169 Key<Blake2_128Concat, T::CrossAccountId>,169 Key<Blake2_128Concat, T::CrossAccountId>, // Spender
170 ),170 ),
171 Value = u128,171 Value = u128,
172 QueryKind = ValueQuery,172 QueryKind = ValueQuery,
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
511 bytes value;511 bytes value;
512}512}
513513
514/// @dev the ERC-165 identifier for this interface is 0x65789571514/// @dev the ERC-165 identifier for this interface is 0x85d7dea6
515contract ERC20UniqueExtensions is Dummy, ERC165 {515contract ERC20UniqueExtensions is Dummy, ERC165 {
516 /// @dev Function to check the amount of tokens that an owner allowed to a spender.
517 /// @param owner crossAddress The address which owns the funds.
518 /// @param spender crossAddress The address which will spend the funds.
519 /// @return A uint256 specifying the amount of tokens still available for the spender.
520 /// @dev EVM selector for this function is: 0xe0af4bd7,
521 /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
522 function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) public view returns (uint256) {
523 require(false, stub_error);
524 owner;
525 spender;
526 dummy;
527 return 0;
528 }
529
516 /// @notice A description for the collection.530 /// @notice A description for the collection.
517 /// @dev EVM selector for this function is: 0x7284e416,531 /// @dev EVM selector for this function is: 0x7284e416,
576 /// @param amounts array of pairs of account address and amount590 /// @param amounts array of pairs of account address and amount
577 /// @dev EVM selector for this function is: 0x1acf2d55,591 /// @dev EVM selector for this function is: 0x1acf2d55,
578 /// or in textual repr: mintBulk((address,uint256)[])592 /// or in textual repr: mintBulk((address,uint256)[])
579 function mintBulk(Tuple9[] memory amounts) public returns (bool) {593 function mintBulk(AmountForAddress[] memory amounts) public returns (bool) {
580 require(false, stub_error);594 require(false, stub_error);
581 amounts;595 amounts;
582 dummy = 0;596 dummy = 0;
618 }632 }
619}633}
620634
621/// @dev anonymous struct
622struct Tuple9 {635struct AmountForAddress {
623 address field_0;636 address to;
624 uint256 field_1;637 uint256 amount;
625}638}
626639
627/// @dev the ERC-165 identifier for this interface is 0x40c10f19640/// @dev the ERC-165 identifier for this interface is 0x40c10f19
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
38use pallet_common::{38use pallet_common::{
39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},
41 eth,41 eth::{self, TokenUri},
42};42};
43use pallet_evm::{account::CrossAccountId, PrecompileHandle};43use pallet_evm::{account::CrossAccountId, PrecompileHandle};
44use pallet_evm_coder_substrate::call;44use pallet_evm_coder_substrate::call;
948 &mut self,948 &mut self,
949 caller: Caller,949 caller: Caller,
950 to: Address,950 to: Address,
951 tokens: Vec<(U256, String)>,951 tokens: Vec<TokenUri>,
952 ) -> Result<bool> {952 ) -> Result<bool> {
953 let key = key::url();953 let key = key::url();
954 let caller = T::CrossAccountId::from_eth(caller);954 let caller = T::CrossAccountId::from_eth(caller);
961 .weight_calls_budget(<StructureWeight<T>>::find_parent());961 .weight_calls_budget(<StructureWeight<T>>::find_parent());
962962
963 let mut data = Vec::with_capacity(tokens.len());963 let mut data = Vec::with_capacity(tokens.len());
964 for (id, token_uri) in tokens {964 for TokenUri { id, uri } in tokens {
965 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;965 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;
966 if id != expected_index {966 if id != expected_index {
967 return Err("item id should be next".into());967 return Err("item id should be next".into());
972 properties972 properties
973 .try_push(Property {973 .try_push(Property {
974 key: key.clone(),974 key: key.clone(),
975 value: token_uri975 value: uri
976 .into_bytes()976 .into_bytes()
977 .try_into()977 .try_into()
978 .map_err(|_| "token uri is too long")?,978 .map_err(|_| "token uri is too long")?,
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
101};101};
102use up_data_structs::{102use up_data_structs::{
103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,
104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyKey,
105 PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,105 PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty, TokenChild,
106 TokenChild, AuxPropertyValue, PropertiesPermissionMap,106 AuxPropertyValue, PropertiesPermissionMap,
107};107};
108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
109use pallet_common::{109use pallet_common::{
110 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,110 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,
111 eth::collection_id_to_address, erc::CollectionHelpersEvents,111 eth::collection_id_to_address,
112};112};
113use pallet_structure::{Pallet as PalletStructure, Error as StructureError};113use pallet_structure::{Pallet as PalletStructure, Error as StructureError};
114use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};114use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
115use sp_core::{H160, Get};115use sp_core::H160;
116use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};116use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
117use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};117use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
118use core::ops::Deref;118use core::ops::Deref;
578 }578 }
579579
580 /// A batch operation to add, edit or remove properties for a token.580 /// A batch operation to add, edit or remove properties for a token.
581 /// It sets or removes a token's properties according to
582 /// `properties_updates` contents:
583 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`
584 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.
585 ///581 ///
586 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.582 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.
587 /// - `is_token_create`: Indicates that method is called during token initialization.583 /// - `is_token_create`: Indicates that method is called during token initialization.
603 is_token_create: bool,599 is_token_create: bool,
604 nesting_budget: &dyn Budget,600 nesting_budget: &dyn Budget,
605 ) -> DispatchResult {601 ) -> DispatchResult {
606 let mut collection_admin_status = None;
607 let mut token_owner_result = None;
608
609 let mut is_collection_admin =
610 || *collection_admin_status.get_or_insert_with(|| collection.is_owner_or_admin(sender));
611
612 let mut is_token_owner = || {602 let is_token_owner = || {
613 *token_owner_result.get_or_insert_with(|| -> Result<bool, DispatchError> {
614 let is_owned = <PalletStructure<T>>::check_indirectly_owned(603 let is_owned = <PalletStructure<T>>::check_indirectly_owned(
615 sender.clone(),604 sender.clone(),
616 collection.id,605 collection.id,
620 )?;609 )?;
621610
622 Ok(is_owned)611 Ok(is_owned)
623 })
624 };612 };
625613
626 let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));614 let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
615
627 let permissions = <PalletCommon<T>>::property_permissions(collection.id);616 <PalletCommon<T>>::modify_token_properties(
628
629 for (key, value) in properties_updates {617 collection,
630 let permission = permissions
631 .get(&key)
632 .cloned()
633 .unwrap_or_else(PropertyPermission::none);
634
635 let is_property_exists = stored_properties.get(&key).is_some();
636
637 match permission {
638 PropertyPermission { mutable: false, .. } if is_property_exists => {618 sender,
639 return Err(<CommonError<T>>::NoPermission.into());
640 }
641
642 PropertyPermission {
643 collection_admin,619 token_id,
644 token_owner,620 properties_updates,
645 ..
646 } => {
647 //TODO: investigate threats during public minting.
648 if is_token_create && (collection_admin || token_owner) && value.is_some() {621 is_token_create,
649 // Pass
650 } else if collection_admin && is_collection_admin() {
651 // Pass
652 } else if token_owner && is_token_owner()? {
653 // Pass
654 } else {
655 fail!(<CommonError<T>>::NoPermission);
656 }
657 }
658 }
659
660 match value {
661 Some(value) => {
662 stored_properties
663 .try_set(key.clone(), value)
664 .map_err(<CommonError<T>>::from)?;
665
666 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(
667 collection.id,
668 token_id,
669 key,
670 ));
671 }
672 None => {
673 stored_properties622 stored_properties,
674 .remove(&key)
675 .map_err(<CommonError<T>>::from)?;
676
677 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
678 collection.id,
679 token_id,
680 key,
681 ));
682 }
683 }
684
685 <PalletEvm<T>>::deposit_log(
686 CollectionHelpersEvents::TokenChanged {
687 collection_id: collection_id_to_address(collection.id),
688 token_id: token_id.into(),
689 }
690 .to_log(T::ContractAddress::get()),623 is_token_owner,
691 );
692 }
693
694 <TokenProperties<T>>::set((collection.id, token_id), stored_properties);624 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
695625 )
696 Ok(())
697 }626 }
698627
699 /// Batch operation to add or edit properties for the token628 /// Batch operation to add or edit properties for the token
1418 operator: &T::CrossAccountId,1347 operator: &T::CrossAccountId,
1419 approve: bool,1348 approve: bool,
1420 ) -> DispatchResult {1349 ) -> DispatchResult {
1421 if collection.permissions.access() == AccessMode::AllowList {1350 <PalletCommon<T>>::set_allowance_for_all(
1422 collection.check_allowlist(owner)?;1351 collection,
1423 collection.check_allowlist(operator)?;1352 owner,
1424 }1353 operator,
14251354 approve,
1426 <PalletCommon<T>>::ensure_correct_receiver(operator)?;
1427
1428 // =========
1429
1430 <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve);1355 || <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),
1431 <PalletEvm<T>>::deposit_log(
1432 ERC721Events::ApprovalForAll {1356 ERC721Events::ApprovalForAll {
1433 owner: *owner.as_eth(),1357 owner: *owner.as_eth(),
1434 operator: *operator.as_eth(),1358 operator: *operator.as_eth(),
1435 approved: approve,1359 approved: approve,
1436 }1360 }
1437 .to_log(collection_id_to_address(collection.id)),1361 .to_log(collection_id_to_address(collection.id)),
1438 );1362 )
1439 <PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
1440 collection.id,
1441 owner.clone(),
1442 operator.clone(),
1443 approve,
1444 ));
1445 Ok(())
1446 }1363 }
14471364
1448 /// Tells whether the given `owner` approves the `operator`.1365 /// Tells whether the given `owner` approves the `operator`.
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
949 // /// @param tokens array of pairs of token ID and token URI for minted tokens949 // /// @param tokens array of pairs of token ID and token URI for minted tokens
950 // /// @dev EVM selector for this function is: 0x36543006,950 // /// @dev EVM selector for this function is: 0x36543006,
951 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])951 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
952 // function mintBulkWithTokenURI(address to, Tuple15[] memory tokens) public returns (bool) {952 // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) public returns (bool) {
953 // require(false, stub_error);953 // require(false, stub_error);
954 // to;954 // to;
955 // tokens;955 // tokens;
981 }981 }
982}982}
983983
984/// @dev anonymous struct984/// Data for creation token with uri.
985struct Tuple15 {985struct TokenUri {
986 /// Id of new token.
986 uint256 field_0;987 uint256 id;
988 /// Uri of new token.
987 string field_1;989 string uri;
988}990}
989991
990/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension992/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
modifiedpallets/refungible/CHANGELOG.mddiffbeforeafterboth
44
5<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->
66
7## [0.2.13] - 2023-02-01
8
9### Added
10
11- The functions `allowanceCross` to `ERC20UniqueExtensions` interface.
12
7## [0.2.12] - 2023-01-2013## [0.2.12] - 2023-01-20
814
9### Fixed15### Fixed
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
2edition = "2021"2edition = "2021"
3license = "GPLv3"3license = "GPLv3"
4name = "pallet-refungible"4name = "pallet-refungible"
5version = "0.2.12"5version = "0.2.13"
66
7[dependencies]7[dependencies]
8# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.8# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
34 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,34 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
35 Error as CommonError,35 Error as CommonError,
36 erc::{CommonEvmHandler, CollectionCall, static_property::key},36 erc::{CommonEvmHandler, CollectionCall, static_property::key},
37 eth,37 eth::{self, TokenUri},
38};38};
39use pallet_evm::{account::CrossAccountId, PrecompileHandle};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};
40use pallet_evm_coder_substrate::{call, dispatch_to_evm};40use pallet_evm_coder_substrate::{call, dispatch_to_evm};
999 &mut self,999 &mut self,
1000 caller: Caller,1000 caller: Caller,
1001 to: Address,1001 to: Address,
1002 tokens: Vec<(U256, String)>,1002 tokens: Vec<TokenUri>,
1003 ) -> Result<bool> {1003 ) -> Result<bool> {
1004 let key = key::url();1004 let key = key::url();
1005 let caller = T::CrossAccountId::from_eth(caller);1005 let caller = T::CrossAccountId::from_eth(caller);
1017 .collect::<BTreeMap<_, _>>()1017 .collect::<BTreeMap<_, _>>()
1018 .try_into()1018 .try_into()
1019 .unwrap();1019 .unwrap();
1020 for (id, token_uri) in tokens {1020 for TokenUri { id, uri } in tokens {
1021 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;1021 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;
1022 if id != expected_index {1022 if id != expected_index {
1023 return Err("item id should be next".into());1023 return Err("item id should be next".into());
1028 properties1028 properties
1029 .try_push(Property {1029 .try_push(Property {
1030 key: key.clone(),1030 key: key.clone(),
1031 value: token_uri1031 value: uri
1032 .into_bytes()1032 .into_bytes()
1033 .try_into()1033 .try_into()
1034 .map_err(|_| "token uri is too long")?,1034 .map_err(|_| "token uri is too long")?,
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
31use pallet_common::{31use pallet_common::{
32 CommonWeightInfo,32 CommonWeightInfo,
33 erc::{CommonEvmHandler, PrecompileResult},33 erc::{CommonEvmHandler, PrecompileResult},
34 eth::collection_id_to_address,34 eth::{collection_id_to_address, CrossAddress},
35};35};
36use pallet_evm::{account::CrossAccountId, PrecompileHandle};36use pallet_evm::{account::CrossAccountId, PrecompileHandle};
37use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};37use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};
203where203where
204 T::AccountId: From<[u8; 32]>,204 T::AccountId: From<[u8; 32]>,
205{205{
206 /// @dev Function to check the amount of tokens that an owner allowed to a spender.
207 /// @param owner crossAddress The address which owns the funds.
208 /// @param spender crossAddress The address which will spend the funds.
209 /// @return A uint256 specifying the amount of tokens still available for the spender.
210 fn allowance_cross(&self, owner: CrossAddress, spender: CrossAddress) -> Result<U256> {
211 let owner = owner.into_sub_cross_account::<T>()?;
212 let spender = spender.into_sub_cross_account::<T>()?;
213
214 Ok(<Allowance<T>>::get((self.id, self.1, owner, spender)).into())
215 }
216
206 /// @dev Function that burns an amount of the token of a given account,217 /// @dev Function that burns an amount of the token of a given account,
207 /// deducting from the sender's allowance for said account.218 /// deducting from the sender's allowance for said account.
230 fn burn_from_cross(241 fn burn_from_cross(
231 &mut self,242 &mut self,
232 caller: Caller,243 caller: Caller,
233 from: pallet_common::eth::CrossAddress,244 from: CrossAddress,
234 amount: U256,245 amount: U256,
235 ) -> Result<bool> {246 ) -> Result<bool> {
236 let caller = T::CrossAccountId::from_eth(caller);247 let caller = T::CrossAccountId::from_eth(caller);
256 fn approve_cross(267 fn approve_cross(
257 &mut self,268 &mut self,
258 caller: Caller,269 caller: Caller,
259 spender: pallet_common::eth::CrossAddress,270 spender: CrossAddress,
260 amount: U256,271 amount: U256,
261 ) -> Result<bool> {272 ) -> Result<bool> {
262 let caller = T::CrossAccountId::from_eth(caller);273 let caller = T::CrossAccountId::from_eth(caller);
286 fn transfer_cross(297 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {
287 &mut self,
288 caller: Caller,
289 to: pallet_common::eth::CrossAddress,
290 amount: U256,
291 ) -> Result<bool> {
292 let caller = T::CrossAccountId::from_eth(caller);298 let caller = T::CrossAccountId::from_eth(caller);
293 let to = to.into_sub_cross_account::<T>()?;299 let to = to.into_sub_cross_account::<T>()?;
309 fn transfer_from_cross(315 fn transfer_from_cross(
310 &mut self,316 &mut self,
311 caller: Caller,317 caller: Caller,
312 from: pallet_common::eth::CrossAddress,318 from: CrossAddress,
313 to: pallet_common::eth::CrossAddress,319 to: CrossAddress,
314 amount: U256,320 amount: U256,
315 ) -> Result<bool> {321 ) -> Result<bool> {
316 let caller = T::CrossAccountId::from_eth(caller);322 let caller = T::CrossAccountId::from_eth(caller);
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
9292
93use core::ops::Deref;93use core::ops::Deref;
94use evm_coder::ToLog;94use evm_coder::ToLog;
95use frame_support::{ensure, fail, storage::with_transaction, transactional};95use frame_support::{ensure, storage::with_transaction, transactional};
96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
97use pallet_evm_coder_substrate::WithRecorder;97use pallet_evm_coder_substrate::WithRecorder;
98use pallet_common::{98use pallet_common::{
99 CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address,99 CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address,
100 Event as CommonEvent, Pallet as PalletCommon, erc::CollectionHelpersEvents,100 Event as CommonEvent, Pallet as PalletCommon,
101};101};
102use pallet_structure::Pallet as PalletStructure;102use pallet_structure::Pallet as PalletStructure;
103use sp_core::{Get, H160};103use sp_core::H160;
104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
106use up_data_structs::{106use up_data_structs::{
107 AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,107 AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,
108 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,108 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,
109 PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId,109 PropertyKeyPermission, PropertyScope, PropertyValue, TokenId, TrySetProperty,
110 TrySetProperty, PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,110 PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,
111};111};
112112
240 QueryKind = ValueQuery,240 QueryKind = ValueQuery,
241 >;241 >;
242242
243 /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet.243 /// Spender set by a wallet owner that could perform certain transactions on all tokens in the wallet.
244 #[pallet::storage]244 #[pallet::storage]
245 pub type CollectionAllowance<T: Config> = StorageNMap<245 pub type CollectionAllowance<T: Config> = StorageNMap<
246 Key = (246 Key = (
247 Key<Twox64Concat, CollectionId>,247 Key<Twox64Concat, CollectionId>,
248 Key<Blake2_128Concat, T::CrossAccountId>,248 Key<Blake2_128Concat, T::CrossAccountId>, // Owner
249 Key<Blake2_128Concat, T::CrossAccountId>,249 Key<Blake2_128Concat, T::CrossAccountId>, // Spender
250 ),250 ),
251 Value = bool,251 Value = bool,
252 QueryKind = ValueQuery,252 QueryKind = ValueQuery,
541 is_token_create: bool,541 is_token_create: bool,
542 nesting_budget: &dyn Budget,542 nesting_budget: &dyn Budget,
543 ) -> DispatchResult {543 ) -> DispatchResult {
544 let is_collection_admin = || collection.is_owner_or_admin(sender);
545 let is_token_owner = || -> Result<bool, DispatchError> {544 let is_token_owner = || -> Result<bool, DispatchError> {
546 let balance = collection.balance(sender.clone(), token_id);545 let balance = collection.balance(sender.clone(), token_id);
547 let total_pieces: u128 =546 let total_pieces: u128 =
561 Ok(is_bundle_owner)560 Ok(is_bundle_owner)
562 };561 };
563562
564 let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));563 let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
564
565 let permissions = <PalletCommon<T>>::property_permissions(collection.id);565 <PalletCommon<T>>::modify_token_properties(
566
567 for (key, value) in properties_updates {566 collection,
568 let permission = permissions
569 .get(&key)
570 .cloned()
571 .unwrap_or_else(PropertyPermission::none);
572
573 let is_property_exists = stored_properties.get(&key).is_some();
574
575 match permission {
576 PropertyPermission { mutable: false, .. } if is_property_exists => {567 sender,
577 return Err(<CommonError<T>>::NoPermission.into());
578 }
579
580 PropertyPermission {
581 collection_admin,568 token_id,
582 token_owner,569 properties_updates,
583 ..
584 } => {
585 //TODO: investigate threats during public minting.
586 let is_token_create =570 is_token_create,
587 is_token_create && (collection_admin || token_owner) && value.is_some();
588 if !(is_token_create
589 || (collection_admin && is_collection_admin())
590 || (token_owner && is_token_owner()?))
591 {
592 fail!(<CommonError<T>>::NoPermission);
593 }
594 }
595 }
596
597 match value {
598 Some(value) => {
599 stored_properties
600 .try_set(key.clone(), value)
601 .map_err(<CommonError<T>>::from)?;
602
603 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(
604 collection.id,
605 token_id,
606 key,
607 ));
608 }
609 None => {
610 stored_properties571 stored_properties,
611 .remove(&key)
612 .map_err(<CommonError<T>>::from)?;
613
614 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
615 collection.id,
616 token_id,
617 key,
618 ));
619 }
620 }
621
622 <PalletEvm<T>>::deposit_log(
623 CollectionHelpersEvents::TokenChanged {
624 collection_id: collection_id_to_address(collection.id),
625 token_id: token_id.into(),
626 }
627 .to_log(T::ContractAddress::get()),572 is_token_owner,
628 );
629 }
630
631 <TokenProperties<T>>::set((collection.id, token_id), stored_properties);573 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
632574 )
633 Ok(())
634 }575 }
635576
636 pub fn set_token_properties(577 pub fn set_token_properties(
1462 pub fn set_allowance_for_all(1403 pub fn set_allowance_for_all(
1463 collection: &RefungibleHandle<T>,1404 collection: &RefungibleHandle<T>,
1464 owner: &T::CrossAccountId,1405 owner: &T::CrossAccountId,
1465 operator: &T::CrossAccountId,1406 spender: &T::CrossAccountId,
1466 approve: bool,1407 approve: bool,
1467 ) -> DispatchResult {1408 ) -> DispatchResult {
1409 <PalletCommon<T>>::set_allowance_for_all(
1468 if collection.permissions.access() == AccessMode::AllowList {1410 collection,
1469 collection.check_allowlist(owner)?;1411 owner,
1470 collection.check_allowlist(operator)?;1412 spender,
1471 }1413 approve,
1472
1473 <PalletCommon<T>>::ensure_correct_receiver(operator)?;1414 || <CollectionAllowance<T>>::insert((collection.id, owner, spender), approve),
1474
1475 // =========
1476
1477 <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve);
1478 <PalletEvm<T>>::deposit_log(
1479 ERC721Events::ApprovalForAll {1415 ERC721Events::ApprovalForAll {
1480 owner: *owner.as_eth(),1416 owner: *owner.as_eth(),
1481 operator: *operator.as_eth(),1417 operator: *spender.as_eth(),
1482 approved: approve,1418 approved: approve,
1483 }1419 }
1484 .to_log(collection_id_to_address(collection.id)),1420 .to_log(collection_id_to_address(collection.id)),
1485 );1421 )
1486 <PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
1487 collection.id,
1488 owner.clone(),
1489 operator.clone(),
1490 approve,
1491 ));
1492 Ok(())
1493 }1422 }
14941423
1495 /// Tells whether the given `owner` approves the `operator`.1424 /// Tells whether the given `owner` approves the `operator`.
1496 pub fn allowance_for_all(1425 pub fn allowance_for_all(
1497 collection: &RefungibleHandle<T>,1426 collection: &RefungibleHandle<T>,
1498 owner: &T::CrossAccountId,1427 owner: &T::CrossAccountId,
1499 operator: &T::CrossAccountId,1428 spender: &T::CrossAccountId,
1500 ) -> bool {1429 ) -> bool {
1501 <CollectionAllowance<T>>::get((collection.id, owner, operator))1430 <CollectionAllowance<T>>::get((collection.id, owner, spender))
1502 }1431 }
15031432
1504 pub fn repair_item(collection: &RefungibleHandle<T>, token: TokenId) -> DispatchResult {1433 pub fn repair_item(collection: &RefungibleHandle<T>, token: TokenId) -> DispatchResult {
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
938 // /// @param tokens array of pairs of token ID and token URI for minted tokens938 // /// @param tokens array of pairs of token ID and token URI for minted tokens
939 // /// @dev EVM selector for this function is: 0x36543006,939 // /// @dev EVM selector for this function is: 0x36543006,
940 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])940 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
941 // function mintBulkWithTokenURI(address to, Tuple14[] memory tokens) public returns (bool) {941 // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) public returns (bool) {
942 // require(false, stub_error);942 // require(false, stub_error);
943 // to;943 // to;
944 // tokens;944 // tokens;
982 }982 }
983}983}
984984
985/// @dev anonymous struct985/// Data for creation token with uri.
986struct Tuple14 {986struct TokenUri {
987 /// Id of new token.
987 uint256 field_0;988 uint256 id;
989 /// Uri of new token.
988 string field_1;990 string uri;
989}991}
990992
991/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension993/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth
36 }36 }
37}37}
3838
39/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b39/// @dev the ERC-165 identifier for this interface is 0x01d536fc
40contract ERC20UniqueExtensions is Dummy, ERC165 {40contract ERC20UniqueExtensions is Dummy, ERC165 {
41 /// @dev Function to check the amount of tokens that an owner allowed to a spender.
42 /// @param owner crossAddress The address which owns the funds.
43 /// @param spender crossAddress The address which will spend the funds.
44 /// @return A uint256 specifying the amount of tokens still available for the spender.
45 /// @dev EVM selector for this function is: 0xe0af4bd7,
46 /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
47 function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) public view returns (uint256) {
48 require(false, stub_error);
49 owner;
50 spender;
51 dummy;
52 return 0;
53 }
54
41 // /// @dev Function that burns an amount of the token of a given account,55 // /// @dev Function that burns an amount of the token of a given account,
42 // /// deducting from the sender's allowance for said account.56 // /// deducting from the sender's allowance for said account.
modifiedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedruntime/common/ethereum/sponsoring/refungible.rsdiffbeforeafterboth
341 ERC165Call(_, _) => None,341 ERC165Call(_, _) => None,
342342
343 // Not sponsored343 // Not sponsored
344 BurnFrom { .. } | BurnFromCross { .. } | Repartition { .. } => None,344 AllowanceCross { .. } | BurnFrom { .. } | BurnFromCross { .. } | Repartition { .. } => {
345 None
346 }
345347
346 TransferCross { .. } | TransferFromCross { .. } => {348 TransferCross { .. } | TransferFromCross { .. } => {
347 let RefungibleTokenHandle(handle, token_id) = token;349 let RefungibleTokenHandle(handle, token_id) = token;
modifiedtests/src/eth/abi/fungible.jsondiffbeforeafterboth
93 "stateMutability": "view",93 "stateMutability": "view",
94 "type": "function"94 "type": "function"
95 },95 },
96 {
97 "inputs": [
98 {
99 "components": [
100 { "internalType": "address", "name": "eth", "type": "address" },
101 { "internalType": "uint256", "name": "sub", "type": "uint256" }
102 ],
103 "internalType": "struct CrossAddress",
104 "name": "owner",
105 "type": "tuple"
106 },
107 {
108 "components": [
109 { "internalType": "address", "name": "eth", "type": "address" },
110 { "internalType": "uint256", "name": "sub", "type": "uint256" }
111 ],
112 "internalType": "struct CrossAddress",
113 "name": "spender",
114 "type": "tuple"
115 }
116 ],
117 "name": "allowanceCross",
118 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
119 "stateMutability": "view",
120 "type": "function"
121 },
96 {122 {
97 "inputs": [123 "inputs": [
98 {124 {
408 "inputs": [434 "inputs": [
409 {435 {
410 "components": [436 "components": [
411 { "internalType": "address", "name": "field_0", "type": "address" },437 { "internalType": "address", "name": "to", "type": "address" },
412 { "internalType": "uint256", "name": "field_1", "type": "uint256" }438 { "internalType": "uint256", "name": "amount", "type": "uint256" }
413 ],439 ],
414 "internalType": "struct Tuple9[]",440 "internalType": "struct AmountForAddress[]",
415 "name": "amounts",441 "name": "amounts",
416 "type": "tuple[]"442 "type": "tuple[]"
417 }443 }
modifiedtests/src/eth/abi/reFungibleToken.jsondiffbeforeafterboth
59 "stateMutability": "view",59 "stateMutability": "view",
60 "type": "function"60 "type": "function"
61 },61 },
62 {
63 "inputs": [
64 {
65 "components": [
66 { "internalType": "address", "name": "eth", "type": "address" },
67 { "internalType": "uint256", "name": "sub", "type": "uint256" }
68 ],
69 "internalType": "struct CrossAddress",
70 "name": "owner",
71 "type": "tuple"
72 },
73 {
74 "components": [
75 { "internalType": "address", "name": "eth", "type": "address" },
76 { "internalType": "uint256", "name": "sub", "type": "uint256" }
77 ],
78 "internalType": "struct CrossAddress",
79 "name": "spender",
80 "type": "tuple"
81 }
82 ],
83 "name": "allowanceCross",
84 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
85 "stateMutability": "view",
86 "type": "function"
87 },
62 {88 {
63 "inputs": [89 "inputs": [
64 { "internalType": "address", "name": "spender", "type": "address" },90 { "internalType": "address", "name": "spender", "type": "address" },
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
353 bytes value;353 bytes value;
354}354}
355355
356/// @dev the ERC-165 identifier for this interface is 0x65789571356/// @dev the ERC-165 identifier for this interface is 0x85d7dea6
357interface ERC20UniqueExtensions is Dummy, ERC165 {357interface ERC20UniqueExtensions is Dummy, ERC165 {
358 /// @dev Function to check the amount of tokens that an owner allowed to a spender.
359 /// @param owner crossAddress The address which owns the funds.
360 /// @param spender crossAddress The address which will spend the funds.
361 /// @return A uint256 specifying the amount of tokens still available for the spender.
362 /// @dev EVM selector for this function is: 0xe0af4bd7,
363 /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
364 function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
365
358 /// @notice A description for the collection.366 /// @notice A description for the collection.
359 /// @dev EVM selector for this function is: 0x7284e416,367 /// @dev EVM selector for this function is: 0x7284e416,
390 /// @param amounts array of pairs of account address and amount398 /// @param amounts array of pairs of account address and amount
391 /// @dev EVM selector for this function is: 0x1acf2d55,399 /// @dev EVM selector for this function is: 0x1acf2d55,
392 /// or in textual repr: mintBulk((address,uint256)[])400 /// or in textual repr: mintBulk((address,uint256)[])
393 function mintBulk(Tuple9[] memory amounts) external returns (bool);401 function mintBulk(AmountForAddress[] memory amounts) external returns (bool);
394402
395 /// @dev EVM selector for this function is: 0x2ada85ff,403 /// @dev EVM selector for this function is: 0x2ada85ff,
396 /// or in textual repr: transferCross((address,uint256),uint256)404 /// or in textual repr: transferCross((address,uint256),uint256)
410 function collectionHelperAddress() external view returns (address);418 function collectionHelperAddress() external view returns (address);
411}419}
412420
413/// @dev anonymous struct
414struct Tuple9 {421struct AmountForAddress {
415 address field_0;422 address to;
416 uint256 field_1;423 uint256 amount;
417}424}
418425
419/// @dev the ERC-165 identifier for this interface is 0x40c10f19426/// @dev the ERC-165 identifier for this interface is 0x40c10f19
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
644 // /// @param tokens array of pairs of token ID and token URI for minted tokens644 // /// @param tokens array of pairs of token ID and token URI for minted tokens
645 // /// @dev EVM selector for this function is: 0x36543006,645 // /// @dev EVM selector for this function is: 0x36543006,
646 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])646 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
647 // function mintBulkWithTokenURI(address to, Tuple13[] memory tokens) external returns (bool);647 // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
648648
649 /// @notice Function to mint a token.649 /// @notice Function to mint a token.
650 /// @param to The new owner crossAccountId650 /// @param to The new owner crossAccountId
660 function collectionHelperAddress() external view returns (address);660 function collectionHelperAddress() external view returns (address);
661}661}
662662
663/// @dev anonymous struct663/// Data for creation token with uri.
664struct Tuple13 {664struct TokenUri {
665 /// Id of new token.
665 uint256 field_0;666 uint256 id;
667 /// Uri of new token.
666 string field_1;668 string uri;
667}669}
668670
669/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension671/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
638 // /// @param tokens array of pairs of token ID and token URI for minted tokens638 // /// @param tokens array of pairs of token ID and token URI for minted tokens
639 // /// @dev EVM selector for this function is: 0x36543006,639 // /// @dev EVM selector for this function is: 0x36543006,
640 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])640 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
641 // function mintBulkWithTokenURI(address to, Tuple12[] memory tokens) external returns (bool);641 // function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
642642
643 /// @notice Function to mint a token.643 /// @notice Function to mint a token.
644 /// @param to The new owner crossAccountId644 /// @param to The new owner crossAccountId
661 function collectionHelperAddress() external view returns (address);661 function collectionHelperAddress() external view returns (address);
662}662}
663663
664/// @dev anonymous struct664/// Data for creation token with uri.
665struct Tuple12 {665struct TokenUri {
666 /// Id of new token.
666 uint256 field_0;667 uint256 id;
668 /// Uri of new token.
667 string field_1;669 string uri;
668}670}
669671
670/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension672/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
modifiedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
23 function parentTokenId() external view returns (uint256);23 function parentTokenId() external view returns (uint256);
24}24}
2525
26/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b26/// @dev the ERC-165 identifier for this interface is 0x01d536fc
27interface ERC20UniqueExtensions is Dummy, ERC165 {27interface ERC20UniqueExtensions is Dummy, ERC165 {
28 /// @dev Function to check the amount of tokens that an owner allowed to a spender.
29 /// @param owner crossAddress The address which owns the funds.
30 /// @param spender crossAddress The address which will spend the funds.
31 /// @return A uint256 specifying the amount of tokens still available for the spender.
32 /// @dev EVM selector for this function is: 0xe0af4bd7,
33 /// or in textual repr: allowanceCross((address,uint256),(address,uint256))
34 function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
35
28 // /// @dev Function that burns an amount of the token of a given account,36 // /// @dev Function that burns an amount of the token of a given account,
29 // /// deducting from the sender's allowance for said account.37 // /// deducting from the sender's allowance for said account.
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
134 const allowance = await contract.methods.allowance(owner, spender).call();134 const allowance = await contract.methods.allowance(owner, spender).call();
135 expect(+allowance).to.equal(100);135 expect(+allowance).to.equal(100);
136 }136 }
137 {
138 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
139 const spenderCross = helper.ethCrossAccount.fromAddress(spender);
140 const allowance = await contract.methods.allowanceCross(ownerCross, spenderCross).call();
141 expect(+allowance).to.equal(100);
142 }
137 });143 });
138144
139 itEth('Can perform approveCross()', async ({helper}) => {145 itEth('Can perform approveCross()', async ({helper}) => {
modifiedtests/src/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth
168 return proxied.mintBulk(to, tokenIds);168 return proxied.mintBulk(to, tokenIds);
169 }169 }
170170
171 function mintBulkWithTokenURI(address to, Tuple6[] memory tokens)171 function mintBulkWithTokenURI(address to, TokenUri[] memory tokens)
172 external172 external
173 override173 override
174 returns (bool)174 returns (bool)
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
215215
216 const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner, true);216 const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner, true);
217217
218 {218 {
219 await rftToken.methods.approve(operator, 15n).send({from: owner});219 await rftToken.methods.approve(operator, 15n).send({from: owner});
220 await contract.methods.setApprovalForAll(operator, true).send({from: owner});220 await contract.methods.setApprovalForAll(operator, true).send({from: owner});
221 await rftToken.methods.burnFrom(owner, 10n).send({from: operator});221 await rftToken.methods.burnFrom(owner, 10n).send({from: operator});
222 }
223 {
222 const allowance = await rftToken.methods.allowance(owner, operator).call();224 const allowance = await rftToken.methods.allowance(owner, operator).call();
223 expect(allowance).to.be.equal('5');225 expect(+allowance).to.be.equal(5);
224 }226 }
227 {
228 const ownerCross = helper.ethCrossAccount.fromAddress(owner);
229 const operatorCross = helper.ethCrossAccount.fromAddress(operator);
230 const allowance = await rftToken.methods.allowanceCross(ownerCross, operatorCross).call();
231 expect(+allowance).to.equal(5);
232 }
225 });233 });
226234
227 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {235 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {