1use crate::{
21 BalanceOf, Config, H160, Time, U256, deposit_payment::Funds, evm::DryRunConfig,
22 mock::MockHandler, 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
233impl<Balance> From<CodeUploadReturnValue<Balance>>
234 for pallet_revive_types::runtime_api::CodeUploadReturnValueV1<Balance>
235{
236 fn from(value: CodeUploadReturnValue<Balance>) -> Self {
237 Self { code_hash: value.code_hash, deposit: value.deposit }
238 }
239}
240
241#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)]
243pub enum Code {
244 Upload(Vec<u8>),
246 Existing(sp_core::H256),
248}
249
250#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)]
252pub enum StorageDeposit<Balance> {
253 Refund(Balance),
258 Charge(Balance),
263}
264
265impl<T, Balance> ContractResult<T, Balance> {
266 pub fn map_result<V>(self, map_fn: impl FnOnce(T) -> V) -> ContractResult<V, Balance> {
267 ContractResult {
268 weight_consumed: self.weight_consumed,
269 weight_required: self.weight_required,
270 storage_deposit: self.storage_deposit,
271 max_storage_deposit: self.max_storage_deposit,
272 gas_consumed: self.gas_consumed,
273 result: self.result.map(map_fn),
274 }
275 }
276}
277
278impl<Balance: Zero> Default for StorageDeposit<Balance> {
279 fn default() -> Self {
280 Self::Charge(Zero::zero())
281 }
282}
283
284impl<Balance: Zero + Copy> StorageDeposit<Balance> {
285 pub fn charge_or_zero(&self) -> Balance {
287 match self {
288 Self::Charge(amount) => *amount,
289 Self::Refund(_) => Zero::zero(),
290 }
291 }
292
293 pub fn is_zero(&self) -> bool {
294 match self {
295 Self::Charge(amount) => amount.is_zero(),
296 Self::Refund(amount) => amount.is_zero(),
297 }
298 }
299}
300
301impl<Balance> StorageDeposit<Balance>
302where
303 Balance: frame_support::traits::tokens::Balance + Saturating + Ord + Copy,
304{
305 pub fn saturating_add(&self, rhs: &Self) -> Self {
307 use StorageDeposit::*;
308 match (self, rhs) {
309 (Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
310 (Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
311 (Charge(lhs), Refund(rhs)) => {
312 if lhs >= rhs {
313 Charge(lhs.saturating_sub(*rhs))
314 } else {
315 Refund(rhs.saturating_sub(*lhs))
316 }
317 },
318 (Refund(lhs), Charge(rhs)) => {
319 if lhs > rhs {
320 Refund(lhs.saturating_sub(*rhs))
321 } else {
322 Charge(rhs.saturating_sub(*lhs))
323 }
324 },
325 }
326 }
327
328 pub fn saturating_sub(&self, rhs: &Self) -> Self {
330 use StorageDeposit::*;
331 match (self, rhs) {
332 (Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
333 (Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
334 (Charge(lhs), Charge(rhs)) => {
335 if lhs >= rhs {
336 Charge(lhs.saturating_sub(*rhs))
337 } else {
338 Refund(rhs.saturating_sub(*lhs))
339 }
340 },
341 (Refund(lhs), Refund(rhs)) => {
342 if lhs > rhs {
343 Refund(lhs.saturating_sub(*rhs))
344 } else {
345 Charge(rhs.saturating_sub(*lhs))
346 }
347 },
348 }
349 }
350
351 pub fn available(&self, limit: &Balance) -> Option<Balance> {
358 use StorageDeposit::*;
359 match self {
360 Charge(amount) => limit.checked_sub(amount),
361 Refund(amount) => Some(limit.saturating_add(*amount)),
362 }
363 }
364}
365
366#[derive(DefaultNoBound)]
368pub struct ExecConfig<T: Config> {
369 pub bump_nonce: bool,
386 pub collect_deposit_from_hold: Option<(u32, Weight)>,
391 pub effective_gas_price: Option<U256>,
395 pub is_dry_run: Option<DryRunConfig<<<T as Config>::Time as Time>::Moment>>,
398 pub mock_handler: Option<Box<dyn MockHandler<T>>>,
402 pub test_env_transient_storage: Option<RefCell<TransientStorage<T>>>,
407}
408
409impl<T: Config> ExecConfig<T> {
410 pub fn new_substrate_tx() -> Self {
412 Self {
413 bump_nonce: true,
414 collect_deposit_from_hold: None,
415 effective_gas_price: None,
416 is_dry_run: None,
417 mock_handler: None,
418 test_env_transient_storage: None,
419 }
420 }
421
422 pub fn new_substrate_tx_without_bump() -> Self {
423 Self {
424 bump_nonce: false,
425 collect_deposit_from_hold: None,
426 effective_gas_price: None,
427 mock_handler: None,
428 is_dry_run: None,
429 test_env_transient_storage: None,
430 }
431 }
432
433 pub fn new_eth_tx(effective_gas_price: U256, encoded_len: u32, base_weight: Weight) -> Self {
435 Self {
436 bump_nonce: false,
437 collect_deposit_from_hold: Some((encoded_len, base_weight)),
438 effective_gas_price: Some(effective_gas_price),
439 mock_handler: None,
440 is_dry_run: None,
441 test_env_transient_storage: None,
442 }
443 }
444
445 pub fn with_dry_run(
447 mut self,
448 dry_run_config: DryRunConfig<<<T as Config>::Time as Time>::Moment>,
449 ) -> Self {
450 self.is_dry_run = Some(dry_run_config);
451 self
452 }
453
454 pub fn funds<'a>(&self, account: &'a T::AccountId) -> Funds<'a, T::AccountId> {
458 if self.collect_deposit_from_hold.is_some() {
459 Funds::TxFee(account)
460 } else {
461 Funds::Balance(account)
462 }
463 }
464
465 #[cfg(test)]
467 pub fn clone(&self) -> Self {
468 Self {
469 bump_nonce: self.bump_nonce,
470 collect_deposit_from_hold: self.collect_deposit_from_hold,
471 effective_gas_price: self.effective_gas_price,
472 is_dry_run: self.is_dry_run.clone(),
473 mock_handler: None,
474 test_env_transient_storage: None,
475 }
476 }
477}
478
479#[must_use = "You must handle whether the code was removed or not."]
481pub enum CodeRemoved {
482 No,
484 Yes,
486}