Skip to content

Commit

Permalink
chore: further changes and test
Browse files Browse the repository at this point in the history
  • Loading branch information
im-adithya committed Dec 13, 2023
1 parent 59918a6 commit 9b18faf
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 11 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,10 @@ You can also contribute to our [bounty program](https://github.com/getAlby/light
- ⚠️ invoice in response missing (TODO)
- ⚠️ response does not match spec, missing fields

`pay_keysend`
`list_transactions`
- ⚠️ from and until in request not supported

`list_transactions`
`pay_keysend`

`multi_pay_invoice (TBC)`

Expand All @@ -167,9 +168,10 @@ You can also contribute to our [bounty program](https://github.com/getAlby/light
- ⚠️ invoice in response missing (TODO)
- ⚠️ response does not match spec, missing fields (TODO)

`pay_keysend`
`list_transactions`
- ⚠️ offset and unpaid in request not supported

`list_transactions`
`pay_keysend`

`multi_pay_invoice (TBC)`

Expand Down
47 changes: 42 additions & 5 deletions lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,58 @@ func (svc *LNDService) ListTransactions(ctx context.Context, senderPubkey string
if err != nil {
return nil, err
}
resp, err := svc.client.ListInvoices(ctx, &lnrpc.ListInvoiceRequest{NumMaxInvoices: maxInvoices, IndexOffset: indexOffset})
if err != nil {
return nil, err
// Fetch Incoming Payments
var incomingInvoices []*lnrpc.Invoice
if invoiceType == "" || invoiceType == "incoming" {
incomingResp, err := svc.client.ListInvoices(ctx, &lnrpc.ListInvoiceRequest{NumMaxInvoices: maxInvoices, IndexOffset: indexOffset})
if err != nil {
return nil, err
}
incomingInvoices = incomingResp.Invoices

if unpaid {
incomingUnpaidResp, err := svc.client.ListInvoices(ctx, &lnrpc.ListInvoiceRequest{NumMaxInvoices: maxInvoices, IndexOffset: indexOffset, PendingOnly: true})
if err != nil {
return nil, err
}
incomingInvoices = append(incomingInvoices, incomingUnpaidResp.Invoices...)
}
}

for _, inv := range resp.Invoices {
for _, inv := range incomingInvoices {
invoice := Invoice{
Type: "incoming",
Invoice: inv.PaymentRequest,
Description: inv.Memo,
DescriptionHash: hex.EncodeToString(inv.DescriptionHash),
Preimage: hex.EncodeToString(inv.RPreimage),
PaymentHash: hex.EncodeToString(inv.RHash),
Amount: inv.ValueMsat,
FeesPaid: inv.AmtPaidMsat,
CreatedAt: time.Unix(inv.CreationDate, 0),
SettledAt: time.Unix(inv.SettleDate, 0),
ExpiresAt: time.Unix(inv.CreationDate+inv.Expiry, 0),
}
invoices = append(invoices, invoice)
}
// Fetch Outgoing Invoices
var outgoingInvoices []*lnrpc.Payment
if invoiceType == "" || invoiceType == "incoming" {
// Not just pending but failed payments will also be included because of IncludeIncomplete
outgoingResp, err := svc.client.ListPayments(ctx, &lnrpc.ListPaymentsRequest{MaxPayments: maxInvoices, IndexOffset: indexOffset, IncludeIncomplete: unpaid})
if err != nil {
return nil, err
}
outgoingInvoices = outgoingResp.Payments
}
for _, inv := range outgoingInvoices {
invoice := Invoice{
Type: "outgoing",
Invoice: inv.PaymentRequest,
Preimage: inv.PaymentPreimage,
PaymentHash: inv.PaymentHash,
Amount: inv.ValueMsat,
FeesPaid: inv.FeeMsat,
CreatedAt: time.Unix(0, inv.CreationTimeNs),
}
invoices = append(invoices, invoice)
}
Expand Down
4 changes: 4 additions & 0 deletions lnd/lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func (wrapper *LNDWrapper) ListInvoices(ctx context.Context, req *lnrpc.ListInvo
return wrapper.client.ListInvoices(ctx, req, options...)
}

func (wrapper *LNDWrapper) ListPayments(ctx context.Context, req *lnrpc.ListPaymentsRequest, options ...grpc.CallOption) (*lnrpc.ListPaymentsResponse, error) {
return wrapper.client.ListPayments(ctx, req, options...)
}

func (wrapper *LNDWrapper) LookupInvoice(ctx context.Context, req *lnrpc.PaymentHash, options ...grpc.CallOption) (*lnrpc.Invoice, error) {
return wrapper.client.LookupInvoice(ctx, req, options...)
}
Expand Down
2 changes: 2 additions & 0 deletions models.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ type Invoice struct {
PaymentHash string `json:"payment_hash"`
Amount int64 `json:"amount"`
FeesPaid int64 `json:"fees_paid"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
SettledAt time.Time `json:"settled_at"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
Expand Down
66 changes: 64 additions & 2 deletions service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ const nip47LookupInvoiceJson = `
}
}
`
const nip47ListTransactionsJson = `
{
"method": "list_transactions",
"params": {
"from": 1693876973,
"until": 1694876973,
"limit": 10,
"offset": 0,
"type": "incoming"
}
}
`
const nip47PayJson = `
{
"method": "pay_invoice",
Expand Down Expand Up @@ -85,28 +97,30 @@ var mockNodeInfo = NodeInfo{

var mockInvoices = []Invoice{
{
Type: "incoming",
Invoice: mockInvoice,
Description: "mock invoice 1",
DescriptionHash: "hash1",
Preimage: "preimage1",
PaymentHash: "payment_hash_1",
Amount: 1000,
FeesPaid: 50,
SettledAt: time.Now(),
SettledAt: time.Unix(1693876963, 0),
Metadata: map[string]interface{}{
"key1": "value1",
"key2": 42,
},
},
{
Type: "incoming",
Invoice: mockInvoice,
Description: "mock invoice 2",
DescriptionHash: "hash2",
Preimage: "preimage2",
PaymentHash: "payment_hash_2",
Amount: 2000,
FeesPaid: 75,
SettledAt: time.Now(),
SettledAt: time.Unix(1693876965, 0),
},
}

Expand Down Expand Up @@ -432,6 +446,54 @@ func TestHandleEvent(t *testing.T) {
assert.Equal(t, mockInvoice, received.Result.(*Nip47LookupInvoiceResponse).Invoice)
assert.Equal(t, false, received.Result.(*Nip47LookupInvoiceResponse).Paid)

// list_transactions: without permission
newPayload, err = nip04.Encrypt(nip47ListTransactionsJson, ss)
assert.NoError(t, err)
res, err = svc.HandleEvent(ctx, &nostr.Event{
ID: "test_list_transactions_event_1",
Kind: NIP_47_REQUEST_KIND,
PubKey: senderPubkey,
Content: newPayload,
})
assert.NoError(t, err)
assert.NotNil(t, res)
decrypted, err = nip04.Decrypt(res.Content, ss)
assert.NoError(t, err)
received = &Nip47Response{}
err = json.Unmarshal([]byte(decrypted), received)
assert.NoError(t, err)
assert.Equal(t, NIP_47_ERROR_RESTRICTED, received.Error.Code)
assert.NotNil(t, res)

// list_transactions: with permission
err = svc.db.Model(&AppPermission{}).Where("app_id = ?", app.ID).Update("request_method", NIP_47_LIST_TRANSACTIONS_METHOD).Error
assert.NoError(t, err)
res, err = svc.HandleEvent(ctx, &nostr.Event{
ID: "test_list_transactions_event_2",
Kind: NIP_47_REQUEST_KIND,
PubKey: senderPubkey,
Content: newPayload,
})
assert.NoError(t, err)
assert.NotNil(t, res)
decrypted, err = nip04.Decrypt(res.Content, ss)
assert.NoError(t, err)
received = &Nip47Response{
Result: &Nip47ListTransactionsResponse{},
}
err = json.Unmarshal([]byte(decrypted), received)
assert.NoError(t, err)
assert.Equal(t, 2, len(received.Result.(*Nip47ListTransactionsResponse).Transactions))
transaction := received.Result.(*Nip47ListTransactionsResponse).Transactions[0]
assert.Equal(t, mockInvoices[0].Type, transaction.Type)
assert.Equal(t, mockInvoices[0].Invoice, transaction.Invoice)
assert.Equal(t, mockInvoices[0].Description, transaction.Description)
assert.Equal(t, mockInvoices[0].DescriptionHash, transaction.DescriptionHash)
assert.Equal(t, mockInvoices[0].Preimage, transaction.Preimage)
assert.Equal(t, mockInvoices[0].PaymentHash, transaction.PaymentHash)
assert.Equal(t, mockInvoices[0].Amount, transaction.Amount)
assert.Equal(t, mockInvoices[0].FeesPaid, transaction.FeesPaid)
assert.Equal(t, mockInvoices[0].SettledAt, transaction.SettledAt)
// get info: without permission
newPayload, err = nip04.Encrypt(nip47GetInfoJson, ss)
assert.NoError(t, err)
Expand Down

0 comments on commit 9b18faf

Please sign in to comment.