1use crate::{
21 evm::DryRunConfig, mock::MockHandler, storage::WriteOutcome, BalanceOf, Config, Time, H160,
22 U256,
23};
24use alloc::{boxed::Box, fmt::Debug, string::String, vec::Vec};
25use codec::{Decode, Encode, MaxEncodedLen};
26use frame_support::{traits::tokens::Balance, weights::Weight};
27use pallet_revive_uapi::ReturnFlags;
28use scale_info::TypeInfo;
29use sp_core::Get;
30use sp_runtime::{
31 traits::{One, Saturating, Zero},
32 DispatchError, RuntimeDebug,
33};
34
35#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
46pub struct ContractResult<R, Balance> {
47 pub weight_consumed: Weight,
49 pub weight_required: Weight,
60 pub storage_deposit: StorageDeposit<Balance>,
67 pub max_storage_deposit: StorageDeposit<Balance>,
71 pub gas_consumed: Balance,
73 pub result: Result<R, DispatchError>,
75}
76
77impl<R: Default, B: Balance> Default for ContractResult<R, B> {
78 fn default() -> Self {
79 Self {
80 weight_consumed: Default::default(),
81 weight_required: Default::default(),
82 storage_deposit: Default::default(),
83 max_storage_deposit: Default::default(),
84 gas_consumed: Default::default(),
85 result: Ok(Default::default()),
86 }
87 }
88}
89
90#[derive(Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo)]
92pub struct EthTransactInfo<Balance> {
93 pub weight_required: Weight,
95 pub storage_deposit: Balance,
97 pub max_storage_deposit: Balance,
99 pub eth_gas: U256,
101 pub data: Vec<u8>,
103}
104
105#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
107pub enum EthTransactError {
108 Data(Vec<u8>),
109 Message(String),
110}
111
112#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
113pub enum BalanceConversionError {
115 Value,
117 Dust,
119}
120
121#[derive(Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug)]
124pub struct BalanceWithDust<Balance> {
125 value: Balance,
127 dust: u32,
130}
131
132impl<Balance> From<Balance> for BalanceWithDust<Balance> {
133 fn from(value: Balance) -> Self {
134 Self { value, dust: 0 }
135 }
136}
137
138impl<Balance> BalanceWithDust<Balance> {
139 pub fn deconstruct(self) -> (Balance, u32) {
141 (self.value, self.dust)
142 }
143
144 pub fn new_unchecked<T: Config>(value: Balance, dust: u32) -> Self {
146 debug_assert!(dust < T::NativeToEthRatio::get());
147 Self { value, dust }
148 }
149
150 pub fn from_value<T: Config>(
152 value: U256,
153 ) -> Result<BalanceWithDust<BalanceOf<T>>, BalanceConversionError> {
154 if value.is_zero() {
155 return Ok(Default::default())
156 }
157
158 let (quotient, remainder) = value.div_mod(T::NativeToEthRatio::get().into());
159 let value = quotient.try_into().map_err(|_| BalanceConversionError::Value)?;
160 let dust = remainder.try_into().map_err(|_| BalanceConversionError::Dust)?;
161
162 Ok(BalanceWithDust { value, dust })
163 }
164}
165
166impl<Balance: Zero + One + Saturating> BalanceWithDust<Balance> {
167 pub fn is_zero(&self) -> bool {
169 self.value.is_zero() && self.dust == 0
170 }
171
172 pub fn into_rounded_balance(self) -> Balance {
174 if self.dust == 0 {
175 self.value
176 } else {
177 self.value.saturating_add(Balance::one())
178 }
179 }
180}
181
182pub type CodeUploadResult<Balance> = Result<CodeUploadReturnValue<Balance>, DispatchError>;
184
185pub type GetStorageResult = Result<Option<Vec<u8>>, ContractAccessError>;
187
188pub type SetStorageResult = Result<WriteOutcome, ContractAccessError>;
190
191#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)]
193pub enum ContractAccessError {
194 DoesntExist,
196 KeyDecodingFailed,
198 StorageWriteFailed(DispatchError),
200}
201
202#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, Default)]
204pub struct ExecReturnValue {
205 pub flags: ReturnFlags,
207 pub data: Vec<u8>,
209}
210
211impl ExecReturnValue {
212 pub fn did_revert(&self) -> bool {
214 self.flags.contains(ReturnFlags::REVERT)
215 }
216}
217
218#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, Default)]
220pub struct InstantiateReturnValue {
221 pub result: ExecReturnValue,
223 pub addr: H160,
225}
226
227#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo)]
229pub struct CodeUploadReturnValue<Balance> {
230 pub code_hash: sp_core::H256,
232 pub deposit: Balance,
234}
235
236#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
238pub enum Code {
239 Upload(Vec<u8>),
241 Existing(sp_core::H256),
243}
244
245#[derive(
247 Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo,
248)]
249pub enum StorageDeposit<Balance> {
250 Refund(Balance),
255 Charge(Balance),
260}
261
262impl<T, Balance> ContractResult<T, Balance> {
263 pub fn map_result<V>(self, map_fn: impl FnOnce(T) -> V) -> ContractResult<V, Balance> {
264 ContractResult {
265 weight_consumed: self.weight_consumed,
266 weight_required: self.weight_required,
267 storage_deposit: self.storage_deposit,
268 max_storage_deposit: self.max_storage_deposit,
269 gas_consumed: self.gas_consumed,
270 result: self.result.map(map_fn),
271 }
272 }
273}
274
275impl<Balance: Zero> Default for StorageDeposit<Balance> {
276 fn default() -> Self {
277 Self::Charge(Zero::zero())
278 }
279}
280
281impl<Balance: Zero + Copy> StorageDeposit<Balance> {
282 pub fn charge_or_zero(&self) -> Balance {
284 match self {
285 Self::Charge(amount) => *amount,
286 Self::Refund(_) => Zero::zero(),
287 }
288 }
289
290 pub fn is_zero(&self) -> bool {
291 match self {
292 Self::Charge(amount) => amount.is_zero(),
293 Self::Refund(amount) => amount.is_zero(),
294 }
295 }
296}
297
298impl<Balance> StorageDeposit<Balance>
299where
300 Balance: frame_support::traits::tokens::Balance + Saturating + Ord + Copy,
301{
302 pub fn saturating_add(&self, rhs: &Self) -> Self {
304 use StorageDeposit::*;
305 match (self, rhs) {
306 (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
307 (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
308 (Charge(lhs), Refund(rhs)) =>
309 if lhs >= rhs {
310 Charge(lhs.saturating_sub(*rhs))
311 } else {
312 Refund(rhs.saturating_sub(*lhs))
313 },
314 (Refund(lhs), Charge(rhs)) =>
315 if lhs > rhs {
316 Refund(lhs.saturating_sub(*rhs))
317 } else {
318 Charge(rhs.saturating_sub(*lhs))
319 },
320 }
321 }
322
323 pub fn saturating_sub(&self, rhs: &Self) -> Self {
325 use StorageDeposit::*;
326 match (self, rhs) {
327 (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
328 (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
329 (Charge(lhs), Charge(rhs)) =>
330 if lhs >= rhs {
331 Charge(lhs.saturating_sub(*rhs))
332 } else {
333 Refund(rhs.saturating_sub(*lhs))
334 },
335 (Refund(lhs), Refund(rhs)) =>
336 if lhs > rhs {
337 Refund(lhs.saturating_sub(*rhs))
338 } else {
339 Charge(rhs.saturating_sub(*lhs))
340 },
341 }
342 }
343
344 pub fn available(&self, limit: &Balance) -> Option<Balance> {
351 use StorageDeposit::*;
352 match self {
353 Charge(amount) => limit.checked_sub(amount),
354 Refund(amount) => Some(limit.saturating_add(*amount)),
355 }
356 }
357}
358
359pub struct ExecConfig<T: Config> {
361 pub bump_nonce: bool,
378 pub collect_deposit_from_hold: Option<(u32, Weight)>,
383 pub effective_gas_price: Option<U256>,
387 pub is_dry_run: Option<DryRunConfig<<<T as Config>::Time as Time>::Moment>>,
390 pub mock_handler: Option<Box<dyn MockHandler<T>>>,
394}
395
396impl<T: Config> ExecConfig<T> {
397 pub fn new_substrate_tx() -> Self {
399 Self {
400 bump_nonce: true,
401 collect_deposit_from_hold: None,
402 effective_gas_price: None,
403 is_dry_run: None,
404 mock_handler: None,
405 }
406 }
407
408 pub fn new_substrate_tx_without_bump() -> Self {
409 Self {
410 bump_nonce: false,
411 collect_deposit_from_hold: None,
412 effective_gas_price: None,
413 mock_handler: None,
414 is_dry_run: None,
415 }
416 }
417
418 pub fn new_eth_tx(effective_gas_price: U256, encoded_len: u32, base_weight: Weight) -> Self {
420 Self {
421 bump_nonce: false,
422 collect_deposit_from_hold: Some((encoded_len, base_weight)),
423 effective_gas_price: Some(effective_gas_price),
424 mock_handler: None,
425 is_dry_run: None,
426 }
427 }
428
429 pub fn with_dry_run(
431 mut self,
432 dry_run_config: DryRunConfig<<<T as Config>::Time as Time>::Moment>,
433 ) -> Self {
434 self.is_dry_run = Some(dry_run_config);
435 self
436 }
437
438 #[cfg(test)]
440 pub fn clone(&self) -> Self {
441 Self {
442 bump_nonce: self.bump_nonce,
443 collect_deposit_from_hold: self.collect_deposit_from_hold,
444 effective_gas_price: self.effective_gas_price,
445 is_dry_run: self.is_dry_run.clone(),
446 mock_handler: None,
447 }
448 }
449}
450
451#[must_use = "You must handle whether the code was removed or not."]
453pub enum CodeRemoved {
454 No,
456 Yes,
458}