Skip to content

Commit

Permalink
feat: consume nwc_payment_received event in transaction service (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz committed Jul 8, 2024
1 parent e95f1f5 commit 26f2840
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 18 deletions.
4 changes: 0 additions & 4 deletions events/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ type Event struct {
Properties interface{} `json:"properties,omitempty"`
}

type PaymentReceivedEventProperties struct {
PaymentHash string `json:"payment_hash"`
}

type PaymentSentEventProperties struct {
PaymentHash string `json:"payment_hash"`
Duration uint64 `json:"duration"`
Expand Down
24 changes: 19 additions & 5 deletions lnclient/ldk/ldk.go
Original file line number Diff line number Diff line change
Expand Up @@ -1256,13 +1256,27 @@ func (ls *LDKService) handleLdkEvent(event *ldk_node.Event) {
},
})
case ldk_node.EventPaymentReceived:
// TODO: trigger transaction update (reuse below event?)
if eventType.PaymentId == nil {
logger.Logger.WithField("payment_hash", eventType.PaymentHash).Error("payment received event has no payment ID")
return
}
payment := ls.node.Payment(*eventType.PaymentId)
if payment == nil {
logger.Logger.WithField("payment_id", *eventType.PaymentId).Error("could not find LDK payment")
return
}

transaction, err := ls.ldkPaymentToTransaction(payment)
if err != nil {
logger.Logger.WithField("payment_id", *eventType.PaymentId).Error("failed to convert LDK payment to transaction")
return
}

ls.eventPublisher.Publish(&events.Event{
Event: "nwc_payment_received",
Properties: &events.PaymentReceivedEventProperties{
PaymentHash: eventType.PaymentHash,
},
Event: "nwc_payment_received",
Properties: transaction,
})

case ldk_node.EventPaymentSuccessful:
// TODO: trigger transaction update
// TODO: trigger transaction update for payment failed
Expand Down
8 changes: 4 additions & 4 deletions nip47/notifications/nip47_notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@ func NewNip47Notifier(relay Relay, db *gorm.DB, cfg config.Config, keys keys.Key
func (notifier *Nip47Notifier) ConsumeEvent(ctx context.Context, event *events.Event) error {
switch event.Event {
case "nwc_payment_received":
paymentReceivedEventProperties, ok := event.Properties.(*events.PaymentReceivedEventProperties)
lnClientTransaction, ok := event.Properties.(*lnclient.Transaction)
if !ok {
logger.Logger.WithField("event", event).Error("Failed to cast event")
return errors.New("failed to cast event")
}

transaction, err := notifier.transactionsService.LookupTransaction(ctx, paymentReceivedEventProperties.PaymentHash, notifier.lnClient, nil)
transaction, err := notifier.transactionsService.LookupTransaction(ctx, lnClientTransaction.PaymentHash, notifier.lnClient, nil)
if err != nil {
logger.Logger.
WithField("paymentHash", paymentReceivedEventProperties.PaymentHash).
WithField("paymentHash", lnClientTransaction.PaymentHash).
WithError(err).
Error("Failed to lookup invoice by payment hash")
Error("Failed to lookup transaction by payment hash")
return err
}

Expand Down
1 change: 1 addition & 0 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func NewService(ctx context.Context) (*service, error) {
}

eventPublisher.RegisterSubscriber(svc.albyOAuthSvc)
eventPublisher.RegisterSubscriber(svc.transactionsService)

eventPublisher.Publish(&events.Event{
Event: "nwc_started",
Expand Down
62 changes: 57 additions & 5 deletions transactions/transactions_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/getAlby/hub/db"
"github.com/getAlby/hub/events"
"github.com/getAlby/hub/lnclient"
"github.com/getAlby/hub/logger"
decodepay "github.com/nbd-wtf/ln-decodepay"
Expand All @@ -20,6 +21,7 @@ type transactionsService struct {
}

type TransactionsService interface {
events.EventSubscriber
MakeInvoice(ctx context.Context, amount int64, description string, descriptionHash string, expiry int64, lnClient lnclient.LNClient, appId *uint, requestEventId *uint) (*Transaction, error)
LookupTransaction(ctx context.Context, paymentHash string, lnClient lnclient.LNClient, appId *uint) (*Transaction, error)
ListTransactions(ctx context.Context, from, until, limit, offset uint64, unpaid bool, invoiceType string, lnClient lnclient.LNClient) (transactions []Transaction, err error)
Expand Down Expand Up @@ -266,11 +268,7 @@ func (svc *transactionsService) SendKeysend(ctx context.Context, amount uint64,
func (svc *transactionsService) LookupTransaction(ctx context.Context, paymentHash string, lnClient lnclient.LNClient, appId *uint) (*Transaction, error) {
transaction := db.Transaction{}

// FIXME: this is not unique
// TODO: check if passing AppId: null works for the "Global" view
// - wallet page
// - notifications
// - etc.
// FIXME: this is currently not unique
result := svc.db.Find(&transaction, &db.Transaction{
//Type: transactionType,
PaymentHash: paymentHash,
Expand Down Expand Up @@ -354,3 +352,57 @@ func (svc *transactionsService) checkUnsettledTransaction(ctx context.Context, t
}
}
}

func (svc *transactionsService) ConsumeEvent(ctx context.Context, event *events.Event, globalProperties map[string]interface{}) error {
switch event.Event {
case "nwc_payment_received":
lnClientTransaction, ok := event.Properties.(*lnclient.Transaction)
if !ok {
logger.Logger.WithField("event", event).Error("Failed to cast event")
return errors.New("failed to cast event")
}

// TODO: copied from makeinvoice
var metadata string
if lnClientTransaction.Metadata != nil {
metadataBytes, err := json.Marshal(lnClientTransaction.Metadata)
if err != nil {
logger.Logger.WithError(err).Error("Failed to serialize transaction metadata")
return err
}
metadata = string(metadataBytes)
}

// TODO: update the transaction if it already exists!
// Note: brand new payments (keysend) cannot be associated with an app

settledAt := time.Now()
dbTransaction := &db.Transaction{
Type: lnClientTransaction.Type,
State: TRANSACTION_STATE_SETTLED,
Amount: uint64(lnClientTransaction.Amount),
PaymentRequest: lnClientTransaction.Invoice,
PaymentHash: lnClientTransaction.PaymentHash,
Description: lnClientTransaction.Description,
DescriptionHash: lnClientTransaction.DescriptionHash,
// TODO: add missing fields
// ExpiresAt: lnClientTransaction.ExpiresAt,
// Fee: lnClientTransaction.FeesPaid,
// Preimage: ,
SettledAt: &settledAt,
Metadata: metadata,
}

err := svc.db.Create(dbTransaction).Error
if err != nil {
logger.Logger.WithFields(logrus.Fields{
"payment_hash": lnClientTransaction.PaymentHash,
}).WithError(err).Error("Failed to create DB transaction")
return err
}

// TODO: support nwc_payment_sent and nwc_payment_failed ()
}

return nil
}

0 comments on commit 26f2840

Please sign in to comment.