diff --git a/lndclient/lightning_client.go b/lndclient/lightning_client.go index 244a78d..de1c3e1 100644 --- a/lndclient/lightning_client.go +++ b/lndclient/lightning_client.go @@ -62,6 +62,10 @@ type LightningClient interface { ListInvoices(ctx context.Context, req ListInvoicesRequest) ( *ListInvoicesResponse, error) + // ListPayments makes a paginated call to our list payments endpoint. + ListPayments(ctx context.Context, + req ListPaymentsRequest) (*ListPaymentsResponse, error) + // ChannelBackup retrieves the backup for a particular channel. The // backup is returned as an encrypted chanbackup.Single payload. ChannelBackup(context.Context, wire.OutPoint) ([]byte, error) @@ -1022,6 +1026,121 @@ func (s *lightningClient) ListInvoices(ctx context.Context, }, nil } +// Payment represents a payment made by our node. +type Payment struct { + // Hash is the payment hash used. + Hash lntypes.Hash + + // Preimage is the preimage of the payment. It will have a non-nil value + // if the payment is settled. + Preimage *lntypes.Preimage + + // Amount is the amount in millisatoshis of the payment. + Amount lnwire.MilliSatoshi + + // Fee is the amount in millisatoshis that was paid in fees. + Fee lnwire.MilliSatoshi + + // Status describes the state of a payment. + Status *PaymentStatus + + // Htlcs is the set of htlc attempts made by the payment. + Htlcs []*lnrpc.HTLCAttempt + + // SequenceNumber is a unique id for each payment. + SequenceNumber uint64 +} + +// ListPaymentsRequest contains the request parameters for a paginated +// list payments call. +type ListPaymentsRequest struct { + // MaxPayments is the maximum number of payments to return. + MaxPayments uint64 + + // Offset is the index from which to start querying. + Offset uint64 + + // Reversed is set to query our payments backwards. + Reversed bool + + // IncludeIncomplete is set if we want to include incomplete payments. + IncludeIncomplete bool +} + +// ListPaymentsResponse contains the response to a list payments query, +// including the index offsets required for paginated queries. +type ListPaymentsResponse struct { + // FirstIndexOffset is the index offset of the first item in our set. + FirstIndexOffset uint64 + + // LastIndexOffset is the index offset of the last item in our set. + LastIndexOffset uint64 + + // Payments is the set of invoices that were returned. + Payments []Payment +} + +// ListPayments makes a paginated call to our listpayments endpoint. +func (s *lightningClient) ListPayments(ctx context.Context, + req ListPaymentsRequest) (*ListPaymentsResponse, error) { + + rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout) + defer cancel() + + resp, err := s.client.ListPayments( + s.adminMac.WithMacaroonAuth(rpcCtx), + &lnrpc.ListPaymentsRequest{ + IncludeIncomplete: req.IncludeIncomplete, + IndexOffset: req.Offset, + MaxPayments: req.MaxPayments, + Reversed: req.Reversed, + }) + if err != nil { + return nil, err + } + + payments := make([]Payment, len(resp.Payments)) + for i, payment := range resp.Payments { + hash, err := lntypes.MakeHashFromStr(payment.PaymentHash) + if err != nil { + return nil, err + } + + status, err := unmarshallPaymentStatus(payment) + if err != nil { + return nil, err + } + + pmt := Payment{ + Hash: hash, + Status: status, + Htlcs: payment.Htlcs, + Amount: lnwire.MilliSatoshi(payment.ValueMsat), + Fee: lnwire.MilliSatoshi(payment.FeeMsat), + SequenceNumber: payment.PaymentIndex, + } + + // Add our preimage if it is known. + if payment.PaymentPreimage != "" { + preimage, err := lntypes.MakePreimageFromStr( + payment.PaymentPreimage, + ) + if err != nil { + return nil, err + } + pmt.Preimage = &preimage + } + + payments[i] = pmt + } + + return &ListPaymentsResponse{ + FirstIndexOffset: resp.FirstIndexOffset, + LastIndexOffset: resp.LastIndexOffset, + Payments: payments, + }, nil +} + // ChannelBackup retrieves the backup for a particular channel. The backup is // returned as an encrypted chanbackup.Single payload. func (s *lightningClient) ChannelBackup(ctx context.Context, diff --git a/test/lightning_client_mock.go b/test/lightning_client_mock.go index d93359c..6b68819 100644 --- a/test/lightning_client_mock.go +++ b/test/lightning_client_mock.go @@ -208,6 +208,16 @@ func (h *mockLightningClient) ListInvoices(_ context.Context, }, nil } +// ListPayments makes a paginated call to our list payments endpoint. +func (h *mockLightningClient) ListPayments(_ context.Context, + _ lndclient.ListPaymentsRequest) (*lndclient.ListPaymentsResponse, + error) { + + return &lndclient.ListPaymentsResponse{ + Payments: h.lnd.Payments, + }, nil +} + // ChannelBackup retrieves the backup for a particular channel. The // backup is returned as an encrypted chanbackup.Single payload. func (h *mockLightningClient) ChannelBackup(context.Context, wire.OutPoint) ([]byte, error) { diff --git a/test/lnd_services_mock.go b/test/lnd_services_mock.go index cf08715..d2e83fd 100644 --- a/test/lnd_services_mock.go +++ b/test/lnd_services_mock.go @@ -166,6 +166,7 @@ type LndMockServices struct { Channels []lndclient.ChannelInfo ClosedChannels []lndclient.ClosedChannel ForwardingEvents []lndclient.ForwardingEvent + Payments []lndclient.Payment WaitForFinished func()