diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 7934bdf485..90667f639a 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -47,8 +47,8 @@ use crate::rpc_command::init_withdraw::{InitWithdrawCoin, WithdrawTaskHandleShar use crate::rpc_command::{account_balance, get_new_address, init_account_balance, init_create_account, init_scan_for_new_addresses}; use crate::{coin_balance, scan_for_new_addresses_impl, BalanceResult, CoinWithDerivationMethod, DerivationMethod, - DexFee, Eip1559Ops, MakerNftSwapOpsV2, ParseCoinAssocTypes, ParseNftAssocTypes, PayForGasParams, - PrivKeyPolicy, RpcCommonOps, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, ToBytes, + DexFee, MakerNftSwapOpsV2, ParseCoinAssocTypes, ParseNftAssocTypes, PayForGasParams, PrivKeyPolicy, + RpcCommonOps, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, SwapPriorityFeeOps, ToBytes, ValidateNftMakerPaymentArgs, ValidateWatcherSpendInput, WatcherSpendType}; use async_trait::async_trait; use bitcrypto::{dhash160, keccak256, ripemd160, sha256}; @@ -7238,7 +7238,7 @@ fn extract_gas_limit_from_conf(coin_conf: &Json) -> Result SwapTxFeePolicy { self.swap_txfee_policy.lock().unwrap().clone() } fn set_swap_transaction_fee_policy(&self, swap_txfee_policy: SwapTxFeePolicy) { diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 5e40eb9221..992639e711 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -245,8 +245,8 @@ use rpc_command::{get_new_address::{GetNewAddressTaskManager, GetNewAddressTaskM pub mod tendermint; use tendermint::htlc::CustomTendermintMsgType; -use tendermint::{CosmosTransaction, TendermintCoin, TendermintFeeDetails, TendermintProtocolInfo, TendermintToken, - TendermintTokenProtocolInfo}; +use tendermint::{CosmosTransaction, TendermintCoin, TendermintFeeDetails, TendermintPriorityFeeOption, + TendermintProtocolInfo, TendermintToken, TendermintTokenProtocolInfo}; #[doc(hidden)] #[allow(unused_variables)] @@ -2091,6 +2091,10 @@ pub enum WithdrawFee { gas_limit: u64, gas_price: f64, }, + CosmosGasPriority { + gas_limit: u64, + gas_price_option: TendermintPriorityFeeOption, + }, } /// Rename to `GetWithdrawSenderAddresses` when withdraw supports multiple `from` addresses. @@ -2492,10 +2496,12 @@ pub enum TradePreimageValue { UpperBound(BigDecimal), } -#[derive(Clone, Debug, Serialize, Deserialize, Default)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)] pub enum SwapTxFeePolicy { + /// Different tx fee policies not supported (some default gas price getting is used) #[default] Unsupported, + /// Tx fee policy defined internally, by default Internal, Low, Medium, @@ -2514,7 +2520,7 @@ pub struct SwapTxFeePolicyRequest { pub enum SwapTxFeePolicyError { #[from_stringify("CoinFindError")] NoSuchCoin(String), - #[display(fmt = "eip-1559 policy is not supported for coin {}", _0)] + #[display(fmt = "tx fee policy is not supported for coin {}", _0)] NotSupported(String), } @@ -5498,8 +5504,9 @@ fn coins_conf_check(ctx: &MmArc, coins_en: &Json, ticker: &str, req: Option<&Jso Ok(()) } +/// Operations for transaction priority fee policy used in swaps #[async_trait] -pub trait Eip1559Ops { +pub trait SwapPriorityFeeOps { /// Return swap transaction fee policy fn get_swap_transaction_fee_policy(&self) -> SwapTxFeePolicy; @@ -5507,12 +5514,13 @@ pub trait Eip1559Ops { fn set_swap_transaction_fee_policy(&self, swap_txfee_policy: SwapTxFeePolicy); } -/// Get eip 1559 transaction fee per gas policy (low, medium, high) set for the coin +/// Get priority transaction fee policy (low, medium, high) set for the coin pub async fn get_swap_transaction_fee_policy(ctx: MmArc, req: SwapTxFeePolicyRequest) -> SwapTxFeePolicyResult { let coin = lp_coinfind_or_err(&ctx, &req.coin).await?; match coin { MmCoinEnum::EthCoin(eth_coin) => Ok(eth_coin.get_swap_transaction_fee_policy()), MmCoinEnum::Qrc20Coin(qrc20_coin) => Ok(qrc20_coin.get_swap_transaction_fee_policy()), + MmCoinEnum::Tendermint(tendermint_coin) => Ok(tendermint_coin.get_swap_transaction_fee_policy()), _ => MmError::err(SwapTxFeePolicyError::NotSupported(req.coin)), } } @@ -5529,6 +5537,10 @@ pub async fn set_swap_transaction_fee_policy(ctx: MmArc, req: SwapTxFeePolicyReq qrc20_coin.set_swap_transaction_fee_policy(req.swap_tx_fee_policy); Ok(qrc20_coin.get_swap_transaction_fee_policy()) }, + MmCoinEnum::Tendermint(tendermint_coin) => { + tendermint_coin.set_swap_transaction_fee_policy(req.swap_tx_fee_policy); + Ok(tendermint_coin.get_swap_transaction_fee_policy()) + }, _ => MmError::err(SwapTxFeePolicyError::NotSupported(req.coin)), } } diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index df14fea09a..e1ec2ad885 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -17,13 +17,13 @@ use crate::utxo::{qtum, ActualTxFee, AdditionalTxData, AddrFromStrError, Broadca UtxoFromLegacyReqErr, UtxoTx, UtxoTxBroadcastOps, UtxoTxGenerationOps, VerboseTransactionFrom, UTXO_LOCK}; use crate::{BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinFutSpawner, ConfirmPaymentInput, - DexFee, Eip1559Ops, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MakerSwapTakerCoin, + DexFee, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MakerSwapTakerCoin, MarketCoinOps, MmCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionRequest, RawTransactionResult, RefundError, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, - SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, - TakerSwapMakerCoin, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, + SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, SwapOps, SwapPriorityFeeOps, + SwapTxFeePolicy, TakerSwapMakerCoin, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionData, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TransactionResult, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, ValidateOtherPubKeyErr, ValidatePaymentFut, @@ -1655,7 +1655,7 @@ fn transfer_event_from_log(log: &LogEntry) -> Result SwapTxFeePolicy { SwapTxFeePolicy::Unsupported } fn set_swap_transaction_fee_policy(&self, _swap_txfee_policy: SwapTxFeePolicy) {} diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 323637599d..3820f0d8b9 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -20,14 +20,15 @@ use crate::{big_decimal_from_sat_unsigned, BalanceError, BalanceFut, BigDecimal, PrivKeyPolicyNotAllowed, RawTransactionError, RawTransactionFut, RawTransactionRequest, RawTransactionRes, RawTransactionResult, RefundError, RefundPaymentArgs, RefundResult, RpcCommonOps, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignRawTransactionRequest, - SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, TakerSwapMakerCoin, ToBytes, TradeFee, - TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionData, - TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TransactionResult, TransactionType, - TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, - ValidateInstructionsErr, ValidateOtherPubKeyErr, ValidatePaymentFut, ValidatePaymentInput, - ValidateWatcherSpendInput, VerificationError, VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, - WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, - WatcherValidateTakerFeeInput, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest}; + SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, SwapPriorityFeeOps, SwapTxFeePolicy, + TakerSwapMakerCoin, ToBytes, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, + TradePreimageValue, TransactionData, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, + TransactionResult, TransactionType, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, + ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, ValidateOtherPubKeyErr, + ValidatePaymentFut, ValidatePaymentInput, ValidateWatcherSpendInput, VerificationError, + VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, WatcherReward, WatcherRewardError, + WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, + WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest}; use async_std::prelude::FutureExt as AsyncStdFutureExt; use async_trait::async_trait; use bip32::DerivationPath; @@ -92,6 +93,8 @@ const ABCI_GET_TXS_EVENT_PATH: &str = "/cosmos.tx.v1beta1.Service/GetTxsEvent"; pub(crate) const MIN_TX_SATOSHIS: i64 = 1; +pub(crate) const PRIORITY_FEE_LEVELS: usize = 3; + // ABCI Request Defaults const ABCI_REQUEST_HEIGHT: Option = None; const ABCI_REQUEST_PROVE: bool = false; @@ -101,6 +104,8 @@ const DEFAULT_GAS_PRICE: f64 = 0.25; pub(super) const TIMEOUT_HEIGHT_DELTA: u64 = 100; pub const GAS_LIMIT_DEFAULT: u64 = 125_000; pub const GAS_WANTED_BASE_VALUE: f64 = 50_000.; +/// Multiplier to increment simulated gas limit +pub(crate) const GAS_USED_MULTIPLIER: f64 = 1.5; pub(crate) const TX_DEFAULT_MEMO: &str = ""; // https://github.com/irisnet/irismod/blob/5016c1be6fdbcffc319943f33713f4a057622f0a/modules/htlc/types/validation.go#L19-L22 @@ -180,9 +185,47 @@ pub struct TendermintProtocolInfo { pub account_prefix: String, chain_id: String, gas_price: Option, + priority_gas_prices: Option<[f64; PRIORITY_FEE_LEVELS]>, chain_registry_name: Option, } +#[derive(Clone, Debug, Deserialize, PartialEq)] +pub enum TendermintPriorityFeeOption { + Low = 0, + Average = 1, + High = 2, + Default = -1, +} + +impl From for TendermintPriorityFeeOption { + fn from(swap_fee_policy: SwapTxFeePolicy) -> Self { + match swap_fee_policy { + SwapTxFeePolicy::Unsupported => Self::Default, + SwapTxFeePolicy::Internal => Self::Default, + SwapTxFeePolicy::Low => Self::Low, + SwapTxFeePolicy::Medium => Self::Average, + SwapTxFeePolicy::High => Self::High, + } + } +} + +/// Tx fee params for calculate_fee fn +#[derive(Clone, Debug, Deserialize, PartialEq)] +pub(crate) enum CalculateFeeParams { + /// Fee params for withdraw + WithdrawFee(Option), + /// Priority fee policy for swaps + SwapTxFeePolicy(SwapTxFeePolicy), +} + +impl From> for CalculateFeeParams { + fn from(opt_withdraw_fee: Option) -> Self { Self::WithdrawFee(opt_withdraw_fee) } +} + +impl From for CalculateFeeParams { + fn from(swap_fee_policy: SwapTxFeePolicy) -> Self { Self::SwapTxFeePolicy(swap_fee_policy) } +} + #[derive(Clone)] pub struct ActivatedTokenInfo { pub(crate) decimals: u8, @@ -366,6 +409,8 @@ pub struct TendermintCoinImpl { pub(super) denom: Denom, chain_id: ChainId, gas_price: Option, + priority_gas_prices: Option<[f64; PRIORITY_FEE_LEVELS]>, + swap_txfee_policy: Mutex, pub tokens_info: PaMutex>, /// This spawner is used to spawn coin's related futures that should be aborted on coin deactivation /// or on [`MmArc::stop`]. @@ -695,6 +740,8 @@ impl TendermintCoin { denom, chain_id, gas_price: protocol_info.gas_price, + priority_gas_prices: protocol_info.priority_gas_prices, + swap_txfee_policy: Mutex::new(SwapTxFeePolicy::Internal), avg_blocktime: conf.avg_blocktime, tokens_info: PaMutex::new(HashMap::new()), abortable_system, @@ -736,6 +783,15 @@ impl TendermintCoin { #[inline(always)] fn gas_price(&self) -> f64 { self.gas_price.unwrap_or(DEFAULT_GAS_PRICE) } + /// Return gas price for priority level, which was set in the coins file, + /// or default gas price + fn priority_gas_price(&self, priority_fee_option: TendermintPriorityFeeOption) -> f64 { + let default_gas_price = self.gas_price.unwrap_or(DEFAULT_GAS_PRICE); + self.priority_gas_prices + .map(|prices| *prices.get(priority_fee_option as usize).unwrap_or(&default_gas_price)) + .unwrap_or(default_gas_price) + } + #[allow(unused)] async fn get_latest_block(&self) -> MmResult { let request = GetLatestBlockRequest {}; @@ -936,11 +992,11 @@ impl TendermintCoin { msg: Any, timeout_height: u64, memo: String, - withdraw_fee: Option, + fee_params: CalculateFeeParams, ) -> MmResult { let Ok(activated_priv_key) = self.activation_policy.activated_key_or_err() else { - let (gas_price, gas_limit) = self.gas_info_for_withdraw(&withdraw_fee, GAS_LIMIT_DEFAULT); - let amount = ((GAS_WANTED_BASE_VALUE * 1.5) * gas_price).ceil(); + let (gas_price, gas_limit) = self.gas_price_and_limit(fee_params, GAS_LIMIT_DEFAULT); + let amount = ((GAS_WANTED_BASE_VALUE * GAS_USED_MULTIPLIER) * gas_price).ceil(); let fee_amount = Coin { denom: self.platform_denom().clone(), @@ -1001,10 +1057,9 @@ impl TendermintCoin { )) })?; - let (gas_price, gas_limit) = self.gas_info_for_withdraw(&withdraw_fee, GAS_LIMIT_DEFAULT); - - let amount = ((gas.gas_used as f64 * 1.5) * gas_price).ceil(); + let (gas_price, gas_limit) = self.gas_price_and_limit(fee_params, GAS_LIMIT_DEFAULT); + let amount = ((gas.gas_used as f64 * GAS_USED_MULTIPLIER) * gas_price).ceil(); let fee_amount = Coin { denom: self.platform_denom().clone(), amount: (amount as u64).into(), @@ -1021,11 +1076,11 @@ impl TendermintCoin { msg: Any, timeout_height: u64, memo: String, - withdraw_fee: Option, + fee_params: CalculateFeeParams, ) -> MmResult { let Some(priv_key) = priv_key else { - let (gas_price, _) = self.gas_info_for_withdraw(&withdraw_fee, 0); - return Ok(((GAS_WANTED_BASE_VALUE * 1.5) * gas_price).ceil() as u64); + let (gas_price, _) = self.gas_price_and_limit(fee_params, 0); + return Ok(((GAS_WANTED_BASE_VALUE * GAS_USED_MULTIPLIER) * gas_price).ceil() as u64); }; let mut account_info = self.account_info(account_id).await?; @@ -1073,9 +1128,8 @@ impl TendermintCoin { )) })?; - let (gas_price, _) = self.gas_info_for_withdraw(&withdraw_fee, 0); - - Ok(((gas.gas_used as f64 * 1.5) * gas_price).ceil() as u64) + let (gas_price, _) = self.gas_price_and_limit(fee_params, 0); + Ok(((gas.gas_used as f64 * GAS_USED_MULTIPLIER) * gas_price).ceil() as u64) } pub(super) async fn account_info(&self, account_id: &AccountId) -> MmResult { @@ -1516,7 +1570,7 @@ impl TendermintCoin { create_htlc_tx.msg_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned(), - None + coin.get_swap_transaction_fee_policy().into() ) .await ); @@ -1572,8 +1626,13 @@ impl TendermintCoin { let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; let fee = try_tx_s!( - coin.calculate_fee(tx_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned(), None) - .await + coin.calculate_fee( + tx_payload.clone(), + timeout_height, + TX_DEFAULT_MEMO.to_owned(), + coin.get_swap_transaction_fee_policy().into() + ) + .await ); let timeout = expires_at.checked_sub(now_sec()).unwrap_or_default(); @@ -1823,7 +1882,7 @@ impl TendermintCoin { create_htlc_tx.msg_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned(), - None, + self.get_swap_transaction_fee_policy().into(), ) .await?; @@ -1874,7 +1933,7 @@ impl TendermintCoin { msg_send, timeout_height, TX_DEFAULT_MEMO.to_owned(), - None, + self.get_swap_transaction_fee_policy().into(), ) .await?; let fee_amount = big_decimal_from_sat_unsigned(fee_uamount, decimals); @@ -2056,13 +2115,18 @@ impl TendermintCoin { } } - pub(crate) fn gas_info_for_withdraw( - &self, - withdraw_fee: &Option, - fallback_gas_limit: u64, - ) -> (f64, u64) { - match withdraw_fee { - Some(WithdrawFee::CosmosGas { gas_price, gas_limit }) => (*gas_price, *gas_limit), + pub(crate) fn gas_price_and_limit(&self, fee_params: CalculateFeeParams, fallback_gas_limit: u64) -> (f64, u64) { + match fee_params { + CalculateFeeParams::WithdrawFee(Some(WithdrawFee::CosmosGas { gas_price, gas_limit })) => { + (gas_price, gas_limit) + }, + CalculateFeeParams::WithdrawFee(Some(WithdrawFee::CosmosGasPriority { + gas_price_option, + gas_limit, + })) => (self.priority_gas_price(gas_price_option), gas_limit), + CalculateFeeParams::SwapTxFeePolicy(swap_fee_policy) => { + (self.priority_gas_price(swap_fee_policy.into()), fallback_gas_limit) + }, _ => (self.gas_price(), fallback_gas_limit), } } @@ -2236,9 +2300,9 @@ impl MmCoin for TendermintCoin { let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; let (_, gas_limit) = if is_ibc_transfer { - coin.gas_info_for_withdraw(&req.fee, IBC_GAS_LIMIT_DEFAULT) + coin.gas_price_and_limit(req.fee.clone().into(), IBC_GAS_LIMIT_DEFAULT) } else { - coin.gas_info_for_withdraw(&req.fee, GAS_LIMIT_DEFAULT) + coin.gas_price_and_limit(req.fee.clone().into(), GAS_LIMIT_DEFAULT) }; let fee_amount_u64 = coin @@ -2248,7 +2312,7 @@ impl MmCoin for TendermintCoin { msg_payload.clone(), timeout_height, memo.clone(), - req.fee, + req.fee.into(), ) .await?; @@ -2768,7 +2832,7 @@ impl SwapOps for TendermintCoin { claim_htlc_tx.msg_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned(), - None + self.get_swap_transaction_fee_policy().into() ) .await ); @@ -2829,7 +2893,7 @@ impl SwapOps for TendermintCoin { claim_htlc_tx.msg_payload.clone(), timeout_height, TX_DEFAULT_MEMO.into(), - None + self.get_swap_transaction_fee_policy().into() ) .await ); @@ -3196,6 +3260,14 @@ pub(crate) fn chain_registry_name_from_account_prefix(ctx: &MmArc, prefix: &str) None } +impl SwapPriorityFeeOps for TendermintCoin { + fn get_swap_transaction_fee_policy(&self) -> SwapTxFeePolicy { self.swap_txfee_policy.lock().unwrap().clone() } + + fn set_swap_transaction_fee_policy(&self, swap_txfee_policy: SwapTxFeePolicy) { + *self.swap_txfee_policy.lock().unwrap() = swap_txfee_policy + } +} + pub(crate) async fn create_withdraw_msg_as_any( sender: AccountId, receiver: AccountId, @@ -3324,6 +3396,7 @@ pub mod tendermint_coin_tests { use common::{block_on, wait_until_ms, DEX_FEE_ADDR_RAW_PUBKEY}; use cosmrs::proto::cosmos::tx::v1beta1::{GetTxRequest, GetTxResponse, GetTxsEventResponse}; use crypto::privkey::key_pair_from_seed; + use num_traits::FromPrimitive; use std::mem::discriminant; pub const IRIS_TESTNET_HTLC_PAIR1_SEED: &str = "iris test seed"; @@ -3370,6 +3443,7 @@ pub mod tendermint_coin_tests { account_prefix: String::from("iaa"), chain_id: String::from("nyancat-9"), gas_price: None, + priority_gas_prices: None, chain_registry_name: None, } } @@ -3381,6 +3455,7 @@ pub mod tendermint_coin_tests { account_prefix: String::from("iaa"), chain_id: String::from("nyancat-9"), gas_price: None, + priority_gas_prices: Some([0.1, 0.2, 0.3]), chain_registry_name: None, } } @@ -3455,7 +3530,7 @@ pub mod tendermint_coin_tests { create_htlc_tx.msg_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned(), - None, + coin.get_swap_transaction_fee_policy().into(), ) .await .unwrap() @@ -3498,7 +3573,7 @@ pub mod tendermint_coin_tests { claim_htlc_tx.msg_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned(), - None, + coin.get_swap_transaction_fee_policy().into(), ) .await .unwrap() @@ -4225,4 +4300,44 @@ pub mod tendermint_coin_tests { assert!(parse_expected_sequence_number("").is_err()); assert!(parse_expected_sequence_number("check_tx log: account sequence mismatch, expected").is_err()); } + + /// Test getting priority fee for swaps + #[test] + fn test_swap_priority_fee_policy() { + const PRIORITY_FEE_HIGH: f64 = 0.3; + let nodes = vec![RpcNode::for_test(IRIS_TESTNET_RPC_URL)]; + + let protocol_conf = get_iris_protocol(); + + let ctx = mm2_core::mm_ctx::MmCtxBuilder::default().into_mm_arc(); + + let conf = TendermintConf { + avg_blocktime: AVG_BLOCKTIME, + derivation_path: None, + }; + + let key_pair = key_pair_from_seed(IRIS_TESTNET_HTLC_PAIR1_SEED).unwrap(); + let tendermint_pair = TendermintKeyPair::new(key_pair.private().secret, *key_pair.public()); + let activation_policy = + TendermintActivationPolicy::with_private_key_policy(TendermintPrivKeyPolicy::Iguana(tendermint_pair)); + + let coin = block_on(TendermintCoin::init( + &ctx, + "IRIS-TEST".to_string(), + conf, + protocol_conf, + nodes, + false, + activation_policy, + false, + )) + .unwrap(); + + coin.set_swap_transaction_fee_policy(SwapTxFeePolicy::High); + let (gas_price, _) = coin.gas_price_and_limit( + CalculateFeeParams::SwapTxFeePolicy(coin.get_swap_transaction_fee_policy()), + 0_u64, + ); + assert_eq!(BigDecimal::from_f64(gas_price), BigDecimal::from_f64(PRIORITY_FEE_HIGH)); + } } diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index e5cc90f895..94769c15a3 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -584,9 +584,9 @@ impl MmCoin for TendermintToken { let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; let (_, gas_limit) = if is_ibc_transfer { - platform.gas_info_for_withdraw(&req.fee, IBC_GAS_LIMIT_DEFAULT) + platform.gas_price_and_limit(req.fee.clone().into(), IBC_GAS_LIMIT_DEFAULT) } else { - platform.gas_info_for_withdraw(&req.fee, GAS_LIMIT_DEFAULT) + platform.gas_price_and_limit(req.fee.clone().into(), GAS_LIMIT_DEFAULT) }; let fee_amount_u64 = platform @@ -596,7 +596,7 @@ impl MmCoin for TendermintToken { msg_payload.clone(), timeout_height, memo.clone(), - req.fee, + req.fee.into(), ) .await?; diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 7ea038a8f7..52e4c27d1b 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -13,18 +13,18 @@ use coins::eth::v2_activation::{eth_coin_from_conf_and_request_v2, EthActivation use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, EthCoinType, EthPrivKeyBuildPolicy, SignedEthTx, SwapV2Contracts, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; -use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CommonSwapOpsV2, ConfirmPaymentInput, - DerivationMethod, Eip1559Ops, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, NftSwapInfo, - ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundNftMakerPaymentArgs, RefundPaymentArgs, - SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, SendPaymentArgs, SpendNftMakerPaymentArgs, - SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, ToBytes, Transaction, - ValidateNftMakerPaymentArgs}; #[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] -use coins::{CoinsContext, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, +use coins::{lp_coinfind, CoinsContext, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoinEnum, MmCoinStruct, RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundTakerPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, SpendMakerPaymentArgs, TakerCoinSwapOpsV2, TxPreimageWithSig, ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; +use coins::{CoinProtocol, CoinWithDerivationMethod, CommonSwapOpsV2, ConfirmPaymentInput, DerivationMethod, + FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, NftSwapInfo, ParseCoinAssocTypes, ParseNftAssocTypes, + PrivKeyBuildPolicy, RefundNftMakerPaymentArgs, RefundPaymentArgs, SearchForSwapTxSpendInput, + SendNftMakerPaymentArgs, SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, + SwapPriorityFeeOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, ToBytes, Transaction, + ValidateNftMakerPaymentArgs}; use common::{block_on, block_on_f01, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; @@ -55,6 +55,7 @@ const SEPOLIA_MAKER_PRIV: &str = "6e2f3a6223b928a05a3a3622b0c3f3573d03663b704a61 const SEPOLIA_TAKER_PRIV: &str = "e0be82dca60ff7e4c6d6db339ac9e1ae249af081dba2110bddd281e711608f16"; const NFT_ETH: &str = "NFT_ETH"; const ETH: &str = "ETH"; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] const ERC20: &str = "ERC20DEV"; /// # Safety diff --git a/mm2src/mm2_main/tests/docker_tests/tendermint_tests.rs b/mm2src/mm2_main/tests/docker_tests/tendermint_tests.rs index 9fe3858736..860beea703 100644 --- a/mm2src/mm2_main/tests/docker_tests/tendermint_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/tendermint_tests.rs @@ -1,3 +1,4 @@ +use coins::utxo::utxo_common::big_decimal_from_sat; use common::{block_on, log}; use mm2_number::BigDecimal; use mm2_rpc::data::legacy::OrderbookResponse; @@ -11,6 +12,7 @@ use mm2_test_helpers::structs::{Bip44Chain, HDAccountAddressId, OrderbookAddress use serde_json::json; use std::collections::HashSet; use std::iter::FromIterator; +use std::str::FromStr; const TENDERMINT_TEST_SEED: &str = "tendermint test seed"; const TENDERMINT_CONSTANT_BALANCE_SEED: &str = "tendermint constant balance seed"; @@ -651,6 +653,45 @@ fn test_passive_coin_and_force_disable() { block_on(disable_coin_err(&mm, token, false)); } +#[test] +fn test_priority_gas_on_tendermint_withdraw() { + const GAS_PRICE_HIGH: f64 = 0.3; + const GAS_USED: u64 = 55470; + const GAS_USED_MULTIPLIER: f64 = 1.5; + let coins = json!([atom_testnet_conf()]); + let coin = coins[0]["coin"].as_str().unwrap(); + + let conf = Mm2TestConf::seednode(TENDERMINT_TEST_SEED, &coins); + let mm = MarketMakerIt::start(conf.conf, conf.rpc_password, None).unwrap(); + + let activation_res = block_on(enable_tendermint(&mm, coin, &[], ATOM_TENDERMINT_RPC_URLS, false)); + log!("Activation {}", serde_json::to_string(&activation_res).unwrap()); + + let request = block_on(mm.rpc(&json!({ + "userpass": mm.userpass, + "method": "withdraw", + "coin": coin, + "to": "cosmos1w5h6wud7a8zpa539rc99ehgl9gwkad3wjsjq8v", + "amount": "0.1", + "fee": { + "type": "CosmosGasPriority", + "gas_limit": 150000, + "gas_price_option": "High" + } + }))) + .unwrap(); + assert_eq!(request.0, common::StatusCode::OK, "'withdraw' failed: {}", request.1); + let tx_details: TransactionDetails = serde_json::from_str(&request.1).unwrap(); + let expected = big_decimal_from_sat( + (GAS_PRICE_HIGH * GAS_USED as f64 * GAS_USED_MULTIPLIER).ceil() as i64, + 6, + ); + assert_eq!( + BigDecimal::from_str(tx_details.fee_details["amount"].as_str().unwrap()).unwrap(), + expected + ); +} + mod swap { use super::*; diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 115f120574..b19160e1fe 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -614,6 +614,7 @@ pub fn atom_testnet_conf() -> Json { "denom": "uatom", "account_prefix": "cosmos", "chain_id": "cosmoshub-testnet", + "priority_gas_prices": [0.1, 0.2, 0.3] }, }, "derivation_path": "m/44'/118'",