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

feat(swap): implement 0 dexfee for kmd trading pairs #2323

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
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
17 changes: 14 additions & 3 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5891,11 +5891,24 @@ impl MmCoin for EthCoin {
dex_fee_amount: DexFee,
stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
let dex_fee_amount = wei_from_big_decimal(&dex_fee_amount.fee_amount().into(), self.decimals)?;
let fee_coin = match &self.coin_type {
EthCoinType::Eth => self.ticker.to_owned(),
EthCoinType::Erc20 { platform, .. } => platform.to_owned(),
EthCoinType::Nft { .. } => return MmError::err(TradePreimageError::NftProtocolNotSupported),
};
if DexFee::Zero == dex_fee_amount {
return Ok(TradeFee {
coin: fee_coin,
amount: MmNumber::default(),
paid_from_trading_vol: false,
});
}

let dex_fee_amount = wei_from_big_decimal(&dex_fee_amount.fee_amount().into(), self.decimals)?;
// pass the dummy params
let to_addr = addr_from_raw_pubkey(&DEX_FEE_ADDR_RAW_PUBKEY)
.expect("addr_from_raw_pubkey should never fail with DEX_FEE_ADDR_RAW_PUBKEY");
let my_address = self.derivation_method.single_addr_or_err().await?;
let (eth_value, data, call_addr, fee_coin) = match &self.coin_type {
EthCoinType::Eth => (dex_fee_amount, Vec::new(), &to_addr, &self.ticker),
EthCoinType::Erc20 { platform, token_addr } => {
Expand All @@ -5905,8 +5918,6 @@ impl MmCoin for EthCoin {
},
EthCoinType::Nft { .. } => return MmError::err(TradePreimageError::NftProtocolNotSupported),
};

let my_address = self.derivation_method.single_addr_or_err().await?;
let fee_policy_for_estimate = get_swap_fee_policy_for_estimate(self.get_swap_transaction_fee_policy());
let pay_for_gas_option = self.get_swap_pay_for_gas_option(fee_policy_for_estimate).await?;
let pay_for_gas_option = increase_gas_price_by_stage(pay_for_gas_option, &stage);
Expand Down
6 changes: 5 additions & 1 deletion mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3624,6 +3624,8 @@ pub enum DexFee {
fee_amount: MmNumber,
burn_amount: MmNumber,
},
/// Zero dex fee, exclusive to KMD only.
Zero,
}

impl DexFee {
Expand All @@ -3640,13 +3642,14 @@ impl DexFee {
match self {
DexFee::Standard(t) => t.clone(),
DexFee::WithBurn { fee_amount, .. } => fee_amount.clone(),
DexFee::Zero => MmNumber::default(),
}
}

/// Gets the burn amount associated with the dex fee, if applicable.
pub fn burn_amount(&self) -> Option<MmNumber> {
match self {
DexFee::Standard(_) => None,
DexFee::Standard(_) | DexFee::Zero => None,
DexFee::WithBurn { burn_amount, .. } => Some(burn_amount.clone()),
}
}
Expand All @@ -3659,6 +3662,7 @@ impl DexFee {
fee_amount,
burn_amount,
} => fee_amount + burn_amount,
DexFee::Zero => MmNumber::default(),
}
}

