-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enhancement(utxo): improve trade and withdraw fee calculations #2083
base: dev
Are you sure you want to change the base?
Changes from all commits
2cd22fd
f45b5dc
944fd57
0f8426e
cd019f6
8e14509
0a8f110
f3f56cc
d445554
2081c25
817a479
d26490f
9ec826a
15f6f0f
da566ca
f3a10a8
e4fdfb2
ac97404
0fc8f98
026c5cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,12 +10,13 @@ use crate::utxo::tx_cache::{UtxoVerboseCacheOps, UtxoVerboseCacheShared}; | |
use crate::utxo::utxo_builder::{UtxoCoinBuildError, UtxoCoinBuildResult, UtxoCoinBuilder, UtxoCoinBuilderCommonOps, | ||
UtxoFieldsWithGlobalHDBuilder, UtxoFieldsWithHardwareWalletBuilder, | ||
UtxoFieldsWithIguanaSecretBuilder}; | ||
use crate::utxo::utxo_common::{self, big_decimal_from_sat, check_all_utxo_inputs_signed_by_pub, UtxoTxBuilder}; | ||
use crate::utxo::{qtum, ActualTxFee, AdditionalTxData, AddrFromStrError, BroadcastTxErr, FeePolicy, GenerateTxError, | ||
GetUtxoListOps, HistoryUtxoTx, HistoryUtxoTxMap, MatureUnspentList, RecentlySpentOutPointsGuard, | ||
UnsupportedAddr, UtxoActivationParams, UtxoAddressFormat, UtxoCoinFields, UtxoCommonOps, | ||
UtxoFromLegacyReqErr, UtxoTx, UtxoTxBroadcastOps, UtxoTxGenerationOps, VerboseTransactionFrom, | ||
UTXO_LOCK}; | ||
use crate::utxo::utxo_common::{self, big_decimal_from_sat, check_all_utxo_inputs_signed_by_pub, | ||
PreImageTradeFeeResult, UtxoTxBuilder}; | ||
use crate::utxo::{qtum, AdditionalTxData, AddrFromStrError, BroadcastTxErr, FeePolicy, GenerateTxError, | ||
GetUtxoListOps, HistoryUtxoTx, HistoryUtxoTxMap, HtlcSpendFeeResult, MatureUnspentList, | ||
RecentlySpentOutPointsGuard, UnsupportedAddr, UtxoActivationParams, UtxoAddressFormat, | ||
UtxoCoinFields, UtxoCommonOps, UtxoFromLegacyReqErr, UtxoTx, UtxoTxBroadcastOps, | ||
UtxoTxGenerationOps, VerboseTransactionFrom, UTXO_LOCK}; | ||
use crate::{BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinFutSpawner, ConfirmPaymentInput, | ||
DexFee, Eip1559Ops, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MakerSwapTakerCoin, | ||
MarketCoinOps, MmCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, | ||
|
@@ -492,9 +493,7 @@ impl Qrc20Coin { | |
/// `gas_fee` should be calculated by: gas_limit * gas_price * (count of contract calls), | ||
/// or should be sum of gas fee of all contract calls. | ||
pub async fn get_qrc20_tx_fee(&self, gas_fee: u64) -> Result<u64, String> { | ||
match try_s!(self.get_tx_fee().await) { | ||
ActualTxFee::Dynamic(amount) | ActualTxFee::FixedPerKb(amount) => Ok(amount + gas_fee), | ||
} | ||
Ok(try_s!(self.get_tx_fee_per_kb().await) + gas_fee) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want to add a fee rate (rate per kb) to the gas fee? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assuming that |
||
} | ||
|
||
/// Generate and send a transaction with the specified UTXO outputs. | ||
|
@@ -582,7 +581,7 @@ impl Qrc20Coin { | |
&self, | ||
contract_outputs: Vec<ContractCallOutput>, | ||
stage: &FeeApproxStage, | ||
) -> TradePreimageResult<BigDecimal> { | ||
) -> TradePreimageResult<PreImageTradeFeeResult> { | ||
let decimals = self.as_ref().decimals; | ||
let mut gas_fee = 0; | ||
let mut outputs = Vec::with_capacity(contract_outputs.len()); | ||
|
@@ -595,7 +594,10 @@ impl Qrc20Coin { | |
UtxoCommonOps::preimage_trade_fee_required_to_send_outputs(self, outputs, fee_policy, Some(gas_fee), stage) | ||
.await?; | ||
let gas_fee = big_decimal_from_sat(gas_fee as i64, decimals); | ||
Ok(miner_fee + gas_fee) | ||
Ok(PreImageTradeFeeResult { | ||
tx_size: miner_fee.tx_size, | ||
fee: miner_fee.fee + gas_fee, | ||
}) | ||
} | ||
} | ||
|
||
|
@@ -612,7 +614,7 @@ impl UtxoTxBroadcastOps for Qrc20Coin { | |
#[cfg_attr(test, mockable)] | ||
impl UtxoTxGenerationOps for Qrc20Coin { | ||
/// Get only QTUM transaction fee. | ||
async fn get_tx_fee(&self) -> UtxoRpcResult<ActualTxFee> { utxo_common::get_tx_fee(&self.utxo).await } | ||
async fn get_tx_fee_per_kb(&self) -> UtxoRpcResult<u64> { utxo_common::get_tx_fee_per_kb(&self.utxo).await } | ||
|
||
async fn calc_interest_if_required( | ||
&self, | ||
|
@@ -653,7 +655,7 @@ impl GetUtxoListOps for Qrc20Coin { | |
#[async_trait] | ||
#[cfg_attr(test, mockable)] | ||
impl UtxoCommonOps for Qrc20Coin { | ||
async fn get_htlc_spend_fee(&self, tx_size: u64, stage: &FeeApproxStage) -> UtxoRpcResult<u64> { | ||
async fn get_htlc_spend_fee(&self, tx_size: u64, stage: &FeeApproxStage) -> UtxoRpcResult<HtlcSpendFeeResult> { | ||
utxo_common::get_htlc_spend_fee(self, tx_size, stage).await | ||
} | ||
|
||
|
@@ -718,7 +720,7 @@ impl UtxoCommonOps for Qrc20Coin { | |
fee_policy: FeePolicy, | ||
gas_fee: Option<u64>, | ||
stage: &FeeApproxStage, | ||
) -> TradePreimageResult<BigDecimal> { | ||
) -> TradePreimageResult<PreImageTradeFeeResult> { | ||
utxo_common::preimage_trade_fee_required_to_send_outputs( | ||
self, | ||
self.platform_ticker(), | ||
|
@@ -1352,6 +1354,7 @@ impl MmCoin for Qrc20Coin { | |
coin: selfi.platform.clone(), | ||
amount: big_decimal_from_sat(fee as i64, selfi.utxo.decimals).into(), | ||
paid_from_trading_vol: false, | ||
tx_size: 0, | ||
}) | ||
}; | ||
Box::new(fut.boxed().compat()) | ||
|
@@ -1400,15 +1403,19 @@ impl MmCoin for Qrc20Coin { | |
self.preimage_trade_fee_required_to_send_outputs(vec![sender_refund_output], &stage) | ||
.await? | ||
} else { | ||
BigDecimal::from(0) // No refund fee if not included. | ||
// No refund fee if not included. | ||
PreImageTradeFeeResult { | ||
fee: 0.into(), | ||
tx_size: 0, | ||
} | ||
}; | ||
|
||
let total_fee = erc20_payment_fee + sender_refund_fee; | ||
borngraced marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let qrc20_payment_fee = erc20_payment_fee.fee + sender_refund_fee.fee; | ||
Ok(TradeFee { | ||
coin: self.platform.clone(), | ||
amount: total_fee.into(), | ||
amount: qrc20_payment_fee.into(), | ||
paid_from_trading_vol: false, | ||
tx_size: sender_refund_fee.tx_size, | ||
}) | ||
} | ||
|
||
|
@@ -1429,10 +1436,12 @@ impl MmCoin for Qrc20Coin { | |
let total_fee = selfi | ||
.preimage_trade_fee_required_to_send_outputs(vec![output], &stage) | ||
.await?; | ||
|
||
Ok(TradeFee { | ||
coin: selfi.platform.clone(), | ||
amount: total_fee.into(), | ||
amount: total_fee.fee.into(), | ||
paid_from_trading_vol: false, | ||
tx_size: total_fee.tx_size, | ||
}) | ||
}; | ||
Box::new(fut.boxed().compat()) | ||
|
@@ -1456,8 +1465,9 @@ impl MmCoin for Qrc20Coin { | |
|
||
Ok(TradeFee { | ||
coin: self.platform.clone(), | ||
amount: total_fee.into(), | ||
amount: total_fee.fee.into(), | ||
paid_from_trading_vol: false, | ||
tx_size: total_fee.tx_size, | ||
}) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is how I envision the GUI implementation of this part.
We present the user with the three levels of fees and let them make a choice. The GUI would potentially make three separate withdrawal requests, each using a different priority level. This would generate three different raw transaction hexes, each associated with a different fee and expected confirmation time.
Once the user selects the fee they prefer, the corresponding transaction hex would be used.
What are your thoughts on this approach? Would it be feasible to make some changes that simplifies the process for the GUI to handle this with a single request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, here's mine view.
The api receives a priority withdrawal request from the gui, the api generates fee for the available priorities(currently 3) and send the response (each fee with it's tx hex) and finally, gui can render this three options for user to pick a choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how I see it as well, but it might be too complicated as we would probably need to return 3
TransactionDetails
objects in the response which is different from the current withdraw response.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI for eth I also added priority levels for tx fees:
For withdrawals user can add a new WithdrawFee option and set explicit fee per gas.
For swaps there is an rpc to set the desired level of low/medium/priority for the whole swap (so the API will by itself query the current fee value before each swap step).
There is also an rpc for GUI to query fees for all supported 3 levels (to show fe values to the user so he could select desired level). Initially user should start a loop in the API which periodically calculates priority fees, so the query rpc just immediately returns the recent estimated fee values.
Maybe we could do this similar both for utxo and eth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Some explanation why a there is loop in API to obtain fees. This is how other eth wallet apps do it: API does fee estimations getting data from the eth provider. The GUI subscribes to the fee updates from API so it can in realtime notify the user about changes)