difftreelog
path: add weights
in: master
1 file changed
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth1// 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::Result, generate_stubgen, solidity_interface, types::*};19use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};20use pallet_evm::{21 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,22 account::CrossAccountId,23};24use sp_core::H160;25use up_data_structs::SponsorshipState;26use crate::{27 AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,28 Sponsoring,29};30use frame_support::traits::Get;31use up_sponsorship::SponsorshipHandler;32use sp_std::vec::Vec;3334struct ContractHelpers<T: Config>(SubstrateRecorder<T>);35impl<T: Config> WithRecorder<T> for ContractHelpers<T> {36 fn recorder(&self) -> &SubstrateRecorder<T> {37 &self.038 }3940 fn into_recorder(self) -> SubstrateRecorder<T> {41 self.042 }43}4445#[solidity_interface(name = "ContractHelpers")]46impl<T: Config> ContractHelpers<T>47where48 T::AccountId: AsRef<[u8; 32]>,49{50 /// Get contract ovner51 ///52 /// @param Contract_address contract for which the owner is being determined.53 /// @return Contract owner.54 fn contract_owner(&self, contract_address: address) -> Result<address> {55 Ok(<Owner<T>>::get(contract_address))56 }5758 /// Set sponsor.59 ///60 /// @param contract_address Contract for which a sponsor is being established.61 /// @param sponsor User address who set as pending sponsor.62 fn set_sponsor(63 &mut self,64 caller: caller,65 contract_address: address,66 sponsor: address,67 ) -> Result<void> {68 Pallet::<T>::set_sponsor(69 &T::CrossAccountId::from_eth(caller),70 contract_address,71 &T::CrossAccountId::from_eth(sponsor),72 )73 .map_err(dispatch_to_evm::<T>)?;74 Ok(())75 }7677 /// Set contract as self sponsored.78 ///79 /// @param contract_address Contract for which a self sponsoring is being enabled.80 fn self_sponsored_enable(&mut self, caller: caller, contract_address: address) -> Result<void> {81 Pallet::<T>::self_sponsored_enable(&T::CrossAccountId::from_eth(caller), contract_address)82 .map_err(dispatch_to_evm::<T>)?;83 Ok(())84 }8586 /// Remove sponsor.87 ///88 /// @param contract_address Contract for which a sponsorship is being removed.89 fn remove_sponsor(&mut self, caller: caller, contract_address: address) -> Result<void> {90 Pallet::<T>::remove_sponsor(&T::CrossAccountId::from_eth(caller), contract_address)91 .map_err(dispatch_to_evm::<T>)?;92 Ok(())93 }9495 /// Confirm sponsorship.96 ///97 /// @dev Caller must be same that set via [`set_sponsor`].98 ///99 /// @param contract_address Сontract for which need to confirm sponsorship.100 fn confirm_sponsorship(&mut self, caller: caller, contract_address: address) -> Result<void> {101 Pallet::<T>::confirm_sponsorship(&T::CrossAccountId::from_eth(caller), contract_address)102 .map_err(dispatch_to_evm::<T>)?;103 Ok(())104 }105106 /// Get current sponsor.107 ///108 /// @param contract_address The contract for which a sponsor is requested.109 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.110 fn get_sponsor(&self, contract_address: address) -> Result<(address, uint256)> {111 let sponsor =112 Pallet::<T>::get_sponsor(contract_address).ok_or("Contract has no sponsor")?;113 let sponsor_sub = pallet_common::eth::convert_cross_account_to_uint256::<T>(&sponsor);114 Ok((*sponsor.as_eth(), sponsor_sub))115 }116117 /// Check tat contract has confirmed sponsor.118 ///119 /// @param contract_address The contract for which the presence of a confirmed sponsor is checked.120 /// @return **true** if contract has confirmed sponsor.121 fn has_sponsor(&self, contract_address: address) -> Result<bool> {122 Ok(Pallet::<T>::get_sponsor(contract_address).is_some())123 }124125 /// Check tat contract has pending sponsor.126 ///127 /// @param contract_address The contract for which the presence of a pending sponsor is checked.128 /// @return **true** if contract has pending sponsor.129 fn has_pending_sponsor(&self, contract_address: address) -> Result<bool> {130 Ok(match Sponsoring::<T>::get(contract_address) {131 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => false,132 SponsorshipState::Unconfirmed(_) => true,133 })134 }135136 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {137 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)138 }139140 fn set_sponsoring_mode(141 &mut self,142 caller: caller,143 contract_address: address,144 mode: uint8,145 ) -> Result<void> {146 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;147 let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;148 <Pallet<T>>::set_sponsoring_mode(contract_address, mode);149 Ok(())150 }151152 fn sponsoring_mode(&self, contract_address: address) -> Result<uint8> {153 Ok(<Pallet<T>>::sponsoring_mode(contract_address).to_eth())154 }155156 fn set_sponsoring_rate_limit(157 &mut self,158 caller: caller,159 contract_address: address,160 rate_limit: uint32,161 ) -> Result<void> {162 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;163 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());164 Ok(())165 }166167 fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {168 Ok(<SponsoringRateLimit<T>>::get(contract_address)169 .try_into()170 .map_err(|_| "rate limit > u32::MAX")?)171 }172173 fn allowed(&self, contract_address: address, user: address) -> Result<bool> {174 self.0.consume_sload()?;175 Ok(<Pallet<T>>::allowed(contract_address, user))176 }177178 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {179 Ok(<AllowlistEnabled<T>>::get(contract_address))180 }181182 fn toggle_allowlist(183 &mut self,184 caller: caller,185 contract_address: address,186 enabled: bool,187 ) -> Result<void> {188 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;189 <Pallet<T>>::toggle_allowlist(contract_address, enabled);190 Ok(())191 }192193 fn toggle_allowed(194 &mut self,195 caller: caller,196 contract_address: address,197 user: address,198 allowed: bool,199 ) -> Result<void> {200 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;201 <Pallet<T>>::toggle_allowed(contract_address, user, allowed);202 Ok(())203 }204}205206pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);207impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T>208where209 T::AccountId: AsRef<[u8; 32]>,210{211 fn is_reserved(contract: &sp_core::H160) -> bool {212 contract == &T::ContractAddress::get()213 }214215 fn is_used(contract: &sp_core::H160) -> bool {216 contract == &T::ContractAddress::get()217 }218219 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {220 // TODO: Extract to another OnMethodCall handler221 if <AllowlistEnabled<T>>::get(handle.code_address())222 && !<Pallet<T>>::allowed(handle.code_address(), handle.context().caller)223 {224 return Some(Err(PrecompileFailure::Revert {225 exit_status: ExitRevert::Reverted,226 output: {227 let mut writer = AbiWriter::new_call(evm_coder::fn_selector!(Error(string)));228 writer.string("Target contract is allowlisted");229 writer.finish()230 },231 }));232 }233234 if handle.code_address() != T::ContractAddress::get() {235 return None;236 }237238 let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));239 pallet_evm_coder_substrate::call(handle, helpers)240 }241242 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {243 (contract == &T::ContractAddress::get())244 .then(|| include_bytes!("./stubs/ContractHelpers.raw").to_vec())245 }246}247248pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);249impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {250 fn on_create(owner: H160, contract: H160) {251 <Owner<T>>::insert(contract, owner);252 }253}254255pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);256impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)>257 for HelpersContractSponsoring<T>258{259 fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {260 let (contract, _) = call;261 let mode = <Pallet<T>>::sponsoring_mode(*contract);262 if mode == SponsoringModeT::Disabled {263 return None;264 }265266 let sponsor = match <Pallet<T>>::get_sponsor(*contract) {267 Some(sponsor) => sponsor,268 None => return None,269 };270271 if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(*contract, *who.as_eth()) {272 return None;273 }274 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;275276 if let Some(last_tx_block) = <SponsorBasket<T>>::get(contract, who.as_eth()) {277 let limit = <SponsoringRateLimit<T>>::get(contract);278279 let timeout = last_tx_block + limit;280 if block_number < timeout {281 return None;282 }283 }284285 <SponsorBasket<T>>::insert(contract, who.as_eth(), block_number);286287 Some(sponsor)288 }289}290291generate_stubgen!(contract_helpers_impl, ContractHelpersCall<()>, true);292generate_stubgen!(contract_helpers_iface, ContractHelpersCall<()>, false);