git.delta.rocks / unique-network / refs/commits / 2dfd73643010

difftreelog

source

pallets/evm-contract-helpers/src/eth.rs6.2 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::Result, generate_stubgen, solidity_interface, types::*};19use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};20use pallet_evm::{ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure};21use sp_core::H160;22use crate::{23	AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,24};25use frame_support::traits::Get;26use up_sponsorship::SponsorshipHandler;27use sp_std::{convert::TryInto, vec::Vec};2829struct ContractHelpers<T: Config>(SubstrateRecorder<T>);30impl<T: Config> WithRecorder<T> for ContractHelpers<T> {31	fn recorder(&self) -> &SubstrateRecorder<T> {32		&self.033	}3435	fn into_recorder(self) -> SubstrateRecorder<T> {36		self.037	}38}3940#[solidity_interface(name = "ContractHelpers")]41impl<T: Config> ContractHelpers<T> {42	fn contract_owner(&self, contract_address: address) -> Result<address> {43		Ok(<Owner<T>>::get(contract_address))44	}4546	fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {47		Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)48	}4950	/// Deprecated51	fn toggle_sponsoring(52		&mut self,53		caller: caller,54		contract_address: address,55		enabled: bool,56	) -> Result<void> {57		<Pallet<T>>::ensure_owner(contract_address, caller)?;58		<Pallet<T>>::toggle_sponsoring(contract_address, enabled);59		Ok(())60	}6162	fn set_sponsoring_mode(63		&mut self,64		caller: caller,65		contract_address: address,66		mode: uint8,67	) -> Result<void> {68		<Pallet<T>>::ensure_owner(contract_address, caller)?;69		let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;70		<Pallet<T>>::set_sponsoring_mode(contract_address, mode);71		Ok(())72	}7374	fn sponsoring_mode(&self, contract_address: address) -> Result<uint8> {75		Ok(<Pallet<T>>::sponsoring_mode(contract_address).to_eth())76	}7778	fn set_sponsoring_rate_limit(79		&mut self,80		caller: caller,81		contract_address: address,82		rate_limit: uint32,83	) -> Result<void> {84		<Pallet<T>>::ensure_owner(contract_address, caller)?;85		<Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());86		Ok(())87	}8889	fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {90		Ok(<SponsoringRateLimit<T>>::get(contract_address)91			.try_into()92			.map_err(|_| "rate limit > u32::MAX")?)93	}9495	fn allowed(&self, contract_address: address, user: address) -> Result<bool> {96		self.0.consume_sload()?;97		Ok(<Pallet<T>>::allowed(contract_address, user))98	}99100	fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {101		Ok(<AllowlistEnabled<T>>::get(contract_address))102	}103104	fn toggle_allowlist(105		&mut self,106		caller: caller,107		contract_address: address,108		enabled: bool,109	) -> Result<void> {110		<Pallet<T>>::ensure_owner(contract_address, caller)?;111		<Pallet<T>>::toggle_allowlist(contract_address, enabled);112		Ok(())113	}114115	fn toggle_allowed(116		&mut self,117		caller: caller,118		contract_address: address,119		user: address,120		allowed: bool,121	) -> Result<void> {122		<Pallet<T>>::ensure_owner(contract_address, caller)?;123		<Pallet<T>>::toggle_allowed(contract_address, user, allowed);124		Ok(())125	}126}127128pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);129impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T> {130	fn is_reserved(contract: &sp_core::H160) -> bool {131		contract == &T::ContractAddress::get()132	}133134	fn is_used(contract: &sp_core::H160) -> bool {135		contract == &T::ContractAddress::get()136	}137138	fn call(139		source: &sp_core::H160,140		target: &sp_core::H160,141		gas_left: u64,142		input: &[u8],143		value: sp_core::U256,144	) -> Option<PrecompileResult> {145		// TODO: Extract to another OnMethodCall handler146		if <AllowlistEnabled<T>>::get(target) && !<Pallet<T>>::allowed(*target, *source) {147			return Some(Err(PrecompileFailure::Revert {148				exit_status: ExitRevert::Reverted,149				cost: 0,150				output: {151					let mut writer = AbiWriter::new_call(evm_coder::fn_selector!(Error(string)));152					writer.string("Target contract is allowlisted");153					writer.finish()154				},155			}));156		}157158		if target != &T::ContractAddress::get() {159			return None;160		}161162		let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));163		pallet_evm_coder_substrate::call(*source, helpers, value, input)164	}165166	fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {167		(contract == &T::ContractAddress::get())168			.then(|| include_bytes!("./stubs/ContractHelpers.raw").to_vec())169	}170}171172pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);173impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {174	fn on_create(owner: H160, contract: H160) {175		<Owner<T>>::insert(contract, owner);176	}177}178179pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);180impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for HelpersContractSponsoring<T> {181	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {182		let mode = <Pallet<T>>::sponsoring_mode(call.0);183		if mode == SponsoringModeT::Disabled {184			return None;185		}186		if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(call.0, *who) {187			return None;188		}189		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;190191		if let Some(last_tx_block) = <SponsorBasket<T>>::get(&call.0, who) {192			let limit = <SponsoringRateLimit<T>>::get(&call.0);193194			let timeout = last_tx_block + limit;195			if block_number < timeout {196				return None;197			}198		}199200		<SponsorBasket<T>>::insert(&call.0, who, block_number);201202		Some(call.0)203	}204}205206generate_stubgen!(contract_helpers_impl, ContractHelpersCall<()>, true);207generate_stubgen!(contract_helpers_iface, ContractHelpersCall<()>, false);