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,
33};
34
35#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, 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, Debug, 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, Debug, TypeInfo)]
107pub enum EthTransactError {
108 Data(Vec<u8>),
109 Message(String),
110}
111
112#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, 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, Debug, TypeInfo)]
193pub enum ContractAccessError {
194 DoesntExist,
196 KeyDecodingFailed,
198 StorageWriteFailed(DispatchError),
200}
201
202#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, 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, Debug, TypeInfo, Default)]
220pub struct InstantiateReturnValue {
221 pub result: ExecReturnValue,
223 pub addr: H160,
225}
226
227#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, Debug, 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, Debug, TypeInfo)]
238pub enum Code {
239 Upload(Vec<u8>),
241 Existing(sp_core::H256),
243}
244
245#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)]
247pub enum StorageDeposit<Balance> {
248 Refund(Balance),
253 Charge(Balance),
258}
259
260impl<T, Balance> ContractResult<T, Balance> {
261 pub fn map_result<V>(self, map_fn: impl FnOnce(T) -> V) -> ContractResult<V, Balance> {
262 ContractResult {
263 weight_consumed: self.weight_consumed,
264 weight_required: self.weight_required,
265 storage_deposit: self.storage_deposit,
266 max_storage_deposit: self.max_storage_deposit,
267 gas_consumed: self.gas_consumed,
268 result: self.result.map(map_fn),
269 }
270 }
271}
272
273impl<Balance: Zero> Default for StorageDeposit<Balance> {
274 fn default() -> Self {
275 Self::Charge(Zero::zero())
276 }
277}
278
279impl<Balance: Zero + Copy> StorageDeposit<Balance> {
280 pub fn charge_or_zero(&self) -> Balance {
282 match self {
283 Self::Charge(amount) => *amount,
284 Self::Refund(_) => Zero::zero(),
285 }
286 }
287
288 pub fn is_zero(&self) -> bool {
289 match self {
290 Self::Charge(amount) => amount.is_zero(),
291 Self::Refund(amount) => amount.is_zero(),
292 }
293 }
294}
295
296impl<Balance> StorageDeposit<Balance>
297where
298 Balance: frame_support::traits::tokens::Balance + Saturating + Ord + Copy,
299{
300 pub fn saturating_add(&self, rhs: &Self) -> Self {
302 use StorageDeposit::*;
303 match (self, rhs) {
304 (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
305 (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
306 (Charge(lhs), Refund(rhs)) =>
307 if lhs >= rhs {
308 Charge(lhs.saturating_sub(*rhs))
309 } else {
310 Refund(rhs.saturating_sub(*lhs))
311 },
312 (Refund(lhs), Charge(rhs)) =>
313 if lhs > rhs {
314 Refund(lhs.saturating_sub(*rhs))
315 } else {
316 Charge(rhs.saturating_sub(*lhs))
317 },
318 }
319 }
320
321 pub fn saturating_sub(&self, rhs: &Self) -> Self {
323 use StorageDeposit::*;
324 match (self, rhs) {
325 (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
326 (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
327 (Charge(lhs), Charge(rhs)) =>
328 if lhs >= rhs {
329 Charge(lhs.saturating_sub(*rhs))
330 } else {
331 Refund(rhs.saturating_sub(*lhs))
332 },
333 (Refund(lhs), Refund(rhs)) =>
334 if lhs > rhs {
335 Refund(lhs.saturating_sub(*rhs))
336 } else {
337 Charge(rhs.saturating_sub(*lhs))
338 },
339 }
340 }
341
342 pub fn available(&self, limit: &Balance) -> Option<Balance> {
349 use StorageDeposit::*;
350 match self {
351 Charge(amount) => limit.checked_sub(amount),
352 Refund(amount) => Some(limit.saturating_add(*amount)),
353 }
354 }
355}
356
357pub struct ExecConfig<T: Config> {
359 pub bump_nonce: bool,
376 pub collect_deposit_from_hold: Option<(u32, Weight)>,
381 pub effective_gas_price: Option<U256>,
385 pub is_dry_run: Option<DryRunConfig<<<T as Config>::Time as Time>::Moment>>,
388 pub mock_handler: Option<Box<dyn MockHandler<T>>>,
392}
393
394impl<T: Config> ExecConfig<T> {
395 pub fn new_substrate_tx() -> Self {
397 Self {
398 bump_nonce: true,
399 collect_deposit_from_hold: None,
400 effective_gas_price: None,
401 is_dry_run: None,
402 mock_handler: None,
403 }
404 }
405
406 pub fn new_substrate_tx_without_bump() -> Self {
407 Self {
408 bump_nonce: false,
409 collect_deposit_from_hold: None,
410 effective_gas_price: None,
411 mock_handler: None,
412 is_dry_run: None,
413 }
414 }
415
416 pub fn new_eth_tx(effective_gas_price: U256, encoded_len: u32, base_weight: Weight) -> Self {
418 Self {
419 bump_nonce: false,
420 collect_deposit_from_hold: Some((encoded_len, base_weight)),
421 effective_gas_price: Some(effective_gas_price),
422 mock_handler: None,
423 is_dry_run: None,
424 }
425 }
426
427 pub fn with_dry_run(
429 mut self,
430 dry_run_config: DryRunConfig<<<T as Config>::Time as Time>::Moment>,
431 ) -> Self {
432 self.is_dry_run = Some(dry_run_config);
433 self
434 }
435
436 #[cfg(test)]
438 pub fn clone(&self) -> Self {
439 Self {
440 bump_nonce: self.bump_nonce,
441 collect_deposit_from_hold: self.collect_deposit_from_hold,
442 effective_gas_price: self.effective_gas_price,
443 is_dry_run: self.is_dry_run.clone(),
444 mock_handler: None,
445 }
446 }
447}
448
449#[must_use = "You must handle whether the code was removed or not."]
451pub enum CodeRemoved {
452 No,
454 Yes,
456}