1use crate::{
21 BalanceOf, Config, H160, Time, U256, evm::DryRunConfig, mock::MockHandler,
22 storage::WriteOutcome, transient_storage::TransientStorage,
23};
24use alloc::{boxed::Box, fmt::Debug, string::String, vec::Vec};
25use codec::{Decode, Encode, MaxEncodedLen};
26use core::cell::RefCell;
27use frame_support::{DefaultNoBound, traits::tokens::Balance, weights::Weight};
28use pallet_revive_uapi::ReturnFlags;
29use scale_info::TypeInfo;
30use sp_core::Get;
31use sp_runtime::{
32 DispatchError,
33 traits::{One, Saturating, Zero},
34};
35
36#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
47pub struct ContractResult<R, Balance> {
48 pub weight_consumed: Weight,
50 pub weight_required: Weight,
61 pub storage_deposit: StorageDeposit<Balance>,
68 pub max_storage_deposit: StorageDeposit<Balance>,
72 pub gas_consumed: Balance,
74 pub result: Result<R, DispatchError>,
76}
77
78impl<R: Default, B: Balance> Default for ContractResult<R, B> {
79 fn default() -> Self {
80 Self {
81 weight_consumed: Default::default(),
82 weight_required: Default::default(),
83 storage_deposit: Default::default(),
84 max_storage_deposit: Default::default(),
85 gas_consumed: Default::default(),
86 result: Ok(Default::default()),
87 }
88 }
89}
90
91#[derive(Clone, Eq, PartialEq, Default, Encode, Decode, Debug, TypeInfo)]
93pub struct EthTransactInfo<Balance> {
94 pub weight_required: Weight,
96 pub storage_deposit: Balance,
98 pub max_storage_deposit: Balance,
100 pub eth_gas: U256,
102 pub data: Vec<u8>,
104}
105
106#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
108pub enum EthTransactError {
109 Data(Vec<u8>),
110 Message(String),
111}
112
113#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
114pub enum BalanceConversionError {
116 Value,
118 Dust,
120}
121
122#[derive(Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug)]
125pub struct BalanceWithDust<Balance> {
126 value: Balance,
128 dust: u32,
131}
132
133impl<Balance> From<Balance> for BalanceWithDust<Balance> {
134 fn from(value: Balance) -> Self {
135 Self { value, dust: 0 }
136 }
137}
138
139impl<Balance> BalanceWithDust<Balance> {
140 pub fn deconstruct(self) -> (Balance, u32) {
142 (self.value, self.dust)
143 }
144
145 pub fn new_unchecked<T: Config>(value: Balance, dust: u32) -> Self {
147 debug_assert!(dust < T::NativeToEthRatio::get());
148 Self { value, dust }
149 }
150
151 pub fn from_value<T: Config>(
153 value: U256,
154 ) -> Result<BalanceWithDust<BalanceOf<T>>, BalanceConversionError> {
155 if value.is_zero() {
156 return Ok(Default::default());
157 }
158
159 let (quotient, remainder) = value.div_mod(T::NativeToEthRatio::get().into());
160 let value = quotient.try_into().map_err(|_| BalanceConversionError::Value)?;
161 let dust = remainder.try_into().map_err(|_| BalanceConversionError::Dust)?;
162
163 Ok(BalanceWithDust { value, dust })
164 }
165}
166
167impl<Balance: Zero + One + Saturating> BalanceWithDust<Balance> {
168 pub fn is_zero(&self) -> bool {
170 self.value.is_zero() && self.dust == 0
171 }
172
173 pub fn into_rounded_balance(self) -> Balance {
175 if self.dust == 0 { self.value } else { self.value.saturating_add(Balance::one()) }
176 }
177}
178
179pub type CodeUploadResult<Balance> = Result<CodeUploadReturnValue<Balance>, DispatchError>;
181
182pub type GetStorageResult = Result<Option<Vec<u8>>, ContractAccessError>;
184
185pub type SetStorageResult = Result<WriteOutcome, ContractAccessError>;
187
188#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)]
190pub enum ContractAccessError {
191 DoesntExist,
193 KeyDecodingFailed,
195 StorageWriteFailed(DispatchError),
197}
198
199#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo, Default)]
201pub struct ExecReturnValue {
202 pub flags: ReturnFlags,
204 pub data: Vec<u8>,
206}
207
208impl ExecReturnValue {
209 pub fn did_revert(&self) -> bool {
211 self.flags.contains(ReturnFlags::REVERT)
212 }
213}
214
215#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo, Default)]
217pub struct InstantiateReturnValue {
218 pub result: ExecReturnValue,
220 pub addr: H160,
222}
223
224#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)]
226pub struct CodeUploadReturnValue<Balance> {
227 pub code_hash: sp_core::H256,
229 pub deposit: Balance,
231}
232
233#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
235pub enum Code {
236 Upload(Vec<u8>),
238 Existing(sp_core::H256),
240}
241
242#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)]
244pub enum StorageDeposit<Balance> {
245 Refund(Balance),
250 Charge(Balance),
255}
256
257impl<T, Balance> ContractResult<T, Balance> {
258 pub fn map_result<V>(self, map_fn: impl FnOnce(T) -> V) -> ContractResult<V, Balance> {
259 ContractResult {
260 weight_consumed: self.weight_consumed,
261 weight_required: self.weight_required,
262 storage_deposit: self.storage_deposit,
263 max_storage_deposit: self.max_storage_deposit,
264 gas_consumed: self.gas_consumed,
265 result: self.result.map(map_fn),
266 }
267 }
268}
269
270impl<Balance: Zero> Default for StorageDeposit<Balance> {
271 fn default() -> Self {
272 Self::Charge(Zero::zero())
273 }
274}
275
276impl<Balance: Zero + Copy> StorageDeposit<Balance> {
277 pub fn charge_or_zero(&self) -> Balance {
279 match self {
280 Self::Charge(amount) => *amount,
281 Self::Refund(_) => Zero::zero(),
282 }
283 }
284
285 pub fn is_zero(&self) -> bool {
286 match self {
287 Self::Charge(amount) => amount.is_zero(),
288 Self::Refund(amount) => amount.is_zero(),
289 }
290 }
291}
292
293impl<Balance> StorageDeposit<Balance>
294where
295 Balance: frame_support::traits::tokens::Balance + Saturating + Ord + Copy,
296{
297 pub fn saturating_add(&self, rhs: &Self) -> Self {
299 use StorageDeposit::*;
300 match (self, rhs) {
301 (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
302 (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
303 (Charge(lhs), Refund(rhs)) => {
304 if lhs >= rhs {
305 Charge(lhs.saturating_sub(*rhs))
306 } else {
307 Refund(rhs.saturating_sub(*lhs))
308 }
309 },
310 (Refund(lhs), Charge(rhs)) => {
311 if lhs > rhs {
312 Refund(lhs.saturating_sub(*rhs))
313 } else {
314 Charge(rhs.saturating_sub(*lhs))
315 }
316 },
317 }
318 }
319
320 pub fn saturating_sub(&self, rhs: &Self) -> Self {
322 use StorageDeposit::*;
323 match (self, rhs) {
324 (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
325 (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
326 (Charge(lhs), Charge(rhs)) => {
327 if lhs >= rhs {
328 Charge(lhs.saturating_sub(*rhs))
329 } else {
330 Refund(rhs.saturating_sub(*lhs))
331 }
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
343 pub fn available(&self, limit: &Balance) -> Option<Balance> {
350 use StorageDeposit::*;
351 match self {
352 Charge(amount) => limit.checked_sub(amount),
353 Refund(amount) => Some(limit.saturating_add(*amount)),
354 }
355 }
356}
357
358#[derive(DefaultNoBound)]
360pub 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 pub test_env_transient_storage: Option<RefCell<TransientStorage<T>>>,
399}
400
401impl<T: Config> ExecConfig<T> {
402 pub fn new_substrate_tx() -> Self {
404 Self {
405 bump_nonce: true,
406 collect_deposit_from_hold: None,
407 effective_gas_price: None,
408 is_dry_run: None,
409 mock_handler: None,
410 test_env_transient_storage: None,
411 }
412 }
413
414 pub fn new_substrate_tx_without_bump() -> Self {
415 Self {
416 bump_nonce: false,
417 collect_deposit_from_hold: None,
418 effective_gas_price: None,
419 mock_handler: None,
420 is_dry_run: None,
421 test_env_transient_storage: None,
422 }
423 }
424
425 pub fn new_eth_tx(effective_gas_price: U256, encoded_len: u32, base_weight: Weight) -> Self {
427 Self {
428 bump_nonce: false,
429 collect_deposit_from_hold: Some((encoded_len, base_weight)),
430 effective_gas_price: Some(effective_gas_price),
431 mock_handler: None,
432 is_dry_run: None,
433 test_env_transient_storage: None,
434 }
435 }
436
437 pub fn with_dry_run(
439 mut self,
440 dry_run_config: DryRunConfig<<<T as Config>::Time as Time>::Moment>,
441 ) -> Self {
442 self.is_dry_run = Some(dry_run_config);
443 self
444 }
445
446 #[cfg(test)]
448 pub fn clone(&self) -> Self {
449 Self {
450 bump_nonce: self.bump_nonce,
451 collect_deposit_from_hold: self.collect_deposit_from_hold,
452 effective_gas_price: self.effective_gas_price,
453 is_dry_run: self.is_dry_run.clone(),
454 mock_handler: None,
455 test_env_transient_storage: None,
456 }
457 }
458}
459
460#[must_use = "You must handle whether the code was removed or not."]
462pub enum CodeRemoved {
463 No,
465 Yes,
467}