git.delta.rocks / unique-network / refs/commits / f27580fc65c7

difftreelog

feat make collection ERC721 compatible

Yaroslav Bolyukin2022-10-13parent: #8ad09da.patch.diff
in: master

4 files changed

modifiedpallets/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?
modifiedpallets/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?
modifiedtests/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?
modifiedtests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth
before · tests/src/eth/collectionHelpersAbi.json
1[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]