Skip to content
13 changes: 8 additions & 5 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
10 changes: 5 additions & 5 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 @@ -1167,7 +1167,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 +1201,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 +1239,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 +1276,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
6 changes: 3 additions & 3 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
70 changes: 68 additions & 2 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 @@ -2951,6 +2951,72 @@ impl MmCoinStruct {
}
}

/// Represents the different types of DEX fees.
#[derive(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
34 changes: 19 additions & 15 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
18 changes: 9 additions & 9 deletions mm2src/coins/qrc20/qrc20_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;
use crate::utxo::rpc_clients::UnspentInfo;
use crate::{TxFeeDetails, WaitForHTLCTxSpendArgs};
use crate::{DexFee, TxFeeDetails, WaitForHTLCTxSpendArgs};
use chain::OutPoint;
use common::{block_on, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY};
use crypto::Secp256k1Secret;
Expand Down Expand Up @@ -309,7 +309,7 @@ fn test_send_taker_fee() {

let amount = BigDecimal::from_str("0.01").unwrap();
let tx = coin
.send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, amount.clone(), &[])
.send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, DexFee::Standard(amount.clone().into()), &[])
.wait()
.unwrap();
let tx_hash: H256Json = match tx {
Expand All @@ -323,7 +323,7 @@ fn test_send_taker_fee() {
fee_tx: &tx,
expected_sender: coin.my_public_key().unwrap(),
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.into()),
min_block_number: 0,
uuid: &[],
})
Expand Down Expand Up @@ -351,7 +351,7 @@ fn test_validate_fee() {
fee_tx: &tx,
expected_sender: &sender_pub,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.clone().into()),
min_block_number: 0,
uuid: &[],
})
Expand All @@ -364,7 +364,7 @@ fn test_validate_fee() {
fee_tx: &tx,
expected_sender: &sender_pub,
fee_addr: &fee_addr_dif,
amount: &amount,
dex_fee: &DexFee::Standard(amount.clone().into()),
min_block_number: 0,
uuid: &[],
})
Expand All @@ -382,7 +382,7 @@ fn test_validate_fee() {
fee_tx: &tx,
expected_sender: &DEX_FEE_ADDR_RAW_PUBKEY,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.clone().into()),
min_block_number: 0,
uuid: &[],
})
Expand All @@ -400,7 +400,7 @@ fn test_validate_fee() {
fee_tx: &tx,
expected_sender: &sender_pub,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.clone().into()),
min_block_number: 2000000,
uuid: &[],
})
Expand All @@ -419,7 +419,7 @@ fn test_validate_fee() {
fee_tx: &tx,
expected_sender: &sender_pub,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount_dif,
dex_fee: &DexFee::Standard(amount_dif.into()),
min_block_number: 0,
uuid: &[],
})
Expand All @@ -442,7 +442,7 @@ fn test_validate_fee() {
fee_tx: &tx,
expected_sender: &sender_pub,
fee_addr: &DEX_FEE_ADDR_RAW_PUBKEY,
amount: &amount,
dex_fee: &DexFee::Standard(amount.into()),
min_block_number: 0,
uuid: &[],
})
Expand Down
26 changes: 13 additions & 13 deletions mm2src/coins/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ use super::{CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, SwapOps, Trade
use crate::coin_errors::MyAddressError;
use crate::solana::solana_common::{lamports_to_sol, PrepareTransferData, SufficientBalanceError};
use crate::solana::spl::SplTokenInfo;
use crate::{BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, FeeApproxStage,
FoundSwapTxSpend, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs,
PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed,
RawTransactionFut, RawTransactionRequest, RefundError, RefundPaymentArgs, RefundResult,
SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignatureResult,
SpendPaymentArgs, TakerSwapMakerCoin, TradePreimageFut, TradePreimageResult, TradePreimageValue,
TransactionDetails, TransactionFut, TransactionResult, TransactionType, TxMarshalingErr,
UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr,
ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput,
ValidateWatcherSpendInput, VerificationResult, WaitForHTLCTxSpendArgs, WatcherReward, WatcherRewardError,
WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput,
WithdrawError, WithdrawFut, WithdrawRequest, WithdrawResult};
use crate::{BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, DexFee,
FeeApproxStage, FoundSwapTxSpend, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr,
PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy,
PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionRequest, RefundError, RefundPaymentArgs,
RefundResult, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs,
SignatureResult, SpendPaymentArgs, TakerSwapMakerCoin, TradePreimageFut, TradePreimageResult,
TradePreimageValue, TransactionDetails, TransactionFut, TransactionResult, TransactionType,
TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs,
ValidateInstructionsErr, ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut,
ValidatePaymentInput, ValidateWatcherSpendInput, VerificationResult, WaitForHTLCTxSpendArgs,
WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput,
WatcherValidateTakerFeeInput, WithdrawError, WithdrawFut, WithdrawRequest, WithdrawResult};
use async_trait::async_trait;
use base58::ToBase58;
use bincode::{deserialize, serialize};
Expand Down Expand Up @@ -468,7 +468,7 @@ impl MarketCoinOps for SolanaCoin {

#[async_trait]
impl SwapOps for SolanaCoin {
fn send_taker_fee(&self, _fee_addr: &[u8], amount: BigDecimal, _uuid: &[u8]) -> TransactionFut { unimplemented!() }
fn send_taker_fee(&self, _fee_addr: &[u8], dex_fee: DexFee, _uuid: &[u8]) -> TransactionFut { unimplemented!() }

fn send_maker_payment(&self, _maker_payment_args: SendPaymentArgs) -> TransactionFut { unimplemented!() }

Expand Down
4 changes: 2 additions & 2 deletions mm2src/coins/solana/spl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, SwapOps, Trade
use crate::coin_errors::MyAddressError;
use crate::solana::solana_common::{ui_amount_to_amount, PrepareTransferData, SufficientBalanceError};
use crate::solana::{solana_common, AccountError, SolanaCommonOps, SolanaFeeDetails};
use crate::{BalanceFut, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, FeeApproxStage,
use crate::{BalanceFut, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, DexFee, FeeApproxStage,
FoundSwapTxSpend, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs,
PaymentInstructions, PaymentInstructionsErr, RawTransactionFut, RawTransactionRequest, RefundError,
RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput,
Expand Down Expand Up @@ -289,7 +289,7 @@ impl MarketCoinOps for SplToken {

#[async_trait]
impl SwapOps for SplToken {
fn send_taker_fee(&self, _fee_addr: &[u8], amount: BigDecimal, _uuid: &[u8]) -> TransactionFut { unimplemented!() }
fn send_taker_fee(&self, _fee_addr: &[u8], dex_fee: DexFee, _uuid: &[u8]) -> TransactionFut { unimplemented!() }

fn send_maker_payment(&self, _maker_payment_args: SendPaymentArgs) -> TransactionFut { unimplemented!() }

Expand Down
Loading