Skip to content
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

fix(fee): remove fixed 0.0001 min threshold for TakerFee #1971

Merged
merged 8 commits into from
Oct 3, 2023
6 changes: 4 additions & 2 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2131,11 +2131,13 @@ impl MarketCoinOps for EthCoin {
}
}

#[inline]
fn min_tx_amount(&self) -> BigDecimal { BigDecimal::from(0) }

#[inline]
fn min_trading_vol(&self) -> MmNumber {
let pow = self.decimals / 3;
MmNumber::from(1) / MmNumber::from(10u64.pow(pow as u32))
let pow = self.decimals as u32;
MmNumber::from(1) / MmNumber::from(10u64.pow(pow))
}
}

Expand Down
6 changes: 4 additions & 2 deletions mm2src/coins/qrc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,11 +1270,13 @@ impl MarketCoinOps for Qrc20Coin {

fn display_priv_key(&self) -> Result<String, String> { utxo_common::display_priv_key(&self.utxo) }

#[inline]
fn min_tx_amount(&self) -> BigDecimal { BigDecimal::from(0) }

#[inline]
fn min_trading_vol(&self) -> MmNumber {
let pow = self.utxo.decimals / 3;
MmNumber::from(1) / MmNumber::from(10u64.pow(pow as u32))
let pow = self.utxo.decimals as u32;
MmNumber::from(1) / MmNumber::from(10u64.pow(pow))
}
}

Expand Down
4 changes: 3 additions & 1 deletion mm2src/coins/tendermint/tendermint_coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2394,9 +2394,11 @@ impl MarketCoinOps for TendermintCoin {
.to_string())
}

#[inline]
fn min_tx_amount(&self) -> BigDecimal { big_decimal_from_sat(MIN_TX_SATOSHIS, self.decimals) }

fn min_trading_vol(&self) -> MmNumber { MmNumber::from("0.00777") }
#[inline]
fn min_trading_vol(&self) -> MmNumber { self.min_tx_amount().into() }
}

#[async_trait]
Expand Down
5 changes: 3 additions & 2 deletions mm2src/coins/tendermint/tendermint_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,10 +594,11 @@ impl MarketCoinOps for TendermintToken {

fn display_priv_key(&self) -> Result<String, String> { self.platform_coin.display_priv_key() }

#[inline]
fn min_tx_amount(&self) -> BigDecimal { big_decimal_from_sat(MIN_TX_SATOSHIS, self.decimals) }

/// !! This function includes dummy implementation for P.O.C work
fn min_trading_vol(&self) -> MmNumber { MmNumber::from("0.00777") }
#[inline]
fn min_trading_vol(&self) -> MmNumber { self.min_tx_amount().into() }
}

