From 2b68664e916ed8cd8b98eda769ca11afaf2d1bcf Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Mon, 21 Aug 2023 18:10:28 +0700 Subject: [PATCH 1/7] feat: lookup invoice (Alby) --- alby.go | 89 ++++++++++++++++++++++- handle_lookup_invoice_request.go | 118 +++++++++++++++++++++++++++++++ lnd.go | 5 ++ models.go | 17 +++++ service.go | 3 + service_test.go | 59 +++++++++++++++- 6 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 handle_lookup_invoice_request.go diff --git a/alby.go b/alby.go index 1b7ff4e3..17d378c3 100644 --- a/alby.go +++ b/alby.go @@ -104,7 +104,7 @@ func (svc *AlbyOAuthService) MakeInvoice(ctx context.Context, senderPubkey strin "description": description, "descriptionHash": descriptionHash, "expiry": expiry, - }).Errorf("App not found: %v", err); + }).Errorf("Value must be 1 sat or greater"); return "", "", errors.New("Value must be 1 sat or greater") } @@ -191,6 +191,93 @@ func (svc *AlbyOAuthService) MakeInvoice(ctx context.Context, senderPubkey strin } } +func (svc *AlbyOAuthService) LookupInvoice(ctx context.Context, senderPubkey string, paymentHash string) (invoice string, paid bool, err error) { + // TODO: move to a shared function + app := App{} + err = svc.db.Preload("User").First(&app, &App{ + NostrPubkey: senderPubkey, + }).Error + if err != nil { + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + }).Errorf("App not found: %v", err) + return "", false, err + } + + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + "appId": app.ID, + "userId": app.User.ID, + }).Info("Processing lookup invoice request") + tok, err := svc.FetchUserToken(ctx, app) + if err != nil { + return "", false, err + } + client := svc.oauthConf.Client(ctx, tok) + + body := bytes.NewBuffer([]byte{}) + + // TODO: move to a shared function + req, err := http.NewRequest("GET", fmt.Sprintf("%s/invoices/%s", svc.cfg.AlbyAPIURL, paymentHash), body) + if err != nil { + svc.Logger.WithError(err).Errorf("Error creating request /invoices/%s", paymentHash) + return "", false, err + } + + req.Header.Set("User-Agent", "NWC") + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + "appId": app.ID, + "userId": app.User.ID, + }).Errorf("Failed to lookup invoice: %v", err) + return "", false, err + } + + if resp.StatusCode == 404 { + // TODO: review + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + "appId": app.ID, + "userId": app.User.ID, + }).Info("Lookup invoice returned not found") + return "", false, nil + } else if resp.StatusCode < 300 { + responsePayload := &LookupInvoiceResponse{} + err = json.NewDecoder(resp.Body).Decode(responsePayload) + if err != nil { + return "", false, err + } + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + "appId": app.ID, + "userId": app.User.ID, + "paymentRequest": responsePayload.PaymentRequest, + "settled": responsePayload.Settled, + }).Info("Lookup invoice successful") + return responsePayload.PaymentRequest, responsePayload.Settled, nil + } else { + errorPayload := &ErrorResponse{} + err = json.NewDecoder(resp.Body).Decode(errorPayload) + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + "appId": app.ID, + "userId": app.User.ID, + "APIHttpStatus": resp.StatusCode, + }).Errorf("Lookup invoice failed %s", string(errorPayload.Message)) + return "", false, errors.New(errorPayload.Message) + } +} + func (svc *AlbyOAuthService) GetBalance(ctx context.Context, senderPubkey string) (balance int64, err error) { app := App{} err = svc.db.Preload("User").First(&app, &App{ diff --git a/handle_lookup_invoice_request.go b/handle_lookup_invoice_request.go new file mode 100644 index 00000000..4f6988dd --- /dev/null +++ b/handle_lookup_invoice_request.go @@ -0,0 +1,118 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + + //"fmt" + + "github.com/nbd-wtf/go-nostr" + decodepay "github.com/nbd-wtf/ln-decodepay" + "github.com/sirupsen/logrus" +) + +func (svc *Service) HandleLookupInvoiceEvent(ctx context.Context, request *Nip47Request, event *nostr.Event, app App, ss []byte) (result *nostr.Event, err error) { + + // TODO: move to a shared function + nostrEvent := NostrEvent{App: app, NostrId: event.ID, Content: event.Content, State: "received"} + insertNostrEventResult := svc.db.Create(&nostrEvent) + if insertNostrEventResult.Error != nil { + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + }).Errorf("Failed to save nostr event: %v", insertNostrEventResult.Error) + return nil, insertNostrEventResult.Error + } + + // TODO: move to a shared function + hasPermission, code, message := svc.hasPermission(&app, event, request.Method, nil) + + if !hasPermission { + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + }).Errorf("App does not have permission: %s %s", code, message) + + return svc.createResponse(event, Nip47Response{Error: &Nip47Error{ + Code: code, + Message: message, + }}, ss) + } + + // TODO: move to a shared generic function + lookupInvoiceParams := &Nip47LookupInvoiceParams{} + err = json.Unmarshal(request.Params, lookupInvoiceParams) + if err != nil { + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + }).Errorf("Failed to decode nostr event: %v", err) + return nil, err + } + + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + "invoice": lookupInvoiceParams.Invoice, + "paymentHash": lookupInvoiceParams.PaymentHash, + }).Info("Looking up invoice") + + paymentHash := lookupInvoiceParams.PaymentHash + + if (paymentHash == "") { + paymentRequest, err := decodepay.Decodepay(lookupInvoiceParams.Invoice) + if err != nil { + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + "invoice": lookupInvoiceParams.Invoice, + }).Errorf("Failed to decode bolt11 invoice: %v", err) + + return svc.createResponse(event, Nip47Response{ + Error: &Nip47Error{ + Code: NIP_47_ERROR_INTERNAL, + Message: fmt.Sprintf("Failed to decode bolt11 invoice: %s", err.Error()), + }, + }, ss) + } + paymentHash = paymentRequest.PaymentHash + } + + invoice, paid, err := svc.lnClient.LookupInvoice(ctx, event.PubKey, paymentHash) + if err != nil { + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + "invoice": lookupInvoiceParams.Invoice, + "paymentHash": lookupInvoiceParams.PaymentHash, + }).Infof("Failed to lookup invoice: %v", err) + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_ERROR + svc.db.Save(&nostrEvent) + return svc.createResponse(event, Nip47Response{ + Error: &Nip47Error{ + Code: NIP_47_ERROR_INTERNAL, + Message: fmt.Sprintf("Something went wrong while looking up invoice: %s", err.Error()), + }, + }, ss) + } + + responsePayload := &Nip47LookupInvoiceResponse { + Invoice: invoice, + Paid: paid, + } + + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_EXECUTED + svc.db.Save(&nostrEvent) + return svc.createResponse(event, Nip47Response{ + ResultType: NIP_47_LOOKUP_INVOICE_METHOD, + Result: responsePayload, + }, + ss) +} diff --git a/lnd.go b/lnd.go index 01a5a278..e74cd146 100644 --- a/lnd.go +++ b/lnd.go @@ -19,6 +19,7 @@ type LNClient interface { SendPaymentSync(ctx context.Context, senderPubkey string, payReq string) (preimage string, err error) GetBalance(ctx context.Context, senderPubkey string) (balance int64, err error) MakeInvoice(ctx context.Context, senderPubkey string, amount int64, description string, descriptionHash string, expiry int64) (invoice string, paymentHash string, err error) + LookupInvoice(ctx context.Context, senderPubkey string, paymentHash string) (invoice string, paid bool, err error) } // wrap it again :sweat_smile: @@ -72,6 +73,10 @@ func (svc *LNDService) MakeInvoice(ctx context.Context, senderPubkey string, amo return resp.GetPaymentRequest(), hex.EncodeToString(resp.GetRHash()), nil } +func (svc *LNDService) LookupInvoice(ctx context.Context, senderPubkey string, paymentHash string) (invoice string, paid bool, err error) { + return "", false, fmt.Errorf("not implemented") +} + func (svc *LNDService) SendPaymentSync(ctx context.Context, senderPubkey, payReq string) (preimage string, err error) { resp, err := svc.client.SendPaymentSync(ctx, &lnrpc.SendRequest{PaymentRequest: payReq}) if err != nil { diff --git a/models.go b/models.go index b7e38908..f6fe013d 100644 --- a/models.go +++ b/models.go @@ -14,6 +14,7 @@ const ( NIP_47_PAY_INVOICE_METHOD = "pay_invoice" NIP_47_GET_BALANCE_METHOD = "get_balance" NIP_47_MAKE_INVOICE_METHOD = "make_invoice" + NIP_47_LOOKUP_INVOICE_METHOD = "lookup_invoice" NIP_47_ERROR_INTERNAL = "INTERNAL" NIP_47_ERROR_NOT_IMPLEMENTED = "NOT_IMPLEMENTED" NIP_47_ERROR_QUOTA_EXCEEDED = "QUOTA_EXCEEDED" @@ -37,6 +38,7 @@ var nip47MethodDescriptions = map[string]string{ NIP_47_GET_BALANCE_METHOD: "Read your balance.", NIP_47_PAY_INVOICE_METHOD: "Send payments from your wallet.", NIP_47_MAKE_INVOICE_METHOD: "Create invoices on your behalf.", + NIP_47_LOOKUP_INVOICE_METHOD: "Lookup status of created invoices.", } type AlbyMe struct { @@ -134,6 +136,11 @@ type MakeInvoiceResponse struct { PaymentHash string `json:"payment_hash"` } +type LookupInvoiceResponse struct { + PaymentRequest string `json:"payment_request"` + Settled bool `json:"settled"` +} + type ErrorResponse struct { Error bool `json:"error"` Code int `json:"code"` @@ -183,3 +190,13 @@ type Nip47MakeInvoiceResponse struct { Invoice string `json:"invoice"` PaymentHash string `json:"payment_hash"` } + +type Nip47LookupInvoiceParams struct { + Invoice string `json:"invoice"` + PaymentHash string `json:"payment_hash"` +} + +type Nip47LookupInvoiceResponse struct { + Invoice string `json:"invoice"` + Paid bool `json:"paid"` +} \ No newline at end of file diff --git a/service.go b/service.go index dba42a42..43432e0d 100644 --- a/service.go +++ b/service.go @@ -27,6 +27,7 @@ var supportedMethods = map[string]bool{ NIP_47_PAY_INVOICE_METHOD: true, NIP_47_GET_BALANCE_METHOD: true, NIP_47_MAKE_INVOICE_METHOD: true, + NIP_47_LOOKUP_INVOICE_METHOD: true, } func (svc *Service) GetUser(c echo.Context) (user *User, err error) { @@ -187,6 +188,8 @@ func (svc *Service) HandleEvent(ctx context.Context, event *nostr.Event) (result return svc.HandleGetBalanceEvent(ctx, nip47Request, event, app, ss) case NIP_47_MAKE_INVOICE_METHOD: return svc.HandleMakeInvoiceEvent(ctx, nip47Request, event, app, ss) + case NIP_47_LOOKUP_INVOICE_METHOD: + return svc.HandleLookupInvoiceEvent(ctx, nip47Request, event, app, ss) default: return svc.createResponse(event, Nip47Response{Error: &Nip47Error{ Code: NIP_47_ERROR_NOT_IMPLEMENTED, diff --git a/service_test.go b/service_test.go index b113a3b5..f9c9f1ca 100644 --- a/service_test.go +++ b/service_test.go @@ -28,11 +28,18 @@ const nip47MakeInvoiceJson = ` "params": { "amount": 1000, "description": "[[\"text/identifier\",\"hello@getalby.com\"],[\"text/plain\",\"Sats for Alby\"]]", - "description_hash": "7da78494568d0c8afcd972ea5f5464d6f8d222025c04704e3d19c338ed61cd1f", "expiry": 3600 } } ` +const nip47LookupInvoiceJson = ` +{ + "method": "lookup_invoice", + "params": { + "payment_hash": "4ad9cd27989b514d868e755178378019903a8d78767e3fceb211af9dd00e7a94" + } +} +` const nip47PayJson = ` { "method": "pay_invoice", @@ -349,6 +356,53 @@ func TestHandleEvent(t *testing.T) { assert.NoError(t, err) assert.Equal(t, mockInvoice, received.Result.(*Nip47MakeInvoiceResponse).Invoice) assert.Equal(t, mockPaymentHash, received.Result.(*Nip47MakeInvoiceResponse).PaymentHash) + + // lookup invoice: without permission + newPayload, err = nip04.Encrypt(nip47LookupInvoiceJson, ss) + assert.NoError(t, err) + res, err = svc.HandleEvent(ctx, &nostr.Event{ + ID: "test_event_14", + 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) + + // lookup invoice: with permission + err = svc.db.Model(&AppPermission{}).Where("app_id = ?", app.ID).Update("request_method", NIP_47_LOOKUP_INVOICE_METHOD).Error + assert.NoError(t, err) + appPermission = &AppPermission{ + AppId: app.ID, + App: app, + RequestMethod: NIP_47_LOOKUP_INVOICE_METHOD, + ExpiresAt: expiresAt, + } + err = svc.db.Create(appPermission).Error + res, err = svc.HandleEvent(ctx, &nostr.Event{ + ID: "test_event_15", + 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: &Nip47LookupInvoiceResponse{}, + } + err = json.Unmarshal([]byte(decrypted), received) + assert.NoError(t, err) + assert.Equal(t, mockInvoice, received.Result.(*Nip47LookupInvoiceResponse).Invoice) + assert.Equal(t, false, received.Result.(*Nip47LookupInvoiceResponse).Paid) } func createTestService(t *testing.T) (svc *Service, ln *MockLn) { @@ -393,3 +447,6 @@ func (mln *MockLn) GetBalance(ctx context.Context, senderPubkey string) (balance func (mln *MockLn) MakeInvoice(ctx context.Context, senderPubkey string, amount int64, description string, descriptionHash string, expiry int64) (invoice string, paymentHash string, err error) { return mockInvoice, mockPaymentHash, nil } +func (mln *MockLn) LookupInvoice(ctx context.Context, senderPubkey string, paymentHash string) (invoice string, paid bool, err error) { + return mockInvoice, false, nil +} From b9779ca36da565eb9be33729ec1b012a29c724d0 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Tue, 29 Aug 2023 12:18:44 +0700 Subject: [PATCH 2/7] chore: update minimum amount error message --- alby.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alby.go b/alby.go index 17d378c3..4c1c5fb8 100644 --- a/alby.go +++ b/alby.go @@ -104,8 +104,8 @@ func (svc *AlbyOAuthService) MakeInvoice(ctx context.Context, senderPubkey strin "description": description, "descriptionHash": descriptionHash, "expiry": expiry, - }).Errorf("Value must be 1 sat or greater"); - return "", "", errors.New("Value must be 1 sat or greater") + }).Errorf("amount must be 1000 msat or greater"); + return "", "", errors.New("amount must be 1000 msat or greater") } svc.Logger.WithFields(logrus.Fields{ From 730caaa0112f64f39ded4ce7d380c76f65808f64 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Tue, 29 Aug 2023 14:26:48 +0700 Subject: [PATCH 3/7] feat: add lnd implementation of lookup_invoice --- lnd.go | 16 +++++++++++++++- lnd/interface.go | 1 + lnd/lnd.go | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lnd.go b/lnd.go index b0b69547..4993c5e9 100644 --- a/lnd.go +++ b/lnd.go @@ -78,7 +78,21 @@ func (svc *LNDService) MakeInvoice(ctx context.Context, senderPubkey string, amo } func (svc *LNDService) LookupInvoice(ctx context.Context, senderPubkey string, paymentHash string) (invoice string, paid bool, err error) { - return "", false, fmt.Errorf("not implemented") + paymentHashBytes, err := hex.DecodeString(paymentHash) + + if err != nil || len(paymentHashBytes) != 32 { + svc.Logger.WithFields(logrus.Fields{ + "paymentHash": paymentHash, + }).Errorf("Invalid payment hash") + return "", false, errors.New("Payment hash must be 32 bytes hex") + } + + lndInvoice, err := svc.client.LookupInvoice(ctx, &lnrpc.PaymentHash{ RHash: paymentHashBytes }) + if err != nil { + return "", false, err + } + + return lndInvoice.PaymentRequest, lndInvoice.State == *lnrpc.Invoice_SETTLED.Enum(), nil; } func (svc *LNDService) SendPaymentSync(ctx context.Context, senderPubkey, payReq string) (preimage string, err error) { diff --git a/lnd/interface.go b/lnd/interface.go index f46f94e0..bc40742b 100644 --- a/lnd/interface.go +++ b/lnd/interface.go @@ -15,6 +15,7 @@ type LightningClientWrapper interface { AddInvoice(ctx context.Context, req *lnrpc.Invoice, options ...grpc.CallOption) (*lnrpc.AddInvoiceResponse, error) SubscribeInvoices(ctx context.Context, req *lnrpc.InvoiceSubscription, options ...grpc.CallOption) (SubscribeInvoicesWrapper, error) SubscribePayment(ctx context.Context, req *routerrpc.TrackPaymentRequest, options ...grpc.CallOption) (SubscribePaymentWrapper, error) + LookupInvoice(ctx context.Context, req *lnrpc.PaymentHash, options ...grpc.CallOption) (*lnrpc.Invoice, error) GetInfo(ctx context.Context, req *lnrpc.GetInfoRequest, options ...grpc.CallOption) (*lnrpc.GetInfoResponse, error) DecodeBolt11(ctx context.Context, bolt11 string, options ...grpc.CallOption) (*lnrpc.PayReq, error) IsIdentityPubkey(pubkey string) (isOurPubkey bool) diff --git a/lnd/lnd.go b/lnd/lnd.go index 239bb086..069c5a13 100644 --- a/lnd/lnd.go +++ b/lnd/lnd.go @@ -120,6 +120,10 @@ func (wrapper *LNDWrapper) SubscribeInvoices(ctx context.Context, req *lnrpc.Inv return wrapper.client.SubscribeInvoices(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...) +} + func (wrapper *LNDWrapper) GetInfo(ctx context.Context, req *lnrpc.GetInfoRequest, options ...grpc.CallOption) (*lnrpc.GetInfoResponse, error) { return wrapper.client.GetInfo(ctx, req, options...) } From 364106e12b26ba3b9ac50ece67401f7199da6366 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 30 Aug 2023 12:58:04 +0700 Subject: [PATCH 4/7] fix: remove special handling for 404 response --- alby.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/alby.go b/alby.go index a2fc67d7..9ce9b7eb 100644 --- a/alby.go +++ b/alby.go @@ -240,16 +240,7 @@ func (svc *AlbyOAuthService) LookupInvoice(ctx context.Context, senderPubkey str return "", false, err } - if resp.StatusCode == 404 { - // TODO: review - svc.Logger.WithFields(logrus.Fields{ - "senderPubkey": senderPubkey, - "paymentHash": paymentHash, - "appId": app.ID, - "userId": app.User.ID, - }).Info("Lookup invoice returned not found") - return "", false, nil - } else if resp.StatusCode < 300 { + if resp.StatusCode < 300 { responsePayload := &LookupInvoiceResponse{} err = json.NewDecoder(resp.Body).Decode(responsePayload) if err != nil { From 67cd6823397616ac09f1a827a7c747c2c01ee1c8 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 30 Aug 2023 13:01:00 +0700 Subject: [PATCH 5/7] chore: remove unnecessary else --- alby.go | 92 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/alby.go b/alby.go index 9ce9b7eb..8eda5b20 100644 --- a/alby.go +++ b/alby.go @@ -174,21 +174,21 @@ func (svc *AlbyOAuthService) MakeInvoice(ctx context.Context, senderPubkey strin "paymentHash": responsePayload.PaymentHash, }).Info("Make invoice successful") return responsePayload.PaymentRequest, responsePayload.PaymentHash, nil - } else { - errorPayload := &ErrorResponse{} - err = json.NewDecoder(resp.Body).Decode(errorPayload) - svc.Logger.WithFields(logrus.Fields{ - "senderPubkey": senderPubkey, - "amount": amount, - "description": description, - "descriptionHash": descriptionHash, - "expiry": expiry, - "appId": app.ID, - "userId": app.User.ID, - "APIHttpStatus": resp.StatusCode, - }).Errorf("Make invoice failed %s", string(errorPayload.Message)) - return "", "", errors.New(errorPayload.Message) } + + errorPayload := &ErrorResponse{} + err = json.NewDecoder(resp.Body).Decode(errorPayload) + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "amount": amount, + "description": description, + "descriptionHash": descriptionHash, + "expiry": expiry, + "appId": app.ID, + "userId": app.User.ID, + "APIHttpStatus": resp.StatusCode, + }).Errorf("Make invoice failed %s", string(errorPayload.Message)) + return "", "", errors.New(errorPayload.Message) } func (svc *AlbyOAuthService) LookupInvoice(ctx context.Context, senderPubkey string, paymentHash string) (invoice string, paid bool, err error) { @@ -255,18 +255,18 @@ func (svc *AlbyOAuthService) LookupInvoice(ctx context.Context, senderPubkey str "settled": responsePayload.Settled, }).Info("Lookup invoice successful") return responsePayload.PaymentRequest, responsePayload.Settled, nil - } else { - errorPayload := &ErrorResponse{} - err = json.NewDecoder(resp.Body).Decode(errorPayload) - svc.Logger.WithFields(logrus.Fields{ - "senderPubkey": senderPubkey, - "paymentHash": paymentHash, - "appId": app.ID, - "userId": app.User.ID, - "APIHttpStatus": resp.StatusCode, - }).Errorf("Lookup invoice failed %s", string(errorPayload.Message)) - return "", false, errors.New(errorPayload.Message) } + + errorPayload := &ErrorResponse{} + err = json.NewDecoder(resp.Body).Decode(errorPayload) + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "paymentHash": paymentHash, + "appId": app.ID, + "userId": app.User.ID, + "APIHttpStatus": resp.StatusCode, + }).Errorf("Lookup invoice failed %s", string(errorPayload.Message)) + return "", false, errors.New(errorPayload.Message) } func (svc *AlbyOAuthService) GetBalance(ctx context.Context, senderPubkey string) (balance int64, err error) { @@ -316,17 +316,17 @@ func (svc *AlbyOAuthService) GetBalance(ctx context.Context, senderPubkey string "userId": app.User.ID, }).Info("Balance fetch successful") return int64(responsePayload.Balance), nil - } else { - errorPayload := &ErrorResponse{} - err = json.NewDecoder(resp.Body).Decode(errorPayload) - svc.Logger.WithFields(logrus.Fields{ - "senderPubkey": senderPubkey, - "appId": app.ID, - "userId": app.User.ID, - "APIHttpStatus": resp.StatusCode, - }).Errorf("Balance fetch failed %s", string(errorPayload.Message)) - return 0, errors.New(errorPayload.Message) } + + errorPayload := &ErrorResponse{} + err = json.NewDecoder(resp.Body).Decode(errorPayload) + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "appId": app.ID, + "userId": app.User.ID, + "APIHttpStatus": resp.StatusCode, + }).Errorf("Balance fetch failed %s", string(errorPayload.Message)) + return 0, errors.New(errorPayload.Message) } func (svc *AlbyOAuthService) SendPaymentSync(ctx context.Context, senderPubkey, payReq string) (preimage string, err error) { @@ -392,18 +392,18 @@ func (svc *AlbyOAuthService) SendPaymentSync(ctx context.Context, senderPubkey, "userId": app.User.ID, }).Info("Payment successful") return responsePayload.Preimage, nil - } else { - errorPayload := &ErrorResponse{} - err = json.NewDecoder(resp.Body).Decode(errorPayload) - svc.Logger.WithFields(logrus.Fields{ - "senderPubkey": senderPubkey, - "bolt11": payReq, - "appId": app.ID, - "userId": app.User.ID, - "APIHttpStatus": resp.StatusCode, - }).Errorf("Payment failed %s", string(errorPayload.Message)) - return "", errors.New(errorPayload.Message) } + + errorPayload := &ErrorResponse{} + err = json.NewDecoder(resp.Body).Decode(errorPayload) + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "bolt11": payReq, + "appId": app.ID, + "userId": app.User.ID, + "APIHttpStatus": resp.StatusCode, + }).Errorf("Payment failed %s", string(errorPayload.Message)) + return "", errors.New(errorPayload.Message) } func (svc *AlbyOAuthService) AuthHandler(c echo.Context) error { From 407eb71bd1c79a35d3b4296ced752e6e188831c5 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 30 Aug 2023 13:06:06 +0700 Subject: [PATCH 6/7] chore: only use error from insert nostr event --- handle_balance_request.go | 8 ++++---- handle_lookup_invoice_request.go | 9 ++++----- handle_make_invoice_request.go | 8 ++++---- handle_payment_request.go | 8 ++++---- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/handle_balance_request.go b/handle_balance_request.go index cb63239e..2df0801b 100644 --- a/handle_balance_request.go +++ b/handle_balance_request.go @@ -15,14 +15,14 @@ const ( func (svc *Service) HandleGetBalanceEvent(ctx context.Context, request *Nip47Request, event *nostr.Event, app App, ss []byte) (result *nostr.Event, err error) { nostrEvent := NostrEvent{App: app, NostrId: event.ID, Content: event.Content, State: "received"} - insertNostrEventResult := svc.db.Create(&nostrEvent) - if insertNostrEventResult.Error != nil { + err = svc.db.Create(&nostrEvent).Error + if err != nil { svc.Logger.WithFields(logrus.Fields{ "eventId": event.ID, "eventKind": event.Kind, "appId": app.ID, - }).Errorf("Failed to save nostr event: %v", insertNostrEventResult.Error) - return nil, insertNostrEventResult.Error + }).Errorf("Failed to save nostr event: %v", err) + return nil, err } hasPermission, code, message := svc.hasPermission(&app, event, request.Method, nil) diff --git a/handle_lookup_invoice_request.go b/handle_lookup_invoice_request.go index 4f6988dd..94b3a98b 100644 --- a/handle_lookup_invoice_request.go +++ b/handle_lookup_invoice_request.go @@ -13,17 +13,16 @@ import ( ) func (svc *Service) HandleLookupInvoiceEvent(ctx context.Context, request *Nip47Request, event *nostr.Event, app App, ss []byte) (result *nostr.Event, err error) { - // TODO: move to a shared function nostrEvent := NostrEvent{App: app, NostrId: event.ID, Content: event.Content, State: "received"} - insertNostrEventResult := svc.db.Create(&nostrEvent) - if insertNostrEventResult.Error != nil { + err = svc.db.Create(&nostrEvent).Error + if err != nil { svc.Logger.WithFields(logrus.Fields{ "eventId": event.ID, "eventKind": event.Kind, "appId": app.ID, - }).Errorf("Failed to save nostr event: %v", insertNostrEventResult.Error) - return nil, insertNostrEventResult.Error + }).Errorf("Failed to save nostr event: %v", err) + return nil, err } // TODO: move to a shared function diff --git a/handle_make_invoice_request.go b/handle_make_invoice_request.go index 96790a3f..c328dcba 100644 --- a/handle_make_invoice_request.go +++ b/handle_make_invoice_request.go @@ -15,14 +15,14 @@ func (svc *Service) HandleMakeInvoiceEvent(ctx context.Context, request *Nip47Re // TODO: move to a shared function nostrEvent := NostrEvent{App: app, NostrId: event.ID, Content: event.Content, State: "received"} - insertNostrEventResult := svc.db.Create(&nostrEvent) - if insertNostrEventResult.Error != nil { + err = svc.db.Create(&nostrEvent).Error + if err != nil { svc.Logger.WithFields(logrus.Fields{ "eventId": event.ID, "eventKind": event.Kind, "appId": app.ID, - }).Errorf("Failed to save nostr event: %v", insertNostrEventResult.Error) - return nil, insertNostrEventResult.Error + }).Errorf("Failed to save nostr event: %v", err) + return nil, err } // TODO: move to a shared function diff --git a/handle_payment_request.go b/handle_payment_request.go index 3355eeff..4ed7d639 100644 --- a/handle_payment_request.go +++ b/handle_payment_request.go @@ -13,14 +13,14 @@ import ( func (svc *Service) HandlePayInvoiceEvent(ctx context.Context, request *Nip47Request, event *nostr.Event, app App, ss []byte) (result *nostr.Event, err error) { nostrEvent := NostrEvent{App: app, NostrId: event.ID, Content: event.Content, State: "received"} - insertNostrEventResult := svc.db.Create(&nostrEvent) - if insertNostrEventResult.Error != nil { + err = svc.db.Create(&nostrEvent).Error + if err != nil { svc.Logger.WithFields(logrus.Fields{ "eventId": event.ID, "eventKind": event.Kind, "appId": app.ID, - }).Errorf("Failed to save nostr event: %v", insertNostrEventResult.Error) - return nil, insertNostrEventResult.Error + }).Errorf("Failed to save nostr event: %v", err) + return nil, err } var bolt11 string From b00ea209a44dce7492c1f253559d480b281dfc44 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 30 Aug 2023 13:09:52 +0700 Subject: [PATCH 7/7] chore: remove unused import --- handle_lookup_invoice_request.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/handle_lookup_invoice_request.go b/handle_lookup_invoice_request.go index 94b3a98b..0aa10fdf 100644 --- a/handle_lookup_invoice_request.go +++ b/handle_lookup_invoice_request.go @@ -5,8 +5,6 @@ import ( "encoding/json" "fmt" - //"fmt" - "github.com/nbd-wtf/go-nostr" decodepay "github.com/nbd-wtf/ln-decodepay" "github.com/sirupsen/logrus"