difftreelog
feat make collection ERC721 compatible
in: master
4 files changed
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- 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 =
+ <crate::CollectionHandle<T>>::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::<T>)?;
+
+ if collection.flags.erc721metadata {
+ return Err("target collection is already Erc721Metadata compatible".into());
+ }
+ collection.flags.erc721metadata = true;
+
+ let all_permissions = <pallet_common::CollectionPropertyPermissions<T>>::get(collection.id);
+ if all_permissions.get(&key::url()).is_none() {
+ self.recorder().consume_sstore()?;
+ <PalletCommon<T>>::set_property_permission(&collection, &caller, default_url_pkp())
+ .map_err(dispatch_to_evm::<T>)?;
+ }
+ if all_permissions.get(&key::suffix()).is_none() {
+ self.recorder().consume_sstore()?;
+ <PalletCommon<T>>::set_property_permission(&collection, &caller, default_suffix_pkp())
+ .map_err(dispatch_to_evm::<T>)?;
+ }
+
+ let all_properties = <pallet_common::CollectionProperties<T>>::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()?;
+ <PalletCommon<T>>::set_collection_properties(&collection, &caller, new_properties)
+ .map_err(dispatch_to_evm::<T>)?;
+ }
+
+ self.recorder().consume_sstore()?;
+ collection.save().map_err(dispatch_to_evm::<T>)?;
+
+ Ok(())
+ }
+
/// Check if a collection exists
/// @param collectionAddress Address of the collection in question
/// @return bool Does the collection exist?
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth--- 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?
tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth--- 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?
tests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth1[2 {3 "anonymous": false,4 "inputs": [5 {6 "indexed": true,7 "internalType": "address",8 "name": "owner",9 "type": "address"10 },11 {12 "indexed": true,13 "internalType": "address",14 "name": "collectionId",15 "type": "address"16 }17 ],18 "name": "CollectionCreated",19 "type": "event"20 },21 {22 "inputs": [],23 "name": "collectionCreationFee",24 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],25 "stateMutability": "view",26 "type": "function"27 },28 {29 "inputs": [30 { "internalType": "string", "name": "name", "type": "string" },31 { "internalType": "string", "name": "description", "type": "string" },32 { "internalType": "string", "name": "tokenPrefix", "type": "string" },33 { "internalType": "string", "name": "baseUri", "type": "string" }34 ],35 "name": "createERC721MetadataCompatibleNFTCollection",36 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],37 "stateMutability": "payable",38 "type": "function"39 },40 {41 "inputs": [42 { "internalType": "string", "name": "name", "type": "string" },43 { "internalType": "string", "name": "description", "type": "string" },44 { "internalType": "string", "name": "tokenPrefix", "type": "string" },45 { "internalType": "string", "name": "baseUri", "type": "string" }46 ],47 "name": "createERC721MetadataCompatibleRFTCollection",48 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],49 "stateMutability": "payable",50 "type": "function"51 },52 {53 "inputs": [54 { "internalType": "string", "name": "name", "type": "string" },55 { "internalType": "string", "name": "description", "type": "string" },56 { "internalType": "string", "name": "tokenPrefix", "type": "string" }57 ],58 "name": "createNFTCollection",59 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],60 "stateMutability": "payable",61 "type": "function"62 },63 {64 "inputs": [65 { "internalType": "string", "name": "name", "type": "string" },66 { "internalType": "string", "name": "description", "type": "string" },67 { "internalType": "string", "name": "tokenPrefix", "type": "string" }68 ],69 "name": "createNonfungibleCollection",70 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],71 "stateMutability": "payable",72 "type": "function"73 },74 {75 "inputs": [76 { "internalType": "string", "name": "name", "type": "string" },77 { "internalType": "string", "name": "description", "type": "string" },78 { "internalType": "string", "name": "tokenPrefix", "type": "string" }79 ],80 "name": "createRFTCollection",81 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],82 "stateMutability": "payable",83 "type": "function"84 },85 {86 "inputs": [87 {88 "internalType": "address",89 "name": "collectionAddress",90 "type": "address"91 }92 ],93 "name": "isCollectionExist",94 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],95 "stateMutability": "view",96 "type": "function"97 },98 {99 "inputs": [100 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }101 ],102 "name": "supportsInterface",103 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],104 "stateMutability": "view",105 "type": "function"106 }107]