Skip to content
17 changes: 10 additions & 7 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use super::eth::Action::{Call, Create};
use crate::lp_price::get_base_price_in_rel;
use crate::nft::nft_structs::{ContractType, ConvertChain, TransactionNftDetails, WithdrawErc1155, WithdrawErc721};
use crate::{ValidateWatcherSpendInput, WatcherSpendType};
use crate::{DexFee, ValidateWatcherSpendInput, WatcherSpendType};
use async_trait::async_trait;
use bitcrypto::{dhash160, keccak256, ripemd160, sha256};
use common::custom_futures::repeatable::{Ready, Retry, RetryOnError};
Expand Down Expand Up @@ -1058,12 +1058,15 @@ impl Deref for EthCoin {

#[async_trait]
impl SwapOps for EthCoin {
fn send_taker_fee(&self, fee_addr: &[u8], amount: BigDecimal, _uuid: &[u8]) -> TransactionFut {
fn send_taker_fee(&self, fee_addr: &[u8], dex_fee: DexFee, _uuid: &[u8]) -> TransactionFut {
let address = try_tx_fus!(addr_from_raw_pubkey(fee_addr));

Box::new(
self.send_to_address(address, try_tx_fus!(wei_from_big_decimal(&amount, self.decimals)))
.map(TransactionEnum::from),
self.send_to_address(
address,
try_tx_fus!(wei_from_big_decimal(&dex_fee.fee_amount().into(), self.decimals)),
)
.map(TransactionEnum::from),
)
}

Expand Down Expand Up @@ -1118,7 +1121,7 @@ impl SwapOps for EthCoin {
fee_tx_hash: &tx.hash,
expected_sender: validate_fee_args.expected_sender,
fee_addr: validate_fee_args.fee_addr,
amount: validate_fee_args.amount,
amount: &validate_fee_args.dex_fee.fee_amount().into(),
min_block_number: validate_fee_args.min_block_number,
uuid: validate_fee_args.uuid,
})
Expand Down Expand Up @@ -4901,10 +4904,10 @@ impl MmCoin for EthCoin {

async fn get_fee_to_send_taker_fee(
&self,
dex_fee_amount: BigDecimal,
dex_fee_amount: DexFee,
stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
let dex_fee_amount = wei_from_big_decimal(&dex_fee_amount, self.decimals)?;
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)
Expand Down
30 changes: 20 additions & 10 deletions mm2src/coins/eth/eth_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use crate::IguanaPrivKey;
use crate::{DexFee, IguanaPrivKey};
use common::{block_on, now_sec, wait_until_sec};
use crypto::privkey::key_pair_from_seed;
use ethkey::{Generator, Random};
Expand Down Expand Up @@ -1104,8 +1104,11 @@ fn test_get_fee_to_send_taker_fee() {
let dex_fee_amount = u256_to_big_decimal(DEX_FEE_AMOUNT.into(), 18).expect("!u256_to_big_decimal");

let (_ctx, coin) = eth_coin_for_test(EthCoinType::Eth, &["http://dummy.dummy"], None);
let actual = block_on(coin.get_fee_to_send_taker_fee(dex_fee_amount.clone(), FeeApproxStage::WithoutApprox))
.expect("!get_fee_to_send_taker_fee");
let actual = block_on(coin.get_fee_to_send_taker_fee(
DexFee::Standard(MmNumber::from(dex_fee_amount.clone())),
FeeApproxStage::WithoutApprox,
))
.expect("!get_fee_to_send_taker_fee");
assert_eq!(actual, expected_fee);

let (_ctx, coin) = eth_coin_for_test(
Expand All @@ -1116,8 +1119,11 @@ fn test_get_fee_to_send_taker_fee() {
&["http://dummy.dummy"],
None,
);
let actual = block_on(coin.get_fee_to_send_taker_fee(dex_fee_amount, FeeApproxStage::WithoutApprox))
.expect("!get_fee_to_send_taker_fee");
let actual = block_on(coin.get_fee_to_send_taker_fee(
DexFee::Standard(MmNumber::from(dex_fee_amount)),
FeeApproxStage::WithoutApprox,
))
.expect("!get_fee_to_send_taker_fee");
assert_eq!(actual, expected_fee);
}

Expand All @@ -1143,7 +1149,11 @@ fn test_get_fee_to_send_taker_fee_insufficient_balance() {
);
let dex_fee_amount = u256_to_big_decimal(DEX_FEE_AMOUNT.into(), 18).expect("!u256_to_big_decimal");

let error = block_on(coin.get_fee_to_send_taker_fee(dex_fee_amount, FeeApproxStage::WithoutApprox)).unwrap_err();
let error = block_on(coin.get_fee_to_send_taker_fee(
DexFee::Standard(MmNumber::from(dex_fee_amount)),
FeeApproxStage::WithoutApprox,
))
.unwrap_err();
log!("{}", error);
assert!(
matches!(error.get_inner(), TradePreimageError::NotSufficientBalance { .. }),
Expand All @@ -1167,7 +1177,7 @@ fn validate_dex_fee_invalid_sender_eth() {
fee_tx: &tx,
expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.into()),
min_block_number: 0,
uuid: &[],
};
Expand Down Expand Up @@ -1201,7 +1211,7 @@ fn validate_dex_fee_invalid_sender_erc() {
fee_tx: &tx,
expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.into()),
min_block_number: 0,
uuid: &[],
};
Expand Down Expand Up @@ -1239,7 +1249,7 @@ fn validate_dex_fee_eth_confirmed_before_min_block() {
fee_tx: &tx,
expected_sender: &compressed_public,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.into()),
min_block_number: 11784793,
uuid: &[],
};
Expand Down Expand Up @@ -1276,7 +1286,7 @@ fn validate_dex_fee_erc_confirmed_before_min_block() {
fee_tx: &tx,
expected_sender: &compressed_public,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.into()),
min_block_number: 11823975,
uuid: &[],
};
Expand Down
8 changes: 4 additions & 4 deletions mm2src/coins/lightning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::lightning::ln_utils::{filter_channels, pay_invoice_with_max_total_clt
use crate::utxo::rpc_clients::UtxoRpcClientEnum;
use crate::utxo::utxo_common::{big_decimal_from_sat, big_decimal_from_sat_unsigned};
use crate::utxo::{sat_from_big_decimal, utxo_common, BlockchainNetwork};
use crate::{BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinFutSpawner, ConfirmPaymentInput, FeeApproxStage,
FoundSwapTxSpend, HistorySyncState, MakerSwapTakerCoin, MarketCoinOps, MmCoin, MmCoinEnum,
use crate::{BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinFutSpawner, ConfirmPaymentInput, DexFee,
FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MakerSwapTakerCoin, MarketCoinOps, MmCoin, MmCoinEnum,
NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr,
RawTransactionError, RawTransactionFut, RawTransactionRequest, RefundError, RefundPaymentArgs,
RefundResult, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs,
Expand Down Expand Up @@ -612,7 +612,7 @@ impl LightningCoin {
#[async_trait]
impl SwapOps for LightningCoin {
// Todo: This uses dummy data for now for the sake of swap P.O.C., this should be implemented probably after agreeing on how fees will work for lightning
fn send_taker_fee(&self, _fee_addr: &[u8], _amount: BigDecimal, _uuid: &[u8]) -> TransactionFut {
fn send_taker_fee(&self, _fee_addr: &[u8], _dex_fee: DexFee, _uuid: &[u8]) -> TransactionFut {
let fut = async move { Ok(TransactionEnum::LightningPayment(PaymentHash([1; 32]))) };
Box::new(fut.boxed().compat())
}
Expand Down Expand Up @@ -1342,7 +1342,7 @@ impl MmCoin for LightningCoin {
// Todo: This uses dummy data for now for the sake of swap P.O.C., this should be implemented probably after agreeing on how fees will work for lightning
async fn get_fee_to_send_taker_fee(
&self,
_dex_fee_amount: BigDecimal,
_dex_fee_amount: DexFee,
_stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
Ok(TradeFee {
Expand Down
72 changes: 69 additions & 3 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ pub struct ValidateFeeArgs<'a> {
pub fee_tx: &'a TransactionEnum,
pub expected_sender: &'a [u8],
pub fee_addr: &'a [u8],
pub amount: &'a BigDecimal,
pub dex_fee: &'a DexFee,
pub min_block_number: u64,
pub uuid: &'a [u8],
}
Expand Down Expand Up @@ -903,7 +903,7 @@ pub enum WatcherRewardError {
/// Swap operations (mostly based on the Hash/Time locked transactions implemented by coin wallets).
#[async_trait]
pub trait SwapOps {
fn send_taker_fee(&self, fee_addr: &[u8], amount: BigDecimal, uuid: &[u8]) -> TransactionFut;
fn send_taker_fee(&self, fee_addr: &[u8], dex_fee: DexFee, uuid: &[u8]) -> TransactionFut;

fn send_maker_payment(&self, maker_payment_args: SendPaymentArgs<'_>) -> TransactionFut;

Expand Down Expand Up @@ -2673,7 +2673,7 @@ pub trait MmCoin:
/// Get transaction fee the Taker has to pay to send a `TakerFee` transaction and check if the wallet has sufficient balance to pay the fee.
async fn get_fee_to_send_taker_fee(
&self,
dex_fee_amount: BigDecimal,
dex_fee_amount: DexFee,
stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee>;

Expand Down Expand Up @@ -2951,6 +2951,72 @@ impl MmCoinStruct {
}
}

/// Represents the different types of DEX fees.
#[derive(Clone, Debug, PartialEq)]
pub enum DexFee {
/// Standard dex fee which will be sent to the dex fee address
Standard(MmNumber),
/// Dex fee with the burn amount.
/// - `fee_amount` goes to the dex fee address.
/// - `burn_amount` will be added as `OP_RETURN` output in the dex fee transaction.
WithBurn {
fee_amount: MmNumber,
burn_amount: MmNumber,
},
}

impl DexFee {
/// Creates a new `DexFee` with burn amounts.
pub fn with_burn(fee_amount: MmNumber, burn_amount: MmNumber) -> DexFee {
DexFee::WithBurn {
fee_amount,
burn_amount,
}
}

/// Gets the fee amount associated with the dex fee.
pub fn fee_amount(&self) -> MmNumber {
match self {
DexFee::Standard(t) => t.clone(),
DexFee::WithBurn { fee_amount, .. } => fee_amount.clone(),
}
}

/// Gets the burn amount associated with the dex fee, if applicable.
pub fn burn_amount(&self) -> Option<MmNumber> {
match self {
DexFee::Standard(_) => None,
DexFee::WithBurn { burn_amount, .. } => Some(burn_amount.clone()),
}
}

/// Calculates the total spend amount, considering both the fee and burn amounts.
pub fn total_spend_amount(&self) -> MmNumber {
match self {
DexFee::Standard(t) => t.clone(),
DexFee::WithBurn {
fee_amount,
burn_amount,
} => fee_amount + burn_amount,
}
}

/// Converts the fee amount to micro-units based on the specified decimal places.
pub fn fee_uamount(&self, decimals: u8) -> NumConversResult<u64> {
let fee_amount = self.fee_amount();
utxo::sat_from_big_decimal(&fee_amount.into(), decimals)
}

/// Converts the burn amount to micro-units, if applicable, based on the specified decimal places.
pub fn burn_uamount(&self, decimals: u8) -> NumConversResult<Option<u64>> {
if let Some(burn_amount) = self.burn_amount() {
Ok(Some(utxo::sat_from_big_decimal(&burn_amount.into(), decimals)?))
} else {
Ok(None)
}
}
}

pub struct CoinsContext {
/// A map from a currency ticker symbol to the corresponding coin.
/// Similar to `LP_coins`.
Expand Down
38 changes: 21 additions & 17 deletions mm2src/coins/qrc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@ use crate::utxo::{qtum, ActualTxFee, AdditionalTxData, AddrFromStrError, Broadca
UtxoActivationParams, UtxoAddressFormat, UtxoCoinFields, UtxoCommonOps, UtxoFromLegacyReqErr,
UtxoTx, UtxoTxBroadcastOps, UtxoTxGenerationOps, VerboseTransactionFrom, UTXO_LOCK};
use crate::{BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinFutSpawner, ConfirmPaymentInput,
FeeApproxStage, FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MakerSwapTakerCoin, MarketCoinOps,
MmCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions,
PaymentInstructionsErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionFut,
RawTransactionRequest, RefundError, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput,
SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignatureResult, SpendPaymentArgs, SwapOps,
TakerSwapMakerCoin, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult,
TradePreimageValue, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut,
TransactionResult, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult,
ValidateFeeArgs, ValidateInstructionsErr, ValidateOtherPubKeyErr, ValidatePaymentFut,
ValidatePaymentInput, ValidateWatcherSpendInput, VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps,
WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput,
WatcherValidateTakerFeeInput, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, WithdrawResult};
DexFee, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, IguanaPrivKey, MakerSwapTakerCoin,
MarketCoinOps, MmCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs,
PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed,
RawTransactionFut, RawTransactionRequest, RefundError, RefundPaymentArgs, RefundResult,
SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignatureResult,
SpendPaymentArgs, SwapOps, TakerSwapMakerCoin, TradeFee, TradePreimageError, TradePreimageFut,
TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionEnum, TransactionErr,
TransactionFut, TransactionResult, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod,
ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, ValidateOtherPubKeyErr,
ValidatePaymentFut, ValidatePaymentInput, ValidateWatcherSpendInput, VerificationResult,
WaitForHTLCTxSpendArgs, WatcherOps, WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput,
WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WithdrawError, WithdrawFee, WithdrawFut,
WithdrawRequest, WithdrawResult};
use async_trait::async_trait;
use bitcrypto::{dhash160, sha256};
use chain::TransactionOutput;
Expand Down Expand Up @@ -753,9 +754,9 @@ impl UtxoCommonOps for Qrc20Coin {

#[async_trait]
impl SwapOps for Qrc20Coin {
fn send_taker_fee(&self, fee_addr: &[u8], amount: BigDecimal, _uuid: &[u8]) -> TransactionFut {
fn send_taker_fee(&self, fee_addr: &[u8], dex_fee: DexFee, _uuid: &[u8]) -> TransactionFut {
let to_address = try_tx_fus!(self.contract_address_from_raw_pubkey(fee_addr));
let amount = try_tx_fus!(wei_from_big_decimal(&amount, self.utxo.decimals));
let amount = try_tx_fus!(wei_from_big_decimal(&dex_fee.fee_amount().into(), self.utxo.decimals));
let transfer_output =
try_tx_fus!(self.transfer_output(to_address, amount, QRC20_GAS_LIMIT_DEFAULT, QRC20_GAS_PRICE_DEFAULT));
let outputs = vec![transfer_output];
Expand Down Expand Up @@ -874,7 +875,10 @@ impl SwapOps for Qrc20Coin {
let fee_addr = try_f!(self
.contract_address_from_raw_pubkey(validate_fee_args.fee_addr)
.map_to_mm(ValidatePaymentError::WrongPaymentTx));
let expected_value = try_f!(wei_from_big_decimal(validate_fee_args.amount, self.utxo.decimals));
let expected_value = try_f!(wei_from_big_decimal(
&validate_fee_args.dex_fee.fee_amount().into(),
self.utxo.decimals
));

let selfi = self.clone();
let fut = async move {
Expand Down Expand Up @@ -1432,10 +1436,10 @@ impl MmCoin for Qrc20Coin {

async fn get_fee_to_send_taker_fee(
&self,
dex_fee_amount: BigDecimal,
dex_fee_amount: DexFee,
stage: FeeApproxStage,
) -> TradePreimageResult<TradeFee> {
let amount = wei_from_big_decimal(&dex_fee_amount, self.utxo.decimals)?;
let amount = wei_from_big_decimal(&dex_fee_amount.fee_amount().into(), self.utxo.decimals)?;

// pass the dummy params
let to_addr = H160::default();
Expand Down
Loading