diff --git a/pallets/dnt-fee-controller/src/lib.rs b/pallets/dnt-fee-controller/src/lib.rs index 0205b817..0db9d979 100644 --- a/pallets/dnt-fee-controller/src/lib.rs +++ b/pallets/dnt-fee-controller/src/lib.rs @@ -31,6 +31,7 @@ pub mod pallet { ERC20WithdrawFailed, ERC20DepositFailed, FeeVaultOverflow, + ArithmeticError, InvalidPercentage, } @@ -105,9 +106,14 @@ pub mod pallet { ) -> Result<(), Self::Error> { let fee_vault = FeeVaultPrecompileAddressStorage::::get().unwrap(); let mapped_amount = amount - .saturating_mul(conversion_rate.0) - .div_mod(conversion_rate.1) - .0; + .checked_mul(conversion_rate.0) + .map(|v| v.div_mod(conversion_rate.1).0); + + let mapped_amount = match mapped_amount { + Some(amount) => amount, + None => return Err(Error::ArithmeticError), + }; + T::ERC20Manager::withdraw_amount(token, from, mapped_amount) .map_err(|_| Error::::ERC20WithdrawFailed)?; T::ERC20Manager::deposit_amount(token, fee_vault, mapped_amount) @@ -123,11 +129,22 @@ pub mod pallet { paid_amount: U256, actual_amount: U256, ) -> Result<(), Self::Error> { - let over_fee = paid_amount.saturating_sub(actual_amount); + let over_fee = paid_amount.checked_sub(actual_amount); + + let over_fee = match over_fee { + Some(amount) => amount, + None => return Err(Error::ArithmeticError), + }; + let mapped_amount = over_fee - .saturating_mul(conversion_rate.0) - .div_mod(conversion_rate.1) - .0; + .checked_mul(conversion_rate.0) + .map(|v| v.div_mod(conversion_rate.1).0); + + let mapped_amount = match mapped_amount { + Some(amount) => amount, + None => return Err(Error::ArithmeticError), + }; + let fee_vault = FeeVaultPrecompileAddressStorage::::get().unwrap(); T::ERC20Manager::withdraw_amount(token, fee_vault, mapped_amount) .map_err(|_| Error::::ERC20WithdrawFailed)?; @@ -145,9 +162,13 @@ pub mod pallet { to: Option, ) -> Result<(U256, U256), Self::Error> { let fee_in_user_token = actual_amount - .saturating_mul(conversion_rate.0) - .div_mod(conversion_rate.1) - .0; + .checked_mul(conversion_rate.0) + .map(|v| v.div_mod(conversion_rate.1).0); + + let fee_in_user_token = match fee_in_user_token { + Some(amount) => amount, + None => return Err(Error::ArithmeticError), + }; let validator_share = match to { None => 100.into(), @@ -155,9 +176,14 @@ pub mod pallet { }; let validator_fee = fee_in_user_token - .saturating_mul(validator_share.into()) - .div_mod(U256::from(100)) - .0; + .checked_mul(validator_share.into()) + .map(|v| v.div_mod(U256::from(100)).0); + + let validator_fee = match validator_fee { + Some(a) => a, + None => return Err(Error::ArithmeticError), + }; + let dapp_fee = fee_in_user_token - validator_fee; pallet_fee_rewards_vault::Pallet::::add_claimable_reward( diff --git a/pallets/sponsored-transactions/src/lib.rs b/pallets/sponsored-transactions/src/lib.rs index e5bf15d7..563eb5de 100644 --- a/pallets/sponsored-transactions/src/lib.rs +++ b/pallets/sponsored-transactions/src/lib.rs @@ -137,12 +137,17 @@ pub mod pallet { let (transaction_fee_token, conversion_rate) = Self::get_fee_token_info(&from); + let max_gas_used = match gas_limit.checked_mul(gas_price.into()) { + Some(a) => a, + None => return Err(DispatchError::Other("Arithmetic error due to overflow.")), + }; + Self::transfer_fee_token( &transaction_fee_token, conversion_rate, &meta_trx_sponsor, &from, - gas_limit.saturating_mul(gas_price.into()), + max_gas_used, ) .map_err(|_| DispatchError::Other("Failed to borrow fee token"))?; @@ -151,16 +156,25 @@ pub mod pallet { let dispatch = pallet_ethereum::Pallet::::transact(origin, transaction) .map_err(|_| DispatchError::Other("Signature doesn't meet with sponsor address"))?; - let gas_used = Self::gas_from_actual_weight(dispatch.actual_weight.unwrap()); + let gas_used = Self::gas_from_actual_weight(dispatch.actual_weight.unwrap()) + .map_err(|_| DispatchError::Other("Arithmetic error due to overflow."))?; - let gas_left = gas_limit.saturating_sub(gas_used.into()); + let gas_left = match gas_limit.checked_sub(gas_used.into()) { + Some(v) => v, + None => 0.into(), + }; + + let refunding_amount = match gas_left.checked_mul(gas_price.into()) { + Some(amount) => amount, + None => return Err(DispatchError::Other("Arithmetic error due to overflow.")), + }; Self::transfer_fee_token( &transaction_fee_token, conversion_rate, &from, &meta_trx_sponsor, - gas_left.saturating_mul(gas_price.into()), + refunding_amount, ) .map_err(|_| DispatchError::Other("Failed to refund fee token"))?; @@ -281,14 +295,19 @@ pub mod pallet { } } - fn gas_from_actual_weight(weight: Weight) -> u64 { - let actual_weight = weight.saturating_add( - T::BlockWeights::get() + fn gas_from_actual_weight(weight: Weight) -> Result { + let actual_weight = match weight.checked_add( + &T::BlockWeights::get() .get(frame_support::dispatch::DispatchClass::Normal) .base_extrinsic, - ); + ) { + Some(v) => v, + None => return Err(()), + }; - ::GasWeightMapping::weight_to_gas(actual_weight) + Ok(::GasWeightMapping::weight_to_gas( + actual_weight, + )) } fn ensure_sponsor_balance(sponsor: H160, token: H160, amount: U256) -> Result<(), ()> { @@ -307,10 +326,14 @@ pub mod pallet { payee: &H160, amount: U256, ) -> Result<(), ()> { - let actual_amount = amount - .saturating_mul(conversion_rate.0) - .div_mod(conversion_rate.1) - .0; + let actual_amount = match amount + .checked_mul(conversion_rate.0) + .map(|v| v.div_mod(conversion_rate.1).0) + { + Some(v) => v, + None => return Err(()), + }; + T::ERC20Manager::withdraw_amount(token.clone(), payer.clone(), actual_amount) .map_err(|_| {})?; diff --git a/pallets/sponsored-transactions/src/tests.rs b/pallets/sponsored-transactions/src/tests.rs index cc98f192..8e705ba9 100644 --- a/pallets/sponsored-transactions/src/tests.rs +++ b/pallets/sponsored-transactions/src/tests.rs @@ -188,9 +188,9 @@ fn check_correct_fee_management(called_arguments: Vec<(bool, H160, H160, U256)>) for (is_deposit, token, _, amount) in called_arguments.iter() { assert!(token.eq(&called_arguments[0].1)); if *is_deposit { - total_deposited = amount.saturating_add(total_deposited); + total_deposited = amount.checked_add(total_deposited).unwrap(); } else { - total_withdrawn = amount.saturating_add(total_withdrawn); + total_withdrawn = amount.checked_add(total_withdrawn).unwrap(); } } assert_eq!(total_deposited, total_withdrawn); diff --git a/pallets/validator-set/src/lib.rs b/pallets/validator-set/src/lib.rs index 9b8d2023..90860ce4 100644 --- a/pallets/validator-set/src/lib.rs +++ b/pallets/validator-set/src/lib.rs @@ -465,10 +465,15 @@ impl Pallet { fn do_remove_validator(validator_id: T::AccountId) -> DispatchResult { let mut validators = >::get(); + let validators_count = match validators.len().checked_sub(1) { + Some(v) => v, + None => return Err(DispatchError::Other("Arithmetic error due to underflow.")), + }; + // Ensuring that the post removal, target validator count doesn't go // below the minimum. ensure!( - validators.len().saturating_sub(1) as u32 >= T::MinAuthorities::get(), + validators_count as u32 >= T::MinAuthorities::get(), Error::::TooLowValidatorCount ); diff --git a/pallets/zero-gas-transactions/src/lib.rs b/pallets/zero-gas-transactions/src/lib.rs index 5527bcbf..349a0008 100644 --- a/pallets/zero-gas-transactions/src/lib.rs +++ b/pallets/zero-gas-transactions/src/lib.rs @@ -19,10 +19,10 @@ pub mod pallet { use frame_system::pallet_prelude::*; use pallet_evm::GasWeightMapping; use pallet_user_fee_selector::UserFeeTokenController; + use sp_core::H256; use sp_core::U256; use sp_std::vec; - use sp_core::{H256}; - use sp_std::{vec::Vec}; + use sp_std::vec::Vec; pub use fp_rpc::TransactionStatus; @@ -52,21 +52,23 @@ pub mod pallet { fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { match call { - Call::send_zero_gas_transaction { transaction, validator_signature } => { + Call::send_zero_gas_transaction { + transaction, + validator_signature, + } => { let from = Self::ensure_transaction_signature(transaction.clone()).map_err(|_| { TransactionValidityError::Invalid(InvalidTransaction::BadProof) })?; - let current_block_validator = >::find_author(); + let current_block_validator = >::find_author(); - Self::ensure_zero_gas_transaction( - transaction.clone(), - current_block_validator, - validator_signature.clone() - ).map_err(|_| { - TransactionValidityError::Invalid(InvalidTransaction::BadProof) - })?; + Self::ensure_zero_gas_transaction( + transaction.clone(), + current_block_validator, + validator_signature.clone(), + ) + .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::BadProof))?; let transaction_data: TransactionData = transaction.into(); @@ -116,9 +118,9 @@ pub mod pallet { let current_block_validator = >::find_author(); Self::ensure_zero_gas_transaction( - transaction.clone(), - current_block_validator, - validator_signature + transaction.clone(), + current_block_validator, + validator_signature, ) .map_err(|_| DispatchError::Other("Invalid zero gas transaction signature"))?; @@ -127,7 +129,8 @@ pub mod pallet { let dispatch = pallet_ethereum::Pallet::::transact(origin, transaction) .map_err(|_| DispatchError::Other("Signature doesn't meet with sponsor address"))?; - let used_gas = Self::gas_from_actual_weight(dispatch.actual_weight.unwrap()); + let used_gas = Self::gas_from_actual_weight(dispatch.actual_weight.unwrap()) + .map_err(|_| DispatchError::Other("Arithmetic error due to overflows"))?; Ok(frame_support::dispatch::PostDispatchInfo { actual_weight: Some(T::GasWeightMapping::gas_to_weight( @@ -140,14 +143,19 @@ pub mod pallet { } impl Pallet { - fn gas_from_actual_weight(weight: Weight) -> u64 { - let actual_weight = weight.saturating_add( - T::BlockWeights::get() + fn gas_from_actual_weight(weight: Weight) -> Result { + let actual_weight = match weight.checked_add( + &T::BlockWeights::get() .get(frame_support::dispatch::DispatchClass::Normal) .base_extrinsic, - ); + ) { + Some(v) => v, + None => return Err(()), + }; - ::GasWeightMapping::weight_to_gas(actual_weight) + Ok(::GasWeightMapping::weight_to_gas( + actual_weight, + )) } fn ensure_transaction_signature( @@ -196,10 +204,8 @@ pub mod pallet { let eip191_message = stbl_tools::eth::build_eip191_message_hash(zero_gas_trx_internal_message); - let zero_gas_trx_signer_address = Self::get_zero_gas_trx_signer( - validator_signature.clone(), - eip191_message.clone(), - ); + let zero_gas_trx_signer_address = + Self::get_zero_gas_trx_signer(validator_signature.clone(), eip191_message.clone()); match zero_gas_trx_signer_address { Some(address) if address == expected_validator => Ok(()), @@ -207,7 +213,9 @@ pub mod pallet { } } - pub fn get_zero_gas_transaction_signing_message(trx: pallet_ethereum::Transaction) -> Vec { + pub fn get_zero_gas_transaction_signing_message( + trx: pallet_ethereum::Transaction, + ) -> Vec { let mut message: Vec = Vec::new(); let trx_hash = trx.hash(); diff --git a/pallets/zero-gas-transactions/src/tests.rs b/pallets/zero-gas-transactions/src/tests.rs index cc98f192..8e705ba9 100644 --- a/pallets/zero-gas-transactions/src/tests.rs +++ b/pallets/zero-gas-transactions/src/tests.rs @@ -188,9 +188,9 @@ fn check_correct_fee_management(called_arguments: Vec<(bool, H160, H160, U256)>) for (is_deposit, token, _, amount) in called_arguments.iter() { assert!(token.eq(&called_arguments[0].1)); if *is_deposit { - total_deposited = amount.saturating_add(total_deposited); + total_deposited = amount.checked_add(total_deposited).unwrap(); } else { - total_withdrawn = amount.saturating_add(total_withdrawn); + total_withdrawn = amount.checked_add(total_withdrawn).unwrap(); } } assert_eq!(total_deposited, total_withdrawn); diff --git a/primitives/runner/src/lib.rs b/primitives/runner/src/lib.rs index 49235755..e27e3276 100644 --- a/primitives/runner/src/lib.rs +++ b/primitives/runner/src/lib.rs @@ -326,7 +326,15 @@ where let (base_fee, mut weight) = T::FeeCalculator::min_gas_price(); let (source_account, inner_weight) = Pallet::::account_basic(&source); - weight = weight.saturating_add(inner_weight); + weight = match weight.checked_add(&inner_weight) { + Some(v) => v, + None => { + return Err(RunnerError { + error: Self::Error::FeeOverflow, + weight, + }) + } + }; let _ = fp_evm::CheckEvmTransaction::::new( fp_evm::CheckEvmTransactionConfig {