Payment lifecycle (#184)

* Rename swap tables: remove ongoing_ prefix

* Add swap status enums and filtering

* Swap-in: add claim_txid

* Swap-out: add claim_txid

* resolve_swap: Don't remove swap when complete

* Fixups after rebase

* Remove unused method

* Consider payment as pending based on confirmations

An onchain payment with no confirmations is considered
pending. The previous logic of converting pending swaps
into pending payments is removed, since we may have
pending swaps that should not result in pending
payments (for example on Receive, before the invoice
is paid).

* Fix swap-in query

* GetInfoResponse: fix balance, include pending

* Remove unused method

* Re-generate flutter bridge files

* Re-generate RN bindings

* Fix payment_type detection in list_payments

* Send: persist to DB when claim tx is seen

* Receive: fix occasional error when broadcasting claim

* Remove fixed TODO

* Receive: only rescan on testnet, where Electrum is used to broadcast

* Log more details when broadcasting fails

* Improve AlreadyClaimed error detection and handling

* Rename SubmarineSwapStatus::Initial to Created

* Split pending payment types into separate field status

* Rename swap status enums

* Fix INSERT query

* Bump lwk libraries

* Simplify Receive try_handle_reverse_swap_status loop

* Change resolve_swap to insert_or_update_payment

* Refactor payment data persistence

* Remove unused dependency

* Bump LWK dependencies

* Rename reconcile_payments_with_onchain

* Rename try_claim_v2

* Rename address() to next_unused_address()

* Move all claim persistence writes in try_claim

* Flatten Payment struct

* Re-generate bindings

* Expose sync() in service interface

* Set Send ws stream as nonblocking, use singleton stream

* Send_payment: sync() before handling new state

* Sync() on sdk.connect()

* Remove unused args from list_payments()

* Receive: rename DB field redeem_script to response JSON

* Convert to and from internal structs to persist CreateResponse JSON

* De-duplicate internal CreateResponse structs to prevent storing same field twice

* Schedule a periodic sync() thread on startup

* Persist swap states and add methods to transition between them

* Handle unwrap() when subscribing for WS updates

* Status Stream: handle remaining unwraps() and TODOs

* Consolidate status transitions into two SDK methods

* Status Stream: reconnect and resume tracking on disconnect

* Remove superfluous TODO

* Send swaps: correctly transition to Complete even if app killed during send_payment()

* State transitions: Move SQL queries to persistence layer

* Send: handle edge TransactionClaimed edge-case

* Send: mark as Complete after we check the preimage

* Send: remove marking as Complete on TransactionClaimed
This commit is contained in:
ok300
2024-05-22 20:00:38 +00:00
committed by GitHub
parent ce24aef3c8
commit c975da5b3c
32 changed files with 2050 additions and 1036 deletions

View File

@@ -50,9 +50,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
RestoreRequest dco_decode_box_autoadd_restore_request(dynamic raw);
@protected
int dco_decode_box_autoadd_u_32(dynamic raw);
@protected
int dco_decode_box_autoadd_u_64(dynamic raw);
@@ -78,10 +75,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
Network dco_decode_network(dynamic raw);
@protected
String? dco_decode_opt_String(dynamic raw);
NewSwapState dco_decode_new_swap_state(dynamic raw);
@protected
int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
String? dco_decode_opt_String(dynamic raw);
@protected
int? dco_decode_opt_box_autoadd_u_64(dynamic raw);
@@ -158,9 +155,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
RestoreRequest sse_decode_box_autoadd_restore_request(SseDeserializer deserializer);
@protected
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
@protected
int sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
@@ -186,10 +180,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
Network sse_decode_network(SseDeserializer deserializer);
@protected
String? sse_decode_opt_String(SseDeserializer deserializer);
NewSwapState sse_decode_new_swap_state(SseDeserializer deserializer);
@protected
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
String? sse_decode_opt_String(SseDeserializer deserializer);
@protected
int? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
@@ -308,12 +302,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
return ptr;
}
@protected
ffi.Pointer<ffi.Uint32> cst_encode_box_autoadd_u_32(int raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
return wire.cst_new_box_autoadd_u_32(cst_encode_u_32(raw));
}
@protected
ffi.Pointer<ffi.Uint64> cst_encode_box_autoadd_u_64(int raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
@@ -344,12 +332,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
return raw == null ? ffi.nullptr : cst_encode_String(raw);
}
@protected
ffi.Pointer<ffi.Uint32> cst_encode_opt_box_autoadd_u_32(int? raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
return raw == null ? ffi.nullptr : cst_encode_box_autoadd_u_32(raw);
}
@protected
ffi.Pointer<ffi.Uint64> cst_encode_opt_box_autoadd_u_64(int? raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
@@ -419,17 +401,20 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void cst_api_fill_to_wire_get_info_response(GetInfoResponse apiObj, wire_cst_get_info_response wireObj) {
wireObj.balance_sat = cst_encode_u_64(apiObj.balanceSat);
wireObj.pending_send_sat = cst_encode_u_64(apiObj.pendingSendSat);
wireObj.pending_receive_sat = cst_encode_u_64(apiObj.pendingReceiveSat);
wireObj.pubkey = cst_encode_String(apiObj.pubkey);
}
@protected
void cst_api_fill_to_wire_payment(Payment apiObj, wire_cst_payment wireObj) {
wireObj.id = cst_encode_opt_String(apiObj.id);
wireObj.timestamp = cst_encode_opt_box_autoadd_u_32(apiObj.timestamp);
wireObj.tx_id = cst_encode_String(apiObj.txId);
wireObj.swap_id = cst_encode_opt_String(apiObj.swapId);
wireObj.timestamp = cst_encode_u_32(apiObj.timestamp);
wireObj.amount_sat = cst_encode_u_64(apiObj.amountSat);
wireObj.fees_sat = cst_encode_opt_box_autoadd_u_64(apiObj.feesSat);
wireObj.payment_type = cst_encode_payment_type(apiObj.paymentType);
wireObj.invoice = cst_encode_opt_String(apiObj.invoice);
wireObj.status = cst_encode_new_swap_state(apiObj.status);
}
@protected
@@ -480,10 +465,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
}
if (apiObj is PaymentError_Refunded) {
var pre_err = cst_encode_String(apiObj.err);
var pre_txid = cst_encode_String(apiObj.txid);
var pre_refund_tx_id = cst_encode_String(apiObj.refundTxId);
wireObj.tag = 10;
wireObj.kind.Refunded.err = pre_err;
wireObj.kind.Refunded.txid = pre_txid;
wireObj.kind.Refunded.refund_tx_id = pre_refund_tx_id;
return;
}
if (apiObj is PaymentError_SendError) {
@@ -553,6 +538,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
int cst_encode_network(Network raw);
@protected
int cst_encode_new_swap_state(NewSwapState raw);
@protected
int cst_encode_payment_type(PaymentType raw);
@@ -595,9 +583,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_box_autoadd_restore_request(RestoreRequest self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_u_64(int self, SseSerializer serializer);
@@ -623,10 +608,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
void sse_encode_network(Network self, SseSerializer serializer);
@protected
void sse_encode_opt_String(String? self, SseSerializer serializer);
void sse_encode_new_swap_state(NewSwapState self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer);
void sse_encode_opt_String(String? self, SseSerializer serializer);
@protected
void sse_encode_opt_box_autoadd_u_64(int? self, SseSerializer serializer);
@@ -767,20 +752,15 @@ class RustLibWire implements BaseWire {
void wire_list_payments(
int port_,
bool with_scan,
bool include_pending,
) {
return _wire_list_payments(
port_,
with_scan,
include_pending,
);
}
late final _wire_list_paymentsPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.Bool, ffi.Bool)>>(
'frbgen_breez_liquid_wire_list_payments');
late final _wire_list_payments = _wire_list_paymentsPtr.asFunction<void Function(int, bool, bool)>();
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>('frbgen_breez_liquid_wire_list_payments');
late final _wire_list_payments = _wire_list_paymentsPtr.asFunction<void Function(int)>();
void wire_prepare_receive_payment(
int port_,
@@ -932,20 +912,6 @@ class RustLibWire implements BaseWire {
late final _cst_new_box_autoadd_restore_request =
_cst_new_box_autoadd_restore_requestPtr.asFunction<ffi.Pointer<wire_cst_restore_request> Function()>();
ffi.Pointer<ffi.Uint32> cst_new_box_autoadd_u_32(
int value,
) {
return _cst_new_box_autoadd_u_32(
value,
);
}
late final _cst_new_box_autoadd_u_32Ptr =
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Uint32> Function(ffi.Uint32)>>(
'frbgen_breez_liquid_cst_new_box_autoadd_u_32');
late final _cst_new_box_autoadd_u_32 =
_cst_new_box_autoadd_u_32Ptr.asFunction<ffi.Pointer<ffi.Uint32> Function(int)>();
ffi.Pointer<ffi.Uint64> cst_new_box_autoadd_u_64(
int value,
) {
@@ -1055,9 +1021,12 @@ final class wire_cst_prepare_send_response extends ffi.Struct {
}
final class wire_cst_payment extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> id;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> tx_id;
external ffi.Pointer<ffi.Uint32> timestamp;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> swap_id;
@ffi.Uint32()
external int timestamp;
@ffi.Uint64()
external int amount_sat;
@@ -1067,7 +1036,8 @@ final class wire_cst_payment extends ffi.Struct {
@ffi.Int32()
external int payment_type;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> invoice;
@ffi.Int32()
external int status;
}
final class wire_cst_list_payment extends ffi.Struct {
@@ -1081,6 +1051,12 @@ final class wire_cst_get_info_response extends ffi.Struct {
@ffi.Uint64()
external int balance_sat;
@ffi.Uint64()
external int pending_send_sat;
@ffi.Uint64()
external int pending_receive_sat;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> pubkey;
}
@@ -1095,7 +1071,7 @@ final class wire_cst_PaymentError_LwkError extends ffi.Struct {
final class wire_cst_PaymentError_Refunded extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> txid;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> refund_tx_id;
}
final class wire_cst_PaymentError_SendError extends ffi.Struct {