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

refactor(SwapOps): make all methods async #2251

Merged
merged 5 commits into from
Oct 24, 2024
Merged
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
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
Loading