git.delta.rocks / unique-network / refs/commits / 25b9e9e7bf38

difftreelog

source

pallets/evm-collection/src/eth.rs6.3 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use core::marker::PhantomData;18use evm_coder::{abi::AbiWriter, execution::*, generate_stubgen, solidity_interface, types::*, ToLog};19use ethereum as _;20use pallet_common::CollectionById;21use pallet_common::{CollectionHandle};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use pallet_evm::{24	ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure,25	account::CrossAccountId, Pallet as PalletEvm,26};27use sp_core::H160;28use up_data_structs::{29	CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,30	MAX_COLLECTION_NAME_LENGTH,31};32use crate::{Config, Pallet};33use frame_support::traits::Get;3435use sp_std::{vec::Vec, rc::Rc};36use alloc::format;3738struct EvmCollection<T: Config>(SubstrateRecorder<T>);39impl<T: Config> WithRecorder<T> for EvmCollection<T> {40	fn recorder(&self) -> &SubstrateRecorder<T> {41		&self.042	}4344	fn into_recorder(self) -> SubstrateRecorder<T> {45		self.046	}47}4849#[derive(ToLog)]50pub enum EthCollectionEvent {51	CollectionCreated {52		#[indexed]53		owner: address,54		#[indexed]55		collection_id: address,56	},57}5859#[solidity_interface(name = "Collection")]60impl<T: Config> EvmCollection<T> {61	fn create_721_collection(62		&self,63		caller: caller,64		name: string,65		description: string,66		token_prefix: string,67	) -> Result<address> {68		let caller = T::CrossAccountId::from_eth(caller);69		let name = name70			.encode_utf16()71			.collect::<Vec<u16>>()72			.try_into()73			.map_err(|_| error_feild_too_long("name", MAX_COLLECTION_NAME_LENGTH))?;74		let description = description75			.encode_utf16()76			.collect::<Vec<u16>>()77			.try_into()78			.map_err(|_| error_feild_too_long("description", MAX_COLLECTION_DESCRIPTION_LENGTH))?;79		let token_prefix = token_prefix80			.into_bytes()81			.try_into()82			.map_err(|_| error_feild_too_long("token_prefix", MAX_TOKEN_PREFIX_LENGTH))?;8384		let data = CreateCollectionData {85			name,86			description,87			token_prefix,88			..Default::default()89		};9091		let collection_id =92			<pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)93				.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;9495		let address = pallet_common::eth::collection_id_to_address(collection_id);96		<PalletEvm<T>>::deposit_log(97			EthCollectionEvent::CollectionCreated {98				owner: *caller.as_eth(),99				collection_id: address,100			}101			.to_log(address),102		);103		Ok(address)104	}105106	fn set_sponsor(107		&self,108		caller: caller,109		collection_address: address,110		sponsor: address,111	) -> Result<void> {112		let mut collection = collection_from_address(collection_address, &self.0)?;113		check_is_owner(caller, &collection)?;114115		let sponsor = T::CrossAccountId::from_eth(sponsor);116		collection.set_sponsor(sponsor.as_sub().clone());117		collection.save().map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;118		Ok(()).map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;119		Ok(())120	}121122	fn confirm_sponsorship(&self, caller: caller, collection_address: address) -> Result<void> {123		let mut collection = collection_from_address(collection_address, &self.0)?;124		let caller = T::CrossAccountId::from_eth(caller);125		if !collection.confirm_sponsorship(caller.as_sub()) {126			return Err(Error::Revert("Caller is not set as sponsor".into()));127		}128		collection.save().map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;129		Ok(())130	}131132	fn set_limits(133		&self,134		caller: caller,135		collection_address: address,136		limits_json: string,137	) -> Result<void> {138		let mut collection = collection_from_address(collection_address, &self.0)?;139		check_is_owner(caller, &collection)?;140141		let limits = serde_json_core::from_str(limits_json.as_ref())142			.map_err(|e| Error::Revert(format!("Parse JSON error: {}", e)))?;143		collection.limits = limits.0;144		collection.save().map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;145		Ok(())146	}147}148149fn error_feild_too_long(feild: &str, bound: u32) -> Error {150	Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))151}152153fn collection_from_address<T: Config>(154	collection_address: address,155	recorder: &SubstrateRecorder<T>,156) -> Result<CollectionHandle<T>> {157	let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)158		.ok_or(Error::Revert("Contract is not an unique collection".into()))?;159	let collection =160		pallet_common::CollectionHandle::new_with_gas_limit(collection_id, recorder.gas_left())161			.ok_or(Error::Revert("Create collection handle error".into()))?;162	Ok(collection)163}164165fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {166	let caller = T::CrossAccountId::from_eth(caller);167	collection168		.check_is_owner(&caller)169		.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;170	Ok(())171}172173pub struct CollectionOnMethodCall<T: Config>(PhantomData<*const T>);174impl<T: Config> OnMethodCall<T> for CollectionOnMethodCall<T> {175	fn is_reserved(contract: &sp_core::H160) -> bool {176		contract == &T::ContractAddress::get()177	}178179	fn is_used(contract: &sp_core::H160) -> bool {180		contract == &T::ContractAddress::get()181	}182183	fn call(184		source: &sp_core::H160,185		target: &sp_core::H160,186		gas_left: u64,187		input: &[u8],188		value: sp_core::U256,189	) -> Option<PrecompileResult> {190		if target != &T::ContractAddress::get() {191			return None;192		}193194		let helpers = EvmCollection::<T>(SubstrateRecorder::new(gas_left));195		pallet_evm_coder_substrate::call(*source, helpers, value, input)196	}197198	fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {199		(contract == &T::ContractAddress::get())200			.then(|| include_bytes!("./stubs/Collection.raw").to_vec())201	}202}203204generate_stubgen!(collection_impl, CollectionCall<()>, true);205generate_stubgen!(collection_iface, CollectionCall<()>, false);