Expand Down
8 changes: 8 additions & 0 deletions mm2src/coins/qrc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1418,6 +1418,14 @@ impl MmCoin for Qrc20Coin {
dex_fee_amount: DexFee,
stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
if DexFee::Zero == dex_fee_amount {
return Ok(TradeFee {
coin: self.platform.clone(),
amount: MmNumber::default(),
paid_from_trading_vol: false,
});
}

let amount = wei_from_big_decimal(&dex_fee_amount.fee_amount().into(), self.utxo.decimals)?;

// pass the dummy params
Expand Down
8 changes: 8 additions & 0 deletions mm2src/coins/tendermint/tendermint_coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2478,6 +2478,14 @@ impl MmCoin for TendermintCoin {
dex_fee_amount: DexFee,
_stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
if DexFee::Zero == dex_fee_amount {
return Ok(TradeFee {
coin: self.ticker.clone(),
amount: MmNumber::default(),
paid_from_trading_vol: false,
});
}

self.get_fee_to_send_taker_fee_for_denom(self.ticker.clone(), self.denom.clone(), self.decimals, dex_fee_amount)
.await
}
Expand Down
9 changes: 9 additions & 0 deletions mm2src/coins/utxo/slp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1844,6 +1844,14 @@ impl MmCoin for SlpToken {
dex_fee_amount: DexFee,
stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
if DexFee::Zero == dex_fee_amount {
return Ok(TradeFee {
coin: self.platform_coin.ticker().into(),
amount: MmNumber::default(),
paid_from_trading_vol: false,
});
}

let slp_amount = sat_from_big_decimal(&dex_fee_amount.fee_amount().into(), self.decimals())?;
// can use dummy P2PKH script_pubkey here
let script_pubkey = ScriptBuilder::build_p2pkh(&H160::default().into()).into();
Expand All @@ -1861,6 +1869,7 @@ impl MmCoin for SlpToken {
&stage,
)
.await?;

Ok(TradeFee {
coin: self.platform_coin.ticker().into(),
amount: fee.into(),
Expand Down
96 changes: 60 additions & 36 deletions mm2src/coins/utxo/utxo_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1243,39 +1243,50 @@ async fn gen_taker_payment_spend_preimage<T: UtxoCommonOps>(
args: &GenTakerPaymentSpendArgs<'_, T>,
n_time: NTimeSetting,
) -> GenPreimageResInner {
let dex_fee_address = address_from_raw_pubkey(
args.dex_fee_pub,
coin.as_ref().conf.address_prefixes.clone(),
coin.as_ref().conf.checksum_type,
coin.as_ref().conf.bech32_hrp.clone(),
coin.addr_format().clone(),
)
.map_to_mm(|e| TxGenError::AddressDerivation(format!("Failed to derive dex_fee_address: {}", e)))?;

let mut outputs = generate_taker_fee_tx_outputs(coin.as_ref().decimals, dex_fee_address.hash(), args.dex_fee)?;
if let DexFee::WithBurn { .. } = args.dex_fee {
let script = output_script(args.maker_address).map_to_mm(|e| {
TxGenError::Other(format!(
"Couldn't generate output script for maker address {}, error {}",
args.maker_address, e
))
})?;
let tx_fee = coin
.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox)
.await?;
let maker_value = args
.taker_tx
.first_output()
.map_to_mm(|e| TxGenError::PrevTxIsNotValid(e.to_string()))?
.value
- outputs[0].value
- outputs[1].value
- tx_fee;
outputs.push(TransactionOutput {
value: maker_value,
script_pubkey: script.to_bytes(),
})
}
let outputs = match args.dex_fee {
DexFee::Zero => vec![],
dex_fee => {
let dex_fee_address = address_from_raw_pubkey(
args.dex_fee_pub,
coin.as_ref().conf.address_prefixes.clone(),
coin.as_ref().conf.checksum_type,
coin.as_ref().conf.bech32_hrp.clone(),
coin.addr_format().clone(),
)
.map_to_mm(|e| TxGenError::AddressDerivation(format!("Failed to derive dex_fee_address: {}", e)))?;

let mut fee_outputs =
generate_taker_fee_tx_outputs(coin.as_ref().decimals, dex_fee_address.hash(), dex_fee)?;

if let DexFee::WithBurn { .. } = dex_fee {
let script = output_script(args.maker_address).map_to_mm(|e| {
TxGenError::Other(format!(
"Couldn't generate output script for maker address {}, error {}",
args.maker_address, e
))
})?;

let tx_fee = coin
.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox)
.await?;

let total_fee_value: u64 = fee_outputs.iter().map(|out| out.value).sum();
let first_output_value = args
.taker_tx
.first_output()
.map_to_mm(|e| TxGenError::PrevTxIsNotValid(e.to_string()))?
.value;

let maker_value = first_output_value - total_fee_value - tx_fee;
fee_outputs.push(TransactionOutput {
value: maker_value,
script_pubkey: script.to_bytes(),
});
}

fee_outputs
},
};

p2sh_spending_tx_preimage(
coin,
Expand Down Expand Up @@ -1306,7 +1317,7 @@ pub async fn gen_and_sign_taker_payment_spend_preimage<T: UtxoCommonOps>(

let sig_hash_type = match args.dex_fee {
DexFee::Standard(_) => SIGHASH_SINGLE,
DexFee::WithBurn { .. } => SIGHASH_ALL,
DexFee::WithBurn { .. } | DexFee::Zero => SIGHASH_ALL,
};

let signature = calc_and_sign_sighash(
Expand Down Expand Up @@ -1349,7 +1360,7 @@ pub async fn validate_taker_payment_spend_preimage<T: UtxoCommonOps + SwapOps>(

let sig_hash_type = match gen_args.dex_fee {
DexFee::Standard(_) => SIGHASH_SINGLE,
DexFee::WithBurn { .. } => SIGHASH_ALL,
DexFee::WithBurn { .. } | DexFee::Zero => SIGHASH_ALL,
};

let sig_hash = signature_hash_to_sign(
Expand Down Expand Up @@ -1433,7 +1444,7 @@ pub async fn sign_and_broadcast_taker_payment_spend<T: UtxoCommonOps>(
let mut taker_signature_with_sighash = preimage.signature.to_vec();
let taker_sig_hash = match gen_args.dex_fee {
DexFee::Standard(_) => (SIGHASH_SINGLE | coin.as_ref().conf.fork_id) as u8,
DexFee::WithBurn { .. } => (SIGHASH_ALL | coin.as_ref().conf.fork_id) as u8,
DexFee::WithBurn { .. } | DexFee::Zero => (SIGHASH_ALL | coin.as_ref().conf.fork_id) as u8,
};

taker_signature_with_sighash.push(taker_sig_hash);
Expand Down Expand Up @@ -1486,6 +1497,11 @@ fn generate_taker_fee_tx_outputs(
address_hash: &AddressHashEnum,
dex_fee: &DexFee,
) -> Result<Vec<TransactionOutput>, MmError<NumConversError>> {
// Don't add outputs for Zero DexFee.
if let DexFee::Zero = dex_fee {
return Ok(vec![]);
}

let fee_amount = dex_fee.fee_uamount(decimals)?;

let mut outputs = vec![TransactionOutput {
Expand Down Expand Up @@ -3973,6 +3989,14 @@ pub async fn get_fee_to_send_taker_fee<T>(
where
T: MarketCoinOps + UtxoCommonOps,
{
if DexFee::Zero == dex_fee {
return Ok(TradeFee {
coin: coin.ticker().to_owned(),
amount: MmNumber::default(),
paid_from_trading_vol: false,
});
}

let decimals = coin.as_ref().decimals;

let outputs = generate_taker_fee_tx_outputs(decimals, &AddressHashEnum::default_address_hash(), &dex_fee)?;
Expand Down
10 changes: 9 additions & 1 deletion mm2src/coins/z_coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1750,9 +1750,17 @@ impl MmCoin for ZCoin {

async fn get_fee_to_send_taker_fee(
&self,
_dex_fee_amount: DexFee,
dex_fee_amount: DexFee,
_stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
if DexFee::Zero == dex_fee_amount {
return Ok(TradeFee {
coin: self.ticker().to_owned(),
amount: MmNumber::default(),
paid_from_trading_vol: false,
});
}

Ok(TradeFee {
coin: self.ticker().to_owned(),
amount: self.get_one_kbyte_tx_fee().await?.into(),
Expand Down
Loading
Loading