package lnd import ( "context" "log" "time" "git.ekzyis.com/ekzyis/delphi.market/db" "github.com/lightninglabs/lndclient" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" ) func (lnd *LNDClient) CreateInvoice(d *db.DB, pubkey string, msats int64, description string) (*db.Invoice, error) { var ( expiry time.Duration = time.Hour preimage lntypes.Preimage hash lntypes.Hash paymentRequest string lnInvoice *lndclient.Invoice dbInvoice *db.Invoice err error ) if preimage, err = generateNewPreimage(); err != nil { return nil, err } hash = preimage.Hash() if paymentRequest, err = lnd.Invoices.AddHoldInvoice(context.TODO(), &invoicesrpc.AddInvoiceData{ Hash: &hash, Value: lnwire.MilliSatoshi(msats), Expiry: int64(expiry / time.Millisecond), }); err != nil { return nil, err } if lnInvoice, err = lnd.Client.LookupInvoice(context.TODO(), hash); err != nil { return nil, err } dbInvoice = &db.Invoice{ Pubkey: pubkey, Msats: msats, Preimage: preimage.String(), PaymentRequest: paymentRequest, Hash: hash.String(), CreatedAt: lnInvoice.CreationDate, ExpiresAt: lnInvoice.CreationDate.Add(expiry), Description: description, } if err := d.CreateInvoice(dbInvoice); err != nil { return nil, err } return dbInvoice, nil } func (lnd *LNDClient) CheckInvoice(d *db.DB, hash lntypes.Hash) { var ( pollInterval = 5 * time.Second invoice db.Invoice lnInvoice *lndclient.Invoice preimage lntypes.Preimage err error ) if err = d.FetchInvoice(&db.FetchInvoiceWhere{Hash: hash.String()}, &invoice); err != nil { log.Println(err) return } handleLoopError := func(err error) { log.Println(err) time.Sleep(pollInterval) } for { log.Printf("lookup invoice: hash=%s", hash) if lnInvoice, err = lnd.Client.LookupInvoice(context.TODO(), hash); err != nil { handleLoopError(err) continue } if time.Now().After(invoice.ExpiresAt) { // cancel invoices after expiration if no matching order found yet if err = lnd.Invoices.CancelInvoice(context.TODO(), hash); err != nil { handleLoopError(err) continue } log.Printf("invoice expired: hash=%s", hash) break } if lnInvoice.AmountPaid > 0 { if preimage, err = lntypes.MakePreimageFromStr(invoice.Preimage); err != nil { handleLoopError(err) continue } // TODO settle invoice after matching order was found if err = lnd.Invoices.SettleInvoice(context.TODO(), preimage); err != nil { handleLoopError(err) continue } if err = d.ConfirmInvoice(hash.String(), time.Now(), int(lnInvoice.AmountPaid)); err != nil { handleLoopError(err) continue } log.Printf("invoice confirmed: hash=%s", hash) break } time.Sleep(pollInterval) } } func (lnd *LNDClient) CheckInvoices(d *db.DB) error { var ( invoices []db.Invoice err error hash lntypes.Hash ) if err = d.FetchInvoices(&db.FetchInvoicesWhere{Unconfirmed: true}, &invoices); err != nil { return err } for _, invoice := range invoices { if hash, err = lntypes.MakeHashFromStr(invoice.Hash); err != nil { return err } go lnd.CheckInvoice(d, hash) } return nil }