From f27580fc65c79ae40475dcc4bbe50fafcf302a6e Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 13 Oct 2022 15:47:00 +0000 Subject: [PATCH] feat: make collection ERC721 compatible --- --- a/pallets/unique/src/eth/mod.rs +++ b/pallets/unique/src/eth/mod.rs @@ -27,6 +27,7 @@ CollectionHelpersEvents, static_property::{key, value as property_value}, }, + Pallet as PalletCommon, }; use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder}; use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult}; @@ -340,6 +341,83 @@ ) } + #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")] + fn make_collection_metadata_compatible( + &mut self, + caller: caller, + collection: address, + base_uri: string, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let collection = + pallet_common::eth::map_eth_to_id(&collection).ok_or("not a collection address")?; + let mut collection = + >::new(collection).ok_or("collection not found")?; + + if !matches!( + collection.mode, + CollectionMode::NFT | CollectionMode::ReFungible + ) { + return Err("target collection should be either NFT or Refungible".into()); + } + + self.recorder().consume_sstore()?; + collection + .check_is_owner_or_admin(&caller) + .map_err(dispatch_to_evm::)?; + + if collection.flags.erc721metadata { + return Err("target collection is already Erc721Metadata compatible".into()); + } + collection.flags.erc721metadata = true; + + let all_permissions = >::get(collection.id); + if all_permissions.get(&key::url()).is_none() { + self.recorder().consume_sstore()?; + >::set_property_permission(&collection, &caller, default_url_pkp()) + .map_err(dispatch_to_evm::)?; + } + if all_permissions.get(&key::suffix()).is_none() { + self.recorder().consume_sstore()?; + >::set_property_permission(&collection, &caller, default_suffix_pkp()) + .map_err(dispatch_to_evm::)?; + } + + let all_properties = >::get(collection.id); + let mut new_properties = vec![]; + if all_properties.get(&key::schema_name()).is_none() { + self.recorder().consume_sstore()?; + new_properties.push(up_data_structs::Property { + key: key::schema_name(), + value: property_value::erc721(), + }); + new_properties.push(up_data_structs::Property { + key: key::schema_version(), + value: property_value::schema_version(), + }); + } + if all_properties.get(&key::base_uri()).is_none() && !base_uri.is_empty() { + new_properties.push(up_data_structs::Property { + key: key::base_uri(), + value: base_uri + .into_bytes() + .try_into() + .map_err(|_| "base uri is too large")?, + }); + } + + if !new_properties.is_empty() { + self.recorder().consume_sstore()?; + >::set_collection_properties(&collection, &caller, new_properties) + .map_err(dispatch_to_evm::)?; + } + + self.recorder().consume_sstore()?; + collection.save().map_err(dispatch_to_evm::)?; + + Ok(()) + } + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? --- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol +++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol @@ -23,7 +23,7 @@ } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0xd14d1221 +/// @dev the ERC-165 identifier for this interface is 0x542f5079 contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection @@ -114,6 +114,15 @@ return 0x0000000000000000000000000000000000000000; } + /// @dev EVM selector for this function is: 0x85624258, + /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string) + function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) public { + require(false, stub_error); + collection; + baseUri; + dummy = 0; + } + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? --- a/tests/src/eth/api/CollectionHelpers.sol +++ b/tests/src/eth/api/CollectionHelpers.sol @@ -18,7 +18,7 @@ } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0xd14d1221 +/// @dev the ERC-165 identifier for this interface is 0x542f5079 interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection @@ -72,6 +72,10 @@ string memory baseUri ) external payable returns (address); + /// @dev EVM selector for this function is: 0x85624258, + /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string) + function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external; + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? --- a/tests/src/eth/collectionHelpersAbi.json +++ b/tests/src/eth/collectionHelpersAbi.json @@ -97,6 +97,16 @@ }, { "inputs": [ + { "internalType": "address", "name": "collection", "type": "address" }, + { "internalType": "string", "name": "baseUri", "type": "string" } + ], + "name": "makeCollectionERC721MetadataCompatible", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } ], "name": "supportsInterface", -- gitstuff