Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ use mm2_core::mm_ctx::{MmArc, MmWeak};
use mm2_number::bigdecimal_custom::CheckedDivision;
use mm2_number::{BigDecimal, BigUint, MmNumber};
use rand::seq::SliceRandom;
use regex::Regex;
use rlp::{DecoderError, Encodable, RlpStream};
use rpc::v1::types::Bytes as BytesJson;
use secp256k1::PublicKey;
Expand Down Expand Up @@ -6843,6 +6844,17 @@ pub enum EthGasDetailsErr {
threshold
)]
AmountTooLow { amount: BigDecimal, threshold: BigDecimal },
#[display(
fmt = "Provided gas fee cap {} Gwei is too low, the required network base fee is {} Gwei.",
provided_fee_cap,
required_base_fee
)]
GasFeeCapTooLow {
provided_fee_cap: BigDecimal,
required_base_fee: BigDecimal,
},
#[display(fmt = "The provided 'max_fee_per_gas' is below the current block's base fee.")]
GasFeeCapBelowBaseFee,
#[from_stringify("NumConversError")]
#[display(fmt = "Internal error: {}", _0)]
Internal(String),
Expand All @@ -6869,6 +6881,19 @@ impl From<Web3RpcError> for EthGasDetailsErr {
}
}

fn parse_fee_cap_error(message: &str) -> Option<(U256, U256)> {
let re = Regex::new(r"gasfeecap: (\d+)\s+basefee: (\d+)").ok()?;
let caps = re.captures(message)?;

let user_cap_str = caps.get(1)?.as_str();
let required_base_str = caps.get(2)?.as_str();

let user_cap = U256::from_dec_str(user_cap_str).ok()?;
let required_base = U256::from_dec_str(required_base_str).ok()?;

Some((user_cap, required_base))
}

async fn get_eth_gas_details_from_withdraw_fee(
eth_coin: &EthCoin,
fee: Option<WithdrawFee>,
Expand Down Expand Up @@ -6960,6 +6985,20 @@ async fn get_eth_gas_details_from_withdraw_fee(
let amount = u256_to_big_decimal(eth_value, eth_coin.decimals).map_mm_err()?;

return MmError::err(EthGasDetailsErr::AmountTooLow { amount, threshold });
} else if error_str.contains("fee cap less than block base fee")
|| error_str.contains("max fee per gas less than block base fee")
{
if let Some((user_cap, required_base)) = parse_fee_cap_error(&error_str) {
// The RPC error gives fee values in wei. Convert to Gwei (9 decimals) for the user.
let provided_fee_cap = u256_to_big_decimal(user_cap, ETH_GWEI_DECIMALS).map_mm_err()?;
let required_base_fee = u256_to_big_decimal(required_base, ETH_GWEI_DECIMALS).map_mm_err()?;
return MmError::err(EthGasDetailsErr::GasFeeCapTooLow {
provided_fee_cap,
required_base_fee,
});
} else {
return MmError::err(EthGasDetailsErr::GasFeeCapBelowBaseFee);
}
}
// This can be a transport error or a non-standard insufficient funds error.
// In the latter case,
Expand Down
25 changes: 25 additions & 0 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3108,6 +3108,12 @@ pub enum WithdrawError {
InvalidAddress(String),
#[display(fmt = "Invalid fee policy: {}", _0)]
InvalidFeePolicy(String),
#[display(fmt = "Invalid fee parameters: {}", reason)]
InvalidFee {
reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
details: Option<Json>,
},
#[display(fmt = "Invalid memo field: {}", _0)]
InvalidMemo(String),
#[display(fmt = "No such coin {}", coin)]
Expand Down Expand Up @@ -3201,6 +3207,7 @@ impl HttpStatusCode for WithdrawError {
| WithdrawError::AmountTooLow { .. }
| WithdrawError::InvalidAddress(_)
| WithdrawError::InvalidFeePolicy(_)
| WithdrawError::InvalidFee { .. }
| WithdrawError::InvalidMemo(_)
| WithdrawError::FromAddressNotFound
| WithdrawError::UnexpectedFromAddress(_)
Expand Down Expand Up @@ -3296,6 +3303,24 @@ impl From<EthGasDetailsErr> for WithdrawError {
match e {
EthGasDetailsErr::InvalidFeePolicy(e) => WithdrawError::InvalidFeePolicy(e),
EthGasDetailsErr::AmountTooLow { amount, threshold } => WithdrawError::AmountTooLow { amount, threshold },
EthGasDetailsErr::GasFeeCapTooLow {
provided_fee_cap,
required_base_fee,
} => {
let reason = "Provided gas fee cap is less than the required network base fee.".to_string();
let details = json!({
"provided_fee_cap_gwei": provided_fee_cap.to_string(),
"required_base_fee_gwei": required_base_fee.to_string()
});
WithdrawError::InvalidFee {
reason,
details: Some(details),
}
},
EthGasDetailsErr::GasFeeCapBelowBaseFee => {
let reason = "The provided 'max fee per gas' is too low for current network conditions.".to_string();
WithdrawError::InvalidFee { reason, details: None }
},
EthGasDetailsErr::Internal(e) => WithdrawError::InternalError(e),
EthGasDetailsErr::Transport(e) => WithdrawError::Transport(e),
EthGasDetailsErr::NftProtocolNotSupported => WithdrawError::NftProtocolNotSupported,
Expand Down
Loading