Skip to content

Commit

Permalink
refactor(SwapOps): make all methods async (#2251)
Browse files Browse the repository at this point in the history
  • Loading branch information
shamardy authored Oct 24, 2024
1 parent b35a818 commit df3d39c
Show file tree
Hide file tree
Showing 25 changed files with 645 additions and 575 deletions.
144 changes: 74 additions & 70 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1105,16 +1105,21 @@ impl Deref for EthCoin {

#[async_trait]
impl SwapOps for EthCoin {
fn send_taker_fee(&self, fee_addr: &[u8], dex_fee: DexFee, _uuid: &[u8], _expire_at: u64) -> 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(&dex_fee.fee_amount().into(), self.decimals)),
)
.map(TransactionEnum::from),
async fn send_taker_fee(
&self,
fee_addr: &[u8],
dex_fee: DexFee,
_uuid: &[u8],
_expire_at: u64,
) -> TransactionResult {
let address = try_tx_s!(addr_from_raw_pubkey(fee_addr));
self.send_to_address(
address,
try_tx_s!(wei_from_big_decimal(&dex_fee.fee_amount().into(), self.decimals)),
)
.map(TransactionEnum::from)
.compat()
.await
}

async fn send_maker_payment(&self, maker_payment_args: SendPaymentArgs<'_>) -> TransactionResult {
Expand All @@ -1124,11 +1129,11 @@ impl SwapOps for EthCoin {
.map(TransactionEnum::from)
}

fn send_taker_payment(&self, taker_payment: SendPaymentArgs) -> TransactionFut {
Box::new(
self.send_hash_time_locked_payment(taker_payment)
.map(TransactionEnum::from),
)
async fn send_taker_payment(&self, taker_payment_args: SendPaymentArgs<'_>) -> TransactionResult {
self.send_hash_time_locked_payment(taker_payment_args)
.map(TransactionEnum::from)
.compat()
.await
}

async fn send_maker_spends_taker_payment(
Expand Down Expand Up @@ -1161,10 +1166,15 @@ impl SwapOps for EthCoin {
.map(TransactionEnum::from)
}

fn validate_fee(&self, validate_fee_args: ValidateFeeArgs<'_>) -> ValidatePaymentFut<()> {
async fn validate_fee(&self, validate_fee_args: ValidateFeeArgs<'_>) -> ValidatePaymentResult<()> {
let tx = match validate_fee_args.fee_tx {
TransactionEnum::SignedEthTx(t) => t.clone(),
_ => panic!(),
fee_tx => {
return MmError::err(ValidatePaymentError::InternalError(format!(
"Invalid fee tx type. fee tx: {:?}",
fee_tx
)))
},
};
validate_fee_impl(self.clone(), EthValidateFeeArgs {
fee_tx_hash: &tx.tx_hash(),
Expand All @@ -1174,6 +1184,8 @@ impl SwapOps for EthCoin {
min_block_number: validate_fee_args.min_block_number,
uuid: validate_fee_args.uuid,
})
.compat()
.await
}

#[inline]
Expand All @@ -1186,70 +1198,62 @@ impl SwapOps for EthCoin {
self.validate_payment(input).compat().await
}

fn check_if_my_payment_sent(
async fn check_if_my_payment_sent(
&self,
if_my_payment_sent_args: CheckIfMyPaymentSentArgs,
) -> Box<dyn Future<Item = Option<TransactionEnum>, Error = String> + Send> {
let id = self.etomic_swap_id(
try_fus!(if_my_payment_sent_args.time_lock.try_into()),
if_my_payment_sent_args.secret_hash,
);
let swap_contract_address = try_fus!(if_my_payment_sent_args.swap_contract_address.try_to_address());
let selfi = self.clone();
if_my_payment_sent_args: CheckIfMyPaymentSentArgs<'_>,
) -> Result<Option<TransactionEnum>, String> {
let time_lock = if_my_payment_sent_args
.time_lock
.try_into()
.map_err(|e: TryFromIntError| e.to_string())?;
let id = self.etomic_swap_id(time_lock, if_my_payment_sent_args.secret_hash);
let swap_contract_address = if_my_payment_sent_args.swap_contract_address.try_to_address()?;
let from_block = if_my_payment_sent_args.search_from_block;
let fut = async move {
let status = try_s!(
selfi
.payment_status(swap_contract_address, Token::FixedBytes(id.clone()))
.compat()
.await
);
let status = self
.payment_status(swap_contract_address, Token::FixedBytes(id.clone()))
.compat()
.await?;

if status == U256::from(PaymentState::Uninitialized as u8) {
return Ok(None);
};
if status == U256::from(PaymentState::Uninitialized as u8) {
return Ok(None);
};

let mut current_block = try_s!(selfi.current_block().compat().await);
if current_block < from_block {
current_block = from_block;
}
let mut current_block = self.current_block().compat().await?;
if current_block < from_block {
current_block = from_block;
}

let mut from_block = from_block;
let mut from_block = from_block;

loop {
let to_block = current_block.min(from_block + selfi.logs_block_range);
loop {
let to_block = current_block.min(from_block + self.logs_block_range);

let events = try_s!(
selfi
.payment_sent_events(swap_contract_address, from_block, to_block)
.compat()
.await
);
let events = self
.payment_sent_events(swap_contract_address, from_block, to_block)
.compat()
.await?;

let found = events.iter().find(|event| &event.data.0[..32] == id.as_slice());
let found = events.iter().find(|event| &event.data.0[..32] == id.as_slice());

match found {
Some(event) => {
let transaction = try_s!(
selfi
.transaction(TransactionId::Hash(event.transaction_hash.unwrap()))
.await
);
match transaction {
Some(t) => break Ok(Some(try_s!(signed_tx_from_web3_tx(t)).into())),
None => break Ok(None),
}
},
None => {
if to_block >= current_block {
break Ok(None);
}
from_block = to_block;
},
}
match found {
Some(event) => {
let transaction = try_s!(
self.transaction(TransactionId::Hash(event.transaction_hash.unwrap()))
.await
);
match transaction {
Some(t) => break Ok(Some(try_s!(signed_tx_from_web3_tx(t)).into())),
None => break Ok(None),
}
},
None => {
if to_block >= current_block {
break Ok(None);
}
from_block = to_block;
},
}
};
Box::new(fut.boxed().compat())
}
}

async fn search_for_swap_tx_spend_my(
Expand Down
18 changes: 5 additions & 13 deletions mm2src/coins/eth/eth_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,9 +591,7 @@ fn validate_dex_fee_invalid_sender_eth() {
min_block_number: 0,
uuid: &[],
};
let error = block_on_f01(coin.validate_fee(validate_fee_args))
.unwrap_err()
.into_inner();
let error = block_on(coin.validate_fee(validate_fee_args)).unwrap_err().into_inner();
match error {
ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("was sent from wrong address")),
_ => panic!("Expected `WrongPaymentTx` wrong sender address, found {:?}", error),
Expand Down Expand Up @@ -629,9 +627,7 @@ fn validate_dex_fee_invalid_sender_erc() {
min_block_number: 0,
uuid: &[],
};
let error = block_on_f01(coin.validate_fee(validate_fee_args))
.unwrap_err()
.into_inner();
let error = block_on(coin.validate_fee(validate_fee_args)).unwrap_err().into_inner();
match error {
ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("was sent from wrong address")),
_ => panic!("Expected `WrongPaymentTx` wrong sender address, found {:?}", error),
Expand Down Expand Up @@ -671,9 +667,7 @@ fn validate_dex_fee_eth_confirmed_before_min_block() {
min_block_number: 11784793,
uuid: &[],
};
let error = block_on_f01(coin.validate_fee(validate_fee_args))
.unwrap_err()
.into_inner();
let error = block_on(coin.validate_fee(validate_fee_args)).unwrap_err().into_inner();
match error {
ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min_block")),
_ => panic!("Expected `WrongPaymentTx` early confirmation, found {:?}", error),
Expand Down Expand Up @@ -712,9 +706,7 @@ fn validate_dex_fee_erc_confirmed_before_min_block() {
min_block_number: 11823975,
uuid: &[],
};
let error = block_on_f01(coin.validate_fee(validate_fee_args))
.unwrap_err()
.into_inner();
let error = block_on(coin.validate_fee(validate_fee_args)).unwrap_err().into_inner();
match error {
ValidatePaymentError::WrongPaymentTx(err) => assert!(err.contains("confirmed before min_block")),
_ => panic!("Expected `WrongPaymentTx` early confirmation, found {:?}", error),
Expand Down Expand Up @@ -838,7 +830,7 @@ fn polygon_check_if_my_payment_sent() {
amount: &BigDecimal::default(),
payment_instructions: &None,
};
let my_payment = block_on_f01(coin.check_if_my_payment_sent(if_my_payment_sent_args))
let my_payment = block_on(coin.check_if_my_payment_sent(if_my_payment_sent_args))
.unwrap()
.unwrap();
let expected_hash = BytesJson::from("69a20008cea0c15ee483b5bbdff942752634aa072dfd2ff715fe87eec302de11");
Expand Down
56 changes: 26 additions & 30 deletions mm2src/coins/lightning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,14 @@ 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], _dex_fee: DexFee, _uuid: &[u8], _expire_at: u64) -> TransactionFut {
let fut = async move { Ok(TransactionEnum::LightningPayment(PaymentHash([1; 32]))) };
Box::new(fut.boxed().compat())
async fn send_taker_fee(
&self,
_fee_addr: &[u8],
_dex_fee: DexFee,
_uuid: &[u8],
_expire_at: u64,
) -> TransactionResult {
Ok(TransactionEnum::LightningPayment(PaymentHash([1; 32])))
}

async fn send_maker_payment(&self, maker_payment_args: SendPaymentArgs<'_>) -> TransactionResult {
Expand All @@ -626,23 +631,19 @@ impl SwapOps for LightningCoin {
Ok(payment.payment_hash.into())
}

fn send_taker_payment(&self, taker_payment_args: SendPaymentArgs<'_>) -> TransactionFut {
async fn send_taker_payment(&self, taker_payment_args: SendPaymentArgs<'_>) -> TransactionResult {
let invoice = match taker_payment_args.payment_instructions.clone() {
Some(PaymentInstructions::Lightning(invoice)) => invoice,
_ => try_tx_fus!(ERR!("Invalid instructions, ligntning invoice is expected")),
_ => try_tx_s!(ERR!("Invalid instructions, ligntning invoice is expected")),
};

let max_total_cltv_expiry_delta = self
.estimate_blocks_from_duration(taker_payment_args.time_lock_duration)
.try_into()
.expect("max_total_cltv_expiry_delta shouldn't exceed u32::MAX");
let coin = self.clone();
let fut = async move {
// Todo: The path/s used is already logged when PaymentPathSuccessful/PaymentPathFailed events are fired, it might be better to save it to the DB and retrieve it with the payment info.
let payment = try_tx_s!(coin.pay_invoice(invoice, Some(max_total_cltv_expiry_delta)).await);
Ok(payment.payment_hash.into())
};
Box::new(fut.boxed().compat())
// Todo: The path/s used is already logged when PaymentPathSuccessful/PaymentPathFailed events are fired, it might be better to save it to the DB and retrieve it with the payment info.
let payment = try_tx_s!(self.pay_invoice(invoice, Some(max_total_cltv_expiry_delta)).await);
Ok(payment.payment_hash.into())
}

#[inline]
Expand Down Expand Up @@ -680,9 +681,7 @@ impl SwapOps for LightningCoin {
}

// Todo: This validates the dummy fee 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 validate_fee(&self, _validate_fee_args: ValidateFeeArgs<'_>) -> ValidatePaymentFut<()> {
Box::new(futures01::future::ok(()))
}
async fn validate_fee(&self, _validate_fee_args: ValidateFeeArgs<'_>) -> ValidatePaymentResult<()> { Ok(()) }

#[inline]
async fn validate_maker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentResult<()> {
Expand All @@ -694,29 +693,26 @@ impl SwapOps for LightningCoin {
self.validate_swap_payment(input).compat().await
}

fn check_if_my_payment_sent(
async fn check_if_my_payment_sent(
&self,
if_my_payment_sent_args: CheckIfMyPaymentSentArgs<'_>,
) -> Box<dyn Future<Item = Option<TransactionEnum>, Error = String> + Send> {
) -> Result<Option<TransactionEnum>, String> {
let invoice = match if_my_payment_sent_args.payment_instructions.clone() {
Some(PaymentInstructions::Lightning(invoice)) => invoice,
_ => try_f!(ERR!("Invalid instructions, ligntning invoice is expected")),
_ => return ERR!("Invalid instructions, ligntning invoice is expected"),
};

let payment_hash = PaymentHash((invoice.payment_hash()).into_inner());
let payment_hex = hex::encode(payment_hash.0);
let coin = self.clone();
let fut = async move {
match coin.db.get_payment_from_db(payment_hash).await {
Ok(maybe_payment) => Ok(maybe_payment.map(|p| p.payment_hash.into())),
Err(e) => ERR!(
"Unable to check if payment {} is in db or not error: {}",
payment_hex,
e
),
}
};
Box::new(fut.boxed().compat())

match self.db.get_payment_from_db(payment_hash).await {
Ok(maybe_payment) => Ok(maybe_payment.map(|p| p.payment_hash.into())),
Err(e) => ERR!(
"Unable to check if payment {} is in db or not error: {}",
payment_hex,
e
),
}
}

// Todo: need to also check on-chain spending
Expand Down
21 changes: 10 additions & 11 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,11 +1069,11 @@ 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], dex_fee: DexFee, uuid: &[u8], expire_at: u64) -> TransactionFut;
async fn send_taker_fee(&self, fee_addr: &[u8], dex_fee: DexFee, uuid: &[u8], expire_at: u64) -> TransactionResult;

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

fn send_taker_payment(&self, taker_payment_args: SendPaymentArgs<'_>) -> TransactionFut;
async fn send_taker_payment(&self, taker_payment_args: SendPaymentArgs<'_>) -> TransactionResult;

async fn send_maker_spends_taker_payment(
&self,
Expand All @@ -1089,16 +1089,16 @@ pub trait SwapOps {

async fn send_maker_refunds_payment(&self, maker_refunds_payment_args: RefundPaymentArgs<'_>) -> TransactionResult;

fn validate_fee(&self, validate_fee_args: ValidateFeeArgs<'_>) -> ValidatePaymentFut<()>;
async fn validate_fee(&self, validate_fee_args: ValidateFeeArgs<'_>) -> ValidatePaymentResult<()>;

async fn validate_maker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentResult<()>;

async fn validate_taker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentResult<()>;

fn check_if_my_payment_sent(
async fn check_if_my_payment_sent(
&self,
if_my_payment_sent_args: CheckIfMyPaymentSentArgs<'_>,
) -> Box<dyn Future<Item = Option<TransactionEnum>, Error = String> + Send>;
) -> Result<Option<TransactionEnum>, String>;

async fn search_for_swap_tx_spend_my(
&self,
Expand All @@ -1122,14 +1122,13 @@ pub trait SwapOps {
/// Whether the refund transaction can be sent now
/// For example: there are no additional conditions for ETH, but for some UTXO coins we should wait for
/// locktime < MTP
fn can_refund_htlc(&self, locktime: u64) -> Box<dyn Future<Item = CanRefundHtlc, Error = String> + Send + '_> {
async fn can_refund_htlc(&self, locktime: u64) -> Result<CanRefundHtlc, String> {
let now = now_sec();
let result = if now > locktime {
CanRefundHtlc::CanRefundNow
if now > locktime {
Ok(CanRefundHtlc::CanRefundNow)
} else {
CanRefundHtlc::HaveToWait(locktime - now + 1)
};
Box::new(futures01::future::ok(result))
Ok(CanRefundHtlc::HaveToWait(locktime - now + 1))
}
}

/// Whether the swap payment is refunded automatically or not when the locktime expires, or the other side fails the HTLC.
Expand Down
Loading

0 comments on commit df3d39c

Please sign in to comment.