Return pending payment (#245)

* Return pending payment

* Simplify select loop

* Revert dart pubspec

* Add error logging for payment events without swap ids

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>
This commit is contained in:
Ross Savage
2024-05-30 17:59:35 +02:00
committed by GitHub
parent 9554dcad19
commit dd00a0b328
9 changed files with 139 additions and 47 deletions

View File

@@ -59,6 +59,9 @@ pub enum PaymentError {
#[error("Boltz did not return any pairs from the request")]
PairsNotFound,
#[error("The payment timed out")]
PaymentTimeout,
#[error("Could not store the swap details locally")]
PersistError,

View File

@@ -326,21 +326,22 @@ impl CstDecode<crate::error::PaymentError> for wire_cst_payment_error {
}
}
8 => crate::error::PaymentError::PairsNotFound,
9 => crate::error::PaymentError::PersistError,
10 => {
9 => crate::error::PaymentError::PaymentTimeout,
10 => crate::error::PaymentError::PersistError,
11 => {
let ans = unsafe { self.kind.Refunded };
crate::error::PaymentError::Refunded {
err: ans.err.cst_decode(),
refund_tx_id: ans.refund_tx_id.cst_decode(),
}
}
11 => {
12 => {
let ans = unsafe { self.kind.SendError };
crate::error::PaymentError::SendError {
err: ans.err.cst_decode(),
}
}
12 => {
13 => {
let ans = unsafe { self.kind.SignerError };
crate::error::PaymentError::SignerError {
err: ans.err.cst_decode(),

View File

@@ -821,9 +821,12 @@ impl SseDecode for crate::error::PaymentError {
return crate::error::PaymentError::PairsNotFound;
}
9 => {
return crate::error::PaymentError::PersistError;
return crate::error::PaymentError::PaymentTimeout;
}
10 => {
return crate::error::PaymentError::PersistError;
}
11 => {
let mut var_err = <String>::sse_decode(deserializer);
let mut var_refundTxId = <String>::sse_decode(deserializer);
return crate::error::PaymentError::Refunded {
@@ -831,11 +834,11 @@ impl SseDecode for crate::error::PaymentError {
refund_tx_id: var_refundTxId,
};
}
11 => {
12 => {
let mut var_err = <String>::sse_decode(deserializer);
return crate::error::PaymentError::SendError { err: var_err };
}
12 => {
13 => {
let mut var_err = <String>::sse_decode(deserializer);
return crate::error::PaymentError::SignerError { err: var_err };
}
@@ -1258,18 +1261,19 @@ impl flutter_rust_bridge::IntoDart for crate::error::PaymentError {
[7.into_dart(), err.into_into_dart().into_dart()].into_dart()
}
crate::error::PaymentError::PairsNotFound => [8.into_dart()].into_dart(),
crate::error::PaymentError::PersistError => [9.into_dart()].into_dart(),
crate::error::PaymentError::PaymentTimeout => [9.into_dart()].into_dart(),
crate::error::PaymentError::PersistError => [10.into_dart()].into_dart(),
crate::error::PaymentError::Refunded { err, refund_tx_id } => [
10.into_dart(),
11.into_dart(),
err.into_into_dart().into_dart(),
refund_tx_id.into_into_dart().into_dart(),
]
.into_dart(),
crate::error::PaymentError::SendError { err } => {
[11.into_dart(), err.into_into_dart().into_dart()].into_dart()
[12.into_dart(), err.into_into_dart().into_dart()].into_dart()
}
crate::error::PaymentError::SignerError { err } => {
[12.into_dart(), err.into_into_dart().into_dart()].into_dart()
[13.into_dart(), err.into_into_dart().into_dart()].into_dart()
}
}
}
@@ -1753,20 +1757,23 @@ impl SseEncode for crate::error::PaymentError {
crate::error::PaymentError::PairsNotFound => {
<i32>::sse_encode(8, serializer);
}
crate::error::PaymentError::PersistError => {
crate::error::PaymentError::PaymentTimeout => {
<i32>::sse_encode(9, serializer);
}
crate::error::PaymentError::Refunded { err, refund_tx_id } => {
crate::error::PaymentError::PersistError => {
<i32>::sse_encode(10, serializer);
}
crate::error::PaymentError::Refunded { err, refund_tx_id } => {
<i32>::sse_encode(11, serializer);
<String>::sse_encode(err, serializer);
<String>::sse_encode(refund_tx_id, serializer);
}
crate::error::PaymentError::SendError { err } => {
<i32>::sse_encode(11, serializer);
<i32>::sse_encode(12, serializer);
<String>::sse_encode(err, serializer);
}
crate::error::PaymentError::SignerError { err } => {
<i32>::sse_encode(12, serializer);
<i32>::sse_encode(13, serializer);
<String>::sse_encode(err, serializer);
}
}

View File

@@ -1019,6 +1019,7 @@ impl LiquidSdk {
})?;
let swap_id = &create_response.id;
let accept_zero_conf = create_response.accept_zero_conf;
let create_response_json = SendSwap::from_boltz_struct_to_json(&create_response, swap_id)?;
let payer_amount_sat = req.fees_sat + receiver_amount_sat;
@@ -1035,28 +1036,55 @@ impl LiquidSdk {
refund_private_key: keypair.display_secret().to_string(),
};
self.persister.insert_send_swap(&swap)?;
let mut events_stream = self.event_manager.subscribe();
self.status_stream.track_swap_id(swap_id)?;
self.wait_for_payment(swap.id, accept_zero_conf)
.await
.map(|payment| SendPaymentResponse { payment })
}
async fn wait_for_payment(
&self,
swap_id: String,
accept_zero_conf: bool,
) -> Result<Payment, PaymentError> {
let timeout_fut = tokio::time::sleep(Duration::from_secs(15));
tokio::pin!(timeout_fut);
let mut events_stream = self.event_manager.subscribe();
let mut maybe_payment: Option<Payment> = None;
loop {
match events_stream.recv().await {
Ok(LiquidSdkEvent::PaymentFailed { details }) => match details.swap_id {
Some(id) if id == swap.id => {
return Err(PaymentError::SendError {
err: "Payment failed".to_string(),
})
}
_ => (),
tokio::select! {
_ = &mut timeout_fut => match maybe_payment {
Some(payment) => return Ok(payment),
None => return Err(PaymentError::PaymentTimeout),
},
Ok(LiquidSdkEvent::PaymentSucceed { details }) => match details.swap_id.clone() {
Some(id) if id == swap.id => {
return Ok(SendPaymentResponse { payment: details })
}
_ => (),
},
Ok(event) => debug!("Unhandled event: {event:?}"),
Err(e) => debug!("Received error waiting for event: {e:?}"),
event = events_stream.recv() => match event {
Ok(LiquidSdkEvent::PaymentPending { details }) => match details.swap_id.clone() {
Some(id) if id == swap_id => match accept_zero_conf {
true => {
debug!("Received Send Payment pending event with zero-conf accepted");
return Ok(details)
}
false => {
debug!("Received Send Payment pending event, waiting for confirmation");
maybe_payment = Some(details);
}
},
_ => error!("Received Send Payment pending event for payment without swap ID"),
},
Ok(LiquidSdkEvent::PaymentSucceed { details }) => match details.swap_id.clone()
{
Some(id) if id == swap_id => {
debug!("Received Send Payment succeed event");
return Ok(details);
}
_ => error!("Received Send Payment succeed event for payment without swap ID"),
},
Ok(event) => debug!("Unhandled event: {event:?}"),
Err(e) => debug!("Received error waiting for event: {e:?}"),
}
}
}
}