1234567891011121314151617use evm_coder::{solidity_interface, types::*, execution::{Result, Error}};18pub use pallet_evm::{PrecompileOutput, PrecompileResult, account::CrossAccountId};19use pallet_evm_coder_substrate::dispatch_to_evm;20use sp_core::{H160, U256};21use sp_std::vec::Vec;22use up_data_structs::{Property, SponsoringRateLimit};23use alloc::format;2425use crate::{Pallet, CollectionHandle, Config, CollectionProperties};26272829pub trait CommonEvmHandler {30 const CODE: &'static [u8];3132 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult>;33}3435#[solidity_interface(name = "Collection")]36impl<T: Config> CollectionHandle<T> {37 fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<()> {38 let caller = T::CrossAccountId::from_eth(caller);39 let key = <Vec<u8>>::from(key)40 .try_into()41 .map_err(|_| "key too large")?;42 let value = value.try_into().map_err(|_| "value too large")?;4344 <Pallet<T>>::set_collection_property(self, &caller, Property { key, value })45 .map_err(dispatch_to_evm::<T>)46 }4748 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {49 let caller = T::CrossAccountId::from_eth(caller);50 let key = <Vec<u8>>::from(key)51 .try_into()52 .map_err(|_| "key too large")?;5354 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)55 }5657 58 fn collection_property(&self, key: string) -> Result<bytes> {59 let key = <Vec<u8>>::from(key)60 .try_into()61 .map_err(|_| "key too large")?;6263 let props = <CollectionProperties<T>>::get(self.id);64 let prop = props.get(&key).ok_or("key not found")?;6566 Ok(prop.to_vec())67 }6869 fn eth_set_sponsor(70 &mut self,71 caller: caller,72 sponsor: address,73 ) -> Result<void> {74 check_is_owner(caller, self)?;7576 let sponsor = T::CrossAccountId::from_eth(sponsor);77 self.set_sponsor(sponsor.as_sub().clone());78 save(self);79 Ok(())80 }8182 fn eth_confirm_sponsorship(&mut self, caller: caller) -> Result<void> {83 let caller = T::CrossAccountId::from_eth(caller);84 if !self.confirm_sponsorship(caller.as_sub()) {85 return Err(Error::Revert("Caller is not set as sponsor".into()));86 }87 save(self);88 Ok(())89 }9091 fn set_limit(92 &mut self,93 caller: caller,94 limit: string,95 value: string,96 ) -> Result<void> {97 check_is_owner(caller, self)?;98 let mut limits = self.limits.clone();99100 match limit.as_str() {101 "accountTokenOwnershipLimit" => {102 limits.account_token_ownership_limit = parse_int(value)?;103 },104 "sponsoredDataSize" => {105 limits.sponsored_data_size = parse_int(value)?;106 },107 "sponsoredDataRateLimit" => {108 limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(parse_int(value)?.unwrap()));109 },110 "tokenLimit" => {111 limits.token_limit = parse_int(value)?;112 },113 "sponsorTransferTimeout" => {114 limits.sponsor_transfer_timeout = parse_int(value)?;115 },116 "sponsorApproveTimeout" => {117 limits.sponsor_approve_timeout = parse_int(value)?;118 },119 "ownerCanTransfer" => {120 limits.owner_can_transfer = parse_bool(value)?;121 },122 "ownerCanDestroy" => {123 limits.owner_can_destroy = parse_bool(value)?;124 },125 "transfersEnabled" => {126 limits.transfers_enabled = parse_bool(value)?;127 },128 _ => return Err(Error::Revert(format!("Unknown limit \"{}\"", limit)))129 }130 self.limits = limits;131 save(self);132 Ok(())133 }134135 fn contract_address(&self, _caller: caller) -> Result<address> {136 Ok(crate::eth::collection_id_to_address(self.id))137 }138}139140fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {141 let caller = T::CrossAccountId::from_eth(caller);142 collection143 .check_is_owner(&caller)144 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;145 Ok(())146}147148fn save<T: Config>(collection: &CollectionHandle<T>) {149 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());150}151152fn parse_int(value: string) -> Result<Option<u32>> {153 value.parse::<u32>()154 .map_err(|e| Error::Revert(format!("Int value \"{}\" parse error: {}", value, e)))155 .map(|value| Some(value))156}157158fn parse_bool(value: string) -> Result<Option<bool>> {159 value.parse::<bool>()160 .map_err(|e| Error::Revert(format!("Bool value \"{}\" parse error: {}", value, e)))161 .map(|value| Some(value))162}