1234567891011121314151617pub mod evm_collection {18 use core::marker::PhantomData;19 use evm_coder::{execution::*, generate_stubgen, solidity_interface, types::*, ToLog};20 use ethereum as _;21 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};22 use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, Pallet as PalletEvm};23 use up_data_structs::{24 CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,25 MAX_COLLECTION_NAME_LENGTH,26 };27 use frame_support::traits::Get;28 use sp_core::H160;29 use pallet_common::CollectionById;30 31 use sp_std::vec::Vec;32 use alloc::format;33 34 pub trait Config:35 frame_system::Config36 + pallet_evm_coder_substrate::Config37 + pallet_evm::account::Config38 + pallet_nonfungible::Config39 {40 type ContractAddress: Get<H160>;41 }4243 struct EvmCollectionHelper<T: Config>(SubstrateRecorder<T>);44 impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {45 fn recorder(&self) -> &SubstrateRecorder<T> {46 &self.047 }48 49 fn into_recorder(self) -> SubstrateRecorder<T> {50 self.051 }52 }5354 #[solidity_interface(name = "CollectionHelper")]55 impl<T: Config> EvmCollectionHelper<T> {56 fn create_721_collection(57 &self,58 caller: caller,59 name: string,60 description: string,61 token_prefix: string,62 ) -> Result<address> {63 let caller = T::CrossAccountId::from_eth(caller);64 let name = name65 .encode_utf16()66 .collect::<Vec<u16>>()67 .try_into()68 .map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;69 let description = description70 .encode_utf16()71 .collect::<Vec<u16>>()72 .try_into()73 .map_err(|_| {74 error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)75 })?;76 let token_prefix = token_prefix77 .into_bytes()78 .try_into()79 .map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;80 81 let key: string = "tokenURI".into(); 82 let key: up_data_structs::PropertyKey = key.into_bytes().try_into().map_err(|_| Error::Revert("".into()))?;83 let permission = up_data_structs::PropertyPermission {84 mutable: true,85 collection_admin: true,86 token_owner: false,87 };88 let mut token_property_permissions = up_data_structs::CollectionPropertiesPermissionsVec::default();89 token_property_permissions.try_push(up_data_structs::PropertyKeyPermission{90 key,91 permission,92 }).map_err(|e| Error::Revert(format!("{:?}", e)))?;9394 let data = CreateCollectionData {95 name,96 description,97 token_prefix,98 token_property_permissions,99 ..Default::default()100 };101 102 let collection_id =103 <pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)104 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;105 106 let address = pallet_common::eth::collection_id_to_address(collection_id);107 <PalletEvm<T>>::deposit_log(108 EthCollectionEvent::CollectionCreated {109 owner: *caller.as_eth(),110 collection_id: address,111 }112 .to_log(address),113 );114 Ok(address)115 }116117 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {118 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {119 let collection_id = id;120 return Ok(<CollectionById<T>>::contains_key(collection_id));121 }122123 Ok(false)124 }125 }126 127 #[derive(ToLog)]128 pub enum EthCollectionEvent {129 CollectionCreated {130 #[indexed]131 owner: address,132 #[indexed]133 collection_id: address,134 },135 }136137 pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);138 impl<T: Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {139 fn is_reserved(contract: &sp_core::H160) -> bool {140 contract == &T::ContractAddress::get()141 }142 143 fn is_used(contract: &sp_core::H160) -> bool {144 contract == &T::ContractAddress::get()145 }146 147 fn call(148 source: &sp_core::H160,149 target: &sp_core::H160,150 gas_left: u64,151 input: &[u8],152 value: sp_core::U256,153 ) -> Option<PrecompileResult> {154 if target != &T::ContractAddress::get() {155 return None;156 }157 158 let helpers = EvmCollectionHelper::<T>(SubstrateRecorder::<T>::new(gas_left));159 pallet_evm_coder_substrate::call(*source, helpers, value, input)160 }161 162 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {163 (contract == &T::ContractAddress::get())164 .then(|| include_bytes!("./stubs/CollectionHelper.raw").to_vec())165 }166 }167 168 generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true);169 generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false);170171 fn error_feild_too_long(feild: &str, bound: u32) -> Error {172 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))173 }174}