package ln import ( "encoding/hex" "encoding/json" "fmt" "strconv" "time" "github.com/lightningnetwork/lnd/lnrpc" ) type Currency int const ( CurMSat Currency = iota CurSat CurBTC CurUSD CurEur ) const ( Paid int = iota UnPaid Expired ) var InvoiceStatus = map[int]string{ UnPaid: "unpaid", Paid: "paid", Expired: "expired", } const ( InfoEndpoint = "info" InvoiceEndpoint = "invoice" ) var ( CurrencyString = map[Currency]string{ CurUSD: "USD", CurSat: "SAT", CurBTC: "BTC", CurMSat: "MSAT", CurEur: "EUR", } CurrencyID = map[string]Currency{ "USD": CurUSD, "SAT": CurSat, "MSAT": CurMSat, "BTC": CurBTC, "EUR": CurEur, } ) type timestamp time.Time func (t *timestamp) UnmarshalJSON(in []byte) error { if string(in) == "null" { *t = timestamp(time.Unix(0, 0)) return nil } val, err := strconv.Atoi(string(in)) if err != nil { return fmt.Errorf("cannot unmarshal timestamp int") } parsedTime := time.Unix(int64(val), 0) *t = timestamp(parsedTime) return nil } func (t timestamp) MarshalJSON() ([]byte, error) { str := strconv.Itoa(int(time.Time(t).Unix())) return []byte(str), nil } func (t timestamp) String() string { return time.Time(t).Format(time.RFC3339) } type Invoice struct { AddIndex uint64 `json:"-"` SettleIndex uint64 `json:"-"` Description string `json:"description"` Msatoshi float64 `json:"msatoshi"` Payreq string `json:"payreq"` RHash string `json:"rhash"` Status string `json:"status"` PaidAt timestamp `json:"paid_at"` CreatedAt timestamp `json:"created_at"` ExpiresAt timestamp `json:"expires_at"` Expired bool `json:"-"` QuotedCurrency string `json:"quoted_currency"` QuotedAmount float64 `json:"quoted_amount"` } func (i Invoice) MarshalBinary() ([]byte, error) { return json.Marshal(i) } func (i *Invoice) UnmarshalBinary(b []byte) error { return json.Unmarshal(b, &i) } // Create new Invoice from lnrpc.Invoice func InvoiceFromLndIn(lndInvoice *lnrpc.Invoice) *Invoice { invoice := Invoice{ AddIndex: lndInvoice.AddIndex, Description: lndInvoice.GetMemo(), Msatoshi: float64(lndInvoice.Value * 1000), Payreq: lndInvoice.PaymentRequest, RHash: hex.EncodeToString(lndInvoice.RHash), CreatedAt: timestamp(time.Unix(lndInvoice.CreationDate, 0)), Status: InvoiceStatus[UnPaid], } invoice.ExpiresAt = timestamp(time.Time(invoice.CreatedAt).Add(time.Second * time.Duration(lndInvoice.Expiry))) // Calculate status if lndInvoice.Settled { invoice.Status = InvoiceStatus[Paid] } if time.Now().After(time.Time(invoice.ExpiresAt)) { invoice.Status = InvoiceStatus[Expired] invoice.Expired = true } return &invoice } // Update stored invoice from lnd invoice func UpdateInvoiceFromLnd(storedIn *Invoice, newIn *lnrpc.Invoice) *Invoice { storedIn.SettleIndex = newIn.SettleIndex storedIn.PaidAt = timestamp(time.Unix(newIn.SettleDate, 0)) // Calculate status if newIn.Settled { storedIn.Status = InvoiceStatus[Paid] } // Handle expired status if time.Now().After(time.Time(storedIn.ExpiresAt)) { storedIn.Status = InvoiceStatus[Expired] storedIn.Expired = true } return storedIn }