#[async_trait]
Expand Down
4 changes: 2 additions & 2 deletions mm2src/mm2_main/src/lp_ordermatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1788,9 +1788,9 @@ impl fmt::Display for MakerOrderBuildError {

#[allow(clippy::result_large_err)]
fn validate_price(price: MmNumber) -> Result<(), MakerOrderBuildError> {
let min_price = MmNumber::from(BigRational::new(1.into(), 100_000_000.into()));
let min_price = 0.into();

if price < min_price {
if price <= min_price {
return Err(MakerOrderBuildError::PriceTooLow {
actual: price,
threshold: min_price,
Expand Down
32 changes: 10 additions & 22 deletions mm2src/mm2_main/src/lp_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,17 +669,6 @@ pub fn lp_atomic_locktime(maker_coin: &str, taker_coin: &str, version: AtomicLoc
}
}

pub fn dex_fee_threshold(min_tx_amount: MmNumber) -> MmNumber {
// Todo: This should be reduced for lightning swaps.
// 0.0001
let min_fee = MmNumber::from((1, 10000));
if min_fee < min_tx_amount {
min_tx_amount
} else {
min_fee
}
}

fn dex_fee_rate(base: &str, rel: &str) -> MmNumber {
let fee_discount_tickers: &[&str] = if var("MYCOIN_FEE_DISCOUNT").is_ok() {
&["KMD", "MYCOIN"]
Expand All @@ -694,20 +683,19 @@ fn dex_fee_rate(base: &str, rel: &str) -> MmNumber {
}
}

pub fn dex_fee_amount(base: &str, rel: &str, trade_amount: &MmNumber, dex_fee_threshold: &MmNumber) -> MmNumber {
pub fn dex_fee_amount(base: &str, rel: &str, trade_amount: &MmNumber, min_tx_amount: &MmNumber) -> MmNumber {
let rate = dex_fee_rate(base, rel);
let fee_amount = trade_amount * &rate;
if &fee_amount < dex_fee_threshold {
dex_fee_threshold.clone()
if &fee_amount < min_tx_amount {
min_tx_amount.clone()
} else {
fee_amount
}
}

pub fn dex_fee_amount_from_taker_coin(taker_coin: &MmCoinEnum, maker_coin: &str, trade_amount: &MmNumber) -> MmNumber {
let min_tx_amount = MmNumber::from(taker_coin.min_tx_amount());
let dex_fee_threshold = dex_fee_threshold(min_tx_amount);
dex_fee_amount(taker_coin.ticker(), maker_coin, trade_amount, &dex_fee_threshold)
dex_fee_amount(taker_coin.ticker(), maker_coin, trade_amount, &min_tx_amount)
}

#[derive(Clone, Debug, Eq, Deserialize, PartialEq, Serialize)]
Expand Down Expand Up @@ -1431,34 +1419,34 @@ mod lp_swap_tests {

#[test]
fn test_dex_fee_amount() {
let dex_fee_threshold = MmNumber::from("0.0001");
let min_tx_amount = MmNumber::from("0.0001");

let base = "BTC";
let rel = "ETH";
let amount = 1.into();
let actual_fee = dex_fee_amount(base, rel, &amount, &dex_fee_threshold);
let actual_fee = dex_fee_amount(base, rel, &amount, &min_tx_amount);
let expected_fee = amount / 777u64.into();
assert_eq!(expected_fee, actual_fee);

let base = "KMD";
let rel = "ETH";
let amount = 1.into();
let actual_fee = dex_fee_amount(base, rel, &amount, &dex_fee_threshold);
let actual_fee = dex_fee_amount(base, rel, &amount, &min_tx_amount);
let expected_fee = amount * (9, 7770).into();
assert_eq!(expected_fee, actual_fee);

let base = "BTC";
let rel = "KMD";
let amount = 1.into();
let actual_fee = dex_fee_amount(base, rel, &amount, &dex_fee_threshold);
let actual_fee = dex_fee_amount(base, rel, &amount, &min_tx_amount);
let expected_fee = amount * (9, 7770).into();
assert_eq!(expected_fee, actual_fee);

let base = "BTC";
let rel = "KMD";
let amount: MmNumber = "0.001".parse::<BigDecimal>().unwrap().into();
let actual_fee = dex_fee_amount(base, rel, &amount, &dex_fee_threshold);
assert_eq!(dex_fee_threshold, actual_fee);
let actual_fee = dex_fee_amount(base, rel, &amount, &min_tx_amount);
assert_eq!(min_tx_amount, actual_fee);
}

#[test]
Expand Down
71 changes: 34 additions & 37 deletions mm2src/mm2_main/src/lp_swap/taker_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use super::swap_lock::{SwapLock, SwapLockOps};
use super::swap_watcher::{watcher_topic, SwapWatcherMsg};
use super::trade_preimage::{TradePreimageRequest, TradePreimageRpcError, TradePreimageRpcResult};
use super::{broadcast_my_swap_status, broadcast_swap_message, broadcast_swap_msg_every,
check_other_coin_balance_for_swap, dex_fee_amount_from_taker_coin, dex_fee_rate, dex_fee_threshold,
get_locked_amount, recv_swap_msg, swap_topic, wait_for_maker_payment_conf_until, AtomicSwap, LockedAmount,
MySwapInfo, NegotiationDataMsg, NegotiationDataV2, NegotiationDataV3, RecoveredSwap, RecoveredSwapAction,
SavedSwap, SavedSwapIo, SavedTradeFee, SwapConfirmationsSettings, SwapError, SwapMsg, SwapPubkeys,
SwapTxDataMsg, SwapsContext, TransactionIdentifier, WAIT_CONFIRM_INTERVAL_SEC};
check_other_coin_balance_for_swap, dex_fee_amount_from_taker_coin, dex_fee_rate, get_locked_amount,
recv_swap_msg, swap_topic, wait_for_maker_payment_conf_until, AtomicSwap, LockedAmount, MySwapInfo,
NegotiationDataMsg, NegotiationDataV2, NegotiationDataV3, RecoveredSwap, RecoveredSwapAction, SavedSwap,
SavedSwapIo, SavedTradeFee, SwapConfirmationsSettings, SwapError, SwapMsg, SwapPubkeys, SwapTxDataMsg,
SwapsContext, TransactionIdentifier, WAIT_CONFIRM_INTERVAL_SEC};
use crate::mm2::lp_network::subscribe_to_topic;
use crate::mm2::lp_ordermatch::TakerOrderBuilder;
use crate::mm2::lp_swap::{broadcast_p2p_tx_msg, broadcast_swap_msg_every_delayed, tx_helper_topic,
Expand Down Expand Up @@ -2577,13 +2577,12 @@ pub fn max_taker_vol_from_available(
rel: &str,
min_tx_amount: &MmNumber,
) -> Result<MmNumber, MmError<MaxTakerVolumeLessThanDust>> {
let fee_threshold = dex_fee_threshold(min_tx_amount.clone());
let dex_fee_rate = dex_fee_rate(base, rel);
let threshold_coef = &(&MmNumber::from(1) + &dex_fee_rate) / &dex_fee_rate;
let max_vol = if available > &fee_threshold * &threshold_coef {
let max_vol = if available > min_tx_amount * &threshold_coef {
available / (MmNumber::from(1) + dex_fee_rate)
} else {
available - fee_threshold
&available - min_tx_amount
};

if &max_vol <= min_tx_amount {
Expand Down Expand Up @@ -2948,21 +2947,19 @@ mod taker_swap_tests {

#[test]
fn test_max_taker_vol_from_available() {
let dex_fee_threshold = MmNumber::from("0.0001");
let min_tx_amount = MmNumber::from("0.00001");

// For these `availables` the dex_fee must be greater than threshold
// For these `availables` the dex_fee must be greater than min_tx_amount
let source = vec![
("0.0779", false),
("0.1", false),
("0.135", false),
("12.000001", false),
("999999999999999999999999999999999999999999999999999999", false),
("0.0778000000000000000000000000000000000000000000000002", false),
("0.0779", false),
("0.0778000000000000000000000000000000000000000000000001", false),
("0.0863333333333333333333333333333333333333333333333334", true),
("0.0863333333333333333333333333333333333333333333333333", true),
("0.00779", false),
("0.01", false),
("0.0135", false),
("1.2000001", false),
("99999999999999999999999999999999999999999999999999999", false),
("0.00778000000000000000000000000000000000000000000000002", false),
("0.00778000000000000000000000000000000000000000000000001", false),
("0.00863333333333333333333333333333333333333333333333334", true),
("0.00863333333333333333333333333333333333333333333333333", true),
];
for (available, is_kmd) in source {
let available = MmNumber::from(available);
Expand All @@ -2971,52 +2968,52 @@ mod taker_swap_tests {
let max_taker_vol = max_taker_vol_from_available(available.clone(), "RICK", "MORTY", &min_tx_amount)
.expect("!max_taker_vol_from_available");

let dex_fee = dex_fee_amount(base, "MORTY", &max_taker_vol, &dex_fee_threshold);
assert!(dex_fee_threshold < dex_fee);
let dex_fee = dex_fee_amount(base, "MORTY", &max_taker_vol, &min_tx_amount);
assert!(min_tx_amount < dex_fee);
assert!(min_tx_amount <= max_taker_vol);
assert_eq!(max_taker_vol + dex_fee, available);
}

// for these `availables` the dex_fee must be the same as `threshold`
// for these `availables` the dex_fee must be the same as min_tx_amount
let source = vec![
("0.0863333333333333333333333333333333333333333333333332", true),
("0.0863333333333333333333333333333333333333333333333331", true),
("0.0777999999999999999999999999999999999999999999999999", false),
("0.0777", false),
("0.0002", false),
("0.00863333333333333333333333333333333333333333333333332", true),
("0.00863333333333333333333333333333333333333333333333331", true),
("0.00777999999999999999999999999999999999999999999999999", false),
("0.00777", false),
("0.00002001", false),
];
for (available, is_kmd) in source {
let available = MmNumber::from(available);
// no matter base or rel is KMD
let base = if is_kmd { "KMD" } else { "RICK" };
let max_taker_vol = max_taker_vol_from_available(available.clone(), base, "MORTY", &min_tx_amount)
.expect("!max_taker_vol_from_available");
let dex_fee = dex_fee_amount(base, "MORTY", &max_taker_vol, &dex_fee_threshold);
let dex_fee = dex_fee_amount(base, "MORTY", &max_taker_vol, &min_tx_amount);
println!(
"available={:?} max_taker_vol={:?} dex_fee={:?}",
available.to_decimal(),
max_taker_vol.to_decimal(),
dex_fee.to_decimal()
);
assert_eq!(dex_fee_threshold, dex_fee);
assert_eq!(min_tx_amount, dex_fee);
assert!(min_tx_amount <= max_taker_vol);
assert_eq!(max_taker_vol + dex_fee, available);
}

// these `availables` must return an error
let availables = vec![
"0.0001999",
"0.00011",
"0.0001000000000000000000000000000000000000000000000001",
"0.0001",
"0.0000999999999999999999999999999999999999999999999999",
"0.0000000000000000000000000000000000000000000000000001",
"0.00002",
"0.000011",
"0.00001000000000000000000000000000000000000000000000001",
"0.00001",
"0.00000999999999999999999999999999999999999999999999999",
"0.00000000000000000000000000000000000000000000000000001",
"0",
"-2",
];
for available in availables {
let available = MmNumber::from(available);
max_taker_vol_from_available(available.clone(), "KMD", "MORTY", &dex_fee_threshold)
max_taker_vol_from_available(available.clone(), "KMD", "MORTY", &min_tx_amount)
.expect_err("!max_taker_vol_from_available success but should be error");
}
}
Expand Down
8 changes: 4 additions & 4 deletions mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2005,8 +2005,8 @@ fn test_get_max_taker_vol() {

// https://github.com/KomodoPlatform/atomicDEX-API/issues/733
#[test]
fn test_get_max_taker_vol_dex_fee_threshold() {
let (_ctx, _, alice_priv_key) = generate_utxo_coin_with_random_privkey("MYCOIN1", "0.05328455".parse().unwrap());
fn test_get_max_taker_vol_dex_fee_min_tx_amount() {
let (_ctx, _, alice_priv_key) = generate_utxo_coin_with_random_privkey("MYCOIN1", "0.00532845".parse().unwrap());
let coins = json!([mycoin_conf(10000), mycoin1_conf(10000)]);
let mm_alice = MarketMakerIt::start(
json!({
Expand Down Expand Up @@ -2034,8 +2034,8 @@ fn test_get_max_taker_vol_dex_fee_threshold() {
.unwrap();
assert!(rc.0.is_success(), "!max_taker_vol: {}", rc.1);
let json: Json = serde_json::from_str(&rc.1).unwrap();
// the result of equation x + 0.0001 (dex fee) + 0.0002 (miner fee * 2) = 0.05328455
assert_eq!(json["result"]["numer"], Json::from("1059691"));
// the result of equation x + 0.00001 (dex fee) + 0.0002 (miner fee * 2) = 0.00532845
assert_eq!(json["result"]["numer"], Json::from("102369"));
assert_eq!(json["result"]["denom"], Json::from("20000000"));

let rc = block_on(mm_alice.rpc(&json!({
Expand Down
15 changes: 5 additions & 10 deletions mm2src/mm2_main/tests/docker_tests/qrc20_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,7 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_
log!("{:?}", block_on(enable_native(&mm, "QTUM", &[], None)));

let qtum_balance = coin.my_spendable_balance().wait().expect("!my_balance");
let qtum_dex_fee_threshold = MmNumber::from("0.000728");
let qtum_min_tx_amount = MmNumber::from("0.000728");

// - `max_possible = balance - locked_amount`, where `locked_amount = 0`
// - `max_trade_fee = trade_fee(balance)`
Expand All @@ -1054,12 +1054,7 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_
// - `max_possible_2 = balance - locked_amount - max_trade_fee`, where `locked_amount = 0`
let max_possible_2 = &qtum_balance - &max_trade_fee;
// - `max_dex_fee = dex_fee(max_possible_2)`
let max_dex_fee = dex_fee_amount(
"QTUM",
"MYCOIN",
&MmNumber::from(max_possible_2),
&qtum_dex_fee_threshold,
);
let max_dex_fee = dex_fee_amount("QTUM", "MYCOIN", &MmNumber::from(max_possible_2), &qtum_min_tx_amount);
debug!("max_dex_fee: {:?}", max_dex_fee.to_fraction());

// - `max_fee_to_send_taker_fee = fee_to_send_taker_fee(max_dex_fee)`
Expand All @@ -1074,11 +1069,11 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_
// where `available = balance - locked_amount - max_trade_fee - max_fee_to_send_taker_fee`
let available = &qtum_balance - &max_trade_fee - &max_fee_to_send_taker_fee;
debug!("total_available: {}", available);
let min_tx_amount = qtum_dex_fee_threshold.clone();
let min_tx_amount = qtum_min_tx_amount.clone();
let expected_max_taker_vol =
max_taker_vol_from_available(MmNumber::from(available), "QTUM", "MYCOIN", &min_tx_amount)
.expect("max_taker_vol_from_available");
let real_dex_fee = dex_fee_amount("QTUM", "MYCOIN", &expected_max_taker_vol, &qtum_dex_fee_threshold);
let real_dex_fee = dex_fee_amount("QTUM", "MYCOIN", &expected_max_taker_vol, &qtum_min_tx_amount);
debug!("real_max_dex_fee: {:?}", real_dex_fee.to_fraction());

// check if the actual max_taker_vol equals to the expected
Expand Down Expand Up @@ -1111,7 +1106,7 @@ fn test_get_max_taker_vol_and_trade_with_dynamic_trade_fee(coin: QtumCoin, priv_
let timelock = now_sec_u32() - 200;
let secret_hash = &[0; 20];

let dex_fee_amount = dex_fee_amount("QTUM", "MYCOIN", &expected_max_taker_vol, &qtum_dex_fee_threshold);
let dex_fee_amount = dex_fee_amount("QTUM", "MYCOIN", &expected_max_taker_vol, &qtum_min_tx_amount);
let _taker_fee_tx = coin
.send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, dex_fee_amount.to_decimal(), &[])
.wait()
Expand Down
Loading
Loading