1234567891011121314151617use evm_coder::{18 solidity_interface, solidity,19 types::*,20 execution::{Result, Error},21};22pub use pallet_evm::{PrecompileOutput, PrecompileResult, account::CrossAccountId};23use pallet_evm_coder_substrate::dispatch_to_evm;24use sp_core::{H160, U256};25use sp_std::vec::Vec;26use up_data_structs::{Property, SponsoringRateLimit};27use alloc::format;2829use crate::{Pallet, CollectionHandle, Config, CollectionProperties};30313233pub trait CommonEvmHandler {34 const CODE: &'static [u8];3536 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult>;37}3839#[solidity_interface(name = "Collection")]40impl<T: Config> CollectionHandle<T> {41 fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<()> {42 let caller = T::CrossAccountId::from_eth(caller);43 let key = <Vec<u8>>::from(key)44 .try_into()45 .map_err(|_| "key too large")?;46 let value = value.try_into().map_err(|_| "value too large")?;4748 <Pallet<T>>::set_collection_property(self, &caller, Property { key, value })49 .map_err(dispatch_to_evm::<T>)50 }5152 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {53 let caller = T::CrossAccountId::from_eth(caller);54 let key = <Vec<u8>>::from(key)55 .try_into()56 .map_err(|_| "key too large")?;5758 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)59 }6061 62 fn collection_property(&self, key: string) -> Result<bytes> {63 let key = <Vec<u8>>::from(key)64 .try_into()65 .map_err(|_| "key too large")?;6667 let props = <CollectionProperties<T>>::get(self.id);68 let prop = props.get(&key).ok_or("key not found")?;6970 Ok(prop.to_vec())71 }7273 fn eth_set_sponsor(&mut self, caller: caller, sponsor: address) -> 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 #[solidity(rename_selector = "setLimit")]92 fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {93 check_is_owner(caller, self)?;94 let mut limits = self.limits.clone();9596 match limit.as_str() {97 "accountTokenOwnershipLimit" => {98 limits.account_token_ownership_limit = Some(value);99 }100 "sponsoredDataSize" => {101 limits.sponsored_data_size = Some(value);102 }103 "sponsoredDataRateLimit" => {104 limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(value));105 }106 "tokenLimit" => {107 limits.token_limit = Some(value);108 }109 "sponsorTransferTimeout" => {110 limits.sponsor_transfer_timeout = Some(value);111 }112 "sponsorApproveTimeout" => {113 limits.sponsor_approve_timeout = Some(value);114 }115 _ => {116 return Err(Error::Revert(format!(117 "Unknown integer limit \"{}\"",118 limit119 )))120 }121 }122 self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)123 .map_err(dispatch_to_evm::<T>)?;124 save(self);125 Ok(())126 }127128 #[solidity(rename_selector = "setLimit")]129 fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {130 check_is_owner(caller, self)?;131 let mut limits = self.limits.clone();132133 match limit.as_str() {134 "ownerCanTransfer" => {135 limits.owner_can_transfer = Some(value);136 }137 "ownerCanDestroy" => {138 limits.owner_can_destroy = Some(value);139 }140 "transfersEnabled" => {141 limits.transfers_enabled = Some(value);142 }143 _ => {144 return Err(Error::Revert(format!(145 "Unknown boolean limit \"{}\"",146 limit147 )))148 }149 }150 self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)151 .map_err(dispatch_to_evm::<T>)?;152 save(self);153 Ok(())154 }155156 fn contract_address(&self, _caller: caller) -> Result<address> {157 Ok(crate::eth::collection_id_to_address(self.id))158 }159}160161fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {162 let caller = T::CrossAccountId::from_eth(caller);163 collection164 .check_is_owner(&caller)165 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;166 Ok(())167}168169fn save<T: Config>(collection: &CollectionHandle<T>) {170 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());171}172173pub fn token_uri_key() -> up_data_structs::PropertyKey {174 b"tokenURI"175 .to_vec()176 .try_into()177 .expect("length < limit; qed")178}