Add invoice description

This commit is contained in:
ekzyis 2023-11-09 03:47:24 +01:00
parent 4aaada7cb7
commit 4b0d017b98
9 changed files with 58 additions and 19 deletions

View File

@ -35,7 +35,8 @@ CREATE TABLE invoices(
created_at TIMESTAMP WITH TIME ZONE NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL, expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
confirmed_at TIMESTAMP WITH TIME ZONE, confirmed_at TIMESTAMP WITH TIME ZONE,
held_since TIMESTAMP WITH TIME ZONE held_since TIMESTAMP WITH TIME ZONE,
description TEXT
); );
CREATE TYPE order_side AS ENUM ('BUY', 'SELL'); CREATE TYPE order_side AS ENUM ('BUY', 'SELL');
CREATE TABLE orders( CREATE TABLE orders(

View File

@ -4,10 +4,10 @@ import "time"
func (db *DB) CreateInvoice(invoice *Invoice) error { func (db *DB) CreateInvoice(invoice *Invoice) error {
if err := db.QueryRow(""+ if err := db.QueryRow(""+
"INSERT INTO invoices(pubkey, msats, preimage, hash, bolt11, created_at, expires_at) "+ "INSERT INTO invoices(pubkey, msats, preimage, hash, bolt11, created_at, expires_at, description) "+
"VALUES($1, $2, $3, $4, $5, $6, $7) "+ "VALUES($1, $2, $3, $4, $5, $6, $7, $8) "+
"RETURNING id", "RETURNING id",
invoice.Pubkey, invoice.Msats, invoice.Preimage, invoice.Hash, invoice.PaymentRequest, invoice.CreatedAt, invoice.ExpiresAt).Scan(&invoice.Id); err != nil { invoice.Pubkey, invoice.Msats, invoice.Preimage, invoice.Hash, invoice.PaymentRequest, invoice.CreatedAt, invoice.ExpiresAt, invoice.Description).Scan(&invoice.Id); err != nil {
return err return err
} }
return nil return nil
@ -20,7 +20,7 @@ type FetchInvoiceWhere struct {
func (db *DB) FetchInvoice(where *FetchInvoiceWhere, invoice *Invoice) error { func (db *DB) FetchInvoice(where *FetchInvoiceWhere, invoice *Invoice) error {
var ( var (
query = "SELECT id, pubkey, msats, preimage, hash, bolt11, created_at, expires_at, confirmed_at, held_since FROM invoices " query = "SELECT id, pubkey, msats, preimage, hash, bolt11, created_at, expires_at, confirmed_at, held_since, COALESCE(description, '') FROM invoices "
args []any args []any
) )
if where.Id != "" { if where.Id != "" {
@ -32,7 +32,7 @@ func (db *DB) FetchInvoice(where *FetchInvoiceWhere, invoice *Invoice) error {
} }
if err := db.QueryRow(query, args...).Scan( if err := db.QueryRow(query, args...).Scan(
&invoice.Id, &invoice.Pubkey, &invoice.Msats, &invoice.Preimage, &invoice.Hash, &invoice.Id, &invoice.Pubkey, &invoice.Msats, &invoice.Preimage, &invoice.Hash,
&invoice.PaymentRequest, &invoice.CreatedAt, &invoice.ExpiresAt, &invoice.ConfirmedAt, &invoice.HeldSince); err != nil { &invoice.PaymentRequest, &invoice.CreatedAt, &invoice.ExpiresAt, &invoice.ConfirmedAt, &invoice.HeldSince, &invoice.Description); err != nil {
return err return err
} }
return nil return nil

View File

@ -46,6 +46,10 @@ func (db *DB) FetchShares(marketId int, shares *[]Share) error {
return nil return nil
} }
func (db *DB) FetchShare(shareId string, share *Share) error {
return db.QueryRow("SELECT id, market_id, description FROM shares WHERE id = $1", shareId).Scan(&share.Id, &share.MarketId, &share.Description)
}
func (db *DB) FetchOrders(where *FetchOrdersWhere, orders *[]Order) error { func (db *DB) FetchOrders(where *FetchOrdersWhere, orders *[]Order) error {
query := "" + query := "" +
"SELECT o.id, share_id, o.pubkey, o.side, o.quantity, o.price, o.invoice_id, o.created_at, s.description, s.market_id, i.confirmed_at " + "SELECT o.id, share_id, o.pubkey, o.side, o.quantity, o.price, o.invoice_id, o.created_at, s.description, s.market_id, i.confirmed_at " +

View File

@ -45,6 +45,7 @@ type (
ExpiresAt time.Time ExpiresAt time.Time
ConfirmedAt null.Time ConfirmedAt null.Time
HeldSince null.Time HeldSince null.Time
Description string
} }
Order struct { Order struct {
Id UUID Id UUID

View File

@ -12,7 +12,7 @@ import (
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
func (lnd *LNDClient) CreateInvoice(d *db.DB, pubkey string, msats int64) (*db.Invoice, error) { func (lnd *LNDClient) CreateInvoice(d *db.DB, pubkey string, msats int64, description string) (*db.Invoice, error) {
var ( var (
expiry time.Duration = time.Hour expiry time.Duration = time.Hour
preimage lntypes.Preimage preimage lntypes.Preimage
@ -44,6 +44,7 @@ func (lnd *LNDClient) CreateInvoice(d *db.DB, pubkey string, msats int64) (*db.I
Hash: hash.String(), Hash: hash.String(),
CreatedAt: lnInvoice.CreationDate, CreatedAt: lnInvoice.CreationDate,
ExpiresAt: lnInvoice.CreationDate.Add(expiry), ExpiresAt: lnInvoice.CreationDate.Add(expiry),
Description: description,
} }
if err := d.CreateInvoice(dbInvoice); err != nil { if err := d.CreateInvoice(dbInvoice); err != nil {
return nil, err return nil, err

View File

@ -44,6 +44,7 @@ func HandleInvoiceStatus(sc context.ServerContext) echo.HandlerFunc {
"ExpiresAt": invoice.ExpiresAt, "ExpiresAt": invoice.ExpiresAt,
"ConfirmedAt": invoice.ConfirmedAt, "ConfirmedAt": invoice.ConfirmedAt,
"HeldSince": invoice.HeldSince, "HeldSince": invoice.HeldSince,
"Description": invoice.Description,
"Qr": qr, "Qr": qr,
} }
return c.JSON(http.StatusOK, data) return c.JSON(http.StatusOK, data)

View File

@ -2,8 +2,10 @@ package handler
import ( import (
"database/sql" "database/sql"
"fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings"
"git.ekzyis.com/ekzyis/delphi.market/db" "git.ekzyis.com/ekzyis/delphi.market/db"
"git.ekzyis.com/ekzyis/delphi.market/lib" "git.ekzyis.com/ekzyis/delphi.market/lib"
@ -48,14 +50,16 @@ func HandleMarket(sc context.ServerContext) echo.HandlerFunc {
func HandleOrder(sc context.ServerContext) echo.HandlerFunc { func HandleOrder(sc context.ServerContext) echo.HandlerFunc {
return func(c echo.Context) error { return func(c echo.Context) error {
var ( var (
u db.User u db.User
o db.Order o db.Order
invoice *db.Invoice s db.Share
msats int64 invoice *db.Invoice
data map[string]any msats int64
qr string description string
hash lntypes.Hash data map[string]any
err error qr string
hash lntypes.Hash
err error
) )
// TODO: // TODO:
// [ ] Step 0: If SELL order, check share balance of user // [ ] Step 0: If SELL order, check share balance of user
@ -72,11 +76,15 @@ func HandleOrder(sc context.ServerContext) echo.HandlerFunc {
u = c.Get("session").(db.User) u = c.Get("session").(db.User)
o.Pubkey = u.Pubkey o.Pubkey = u.Pubkey
msats = o.Quantity * o.Price * 1000 msats = o.Quantity * o.Price * 1000
if err = sc.Db.FetchShare(o.ShareId, &s); err != nil {
return err
}
description = fmt.Sprintf("%s %d %s shares @ %d [market:%d]", strings.ToUpper(o.Side), o.Quantity, s.Description, o.Price, s.MarketId)
// TODO: if SELL order, check share balance of user // TODO: if SELL order, check share balance of user
// Create HODL invoice // Create HODL invoice
if invoice, err = sc.Lnd.CreateInvoice(sc.Db, o.Pubkey, msats); err != nil { if invoice, err = sc.Lnd.CreateInvoice(sc.Db, o.Pubkey, msats, description); err != nil {
return err return err
} }
// Create QR code to pay HODL invoice // Create QR code to pay HODL invoice

View File

@ -31,8 +31,22 @@
<span class="mx-3 my-1">expires at</span><span class="text-ellipsis overflow-hidden font-mono me-3 my-1"> <span class="mx-3 my-1">expires at</span><span class="text-ellipsis overflow-hidden font-mono me-3 my-1">
{{ invoice.ExpiresAt }} {{ invoice.ExpiresAt }}
</span> </span>
<span class="mx-3 my-1">msats</span><span class="text-ellipsis overflow-hidden font-mono me-3 my-1"> <span class="mx-3 my-1">sats</span><span class="text-ellipsis overflow-hidden font-mono me-3 my-1">
{{ invoice.Msats }} {{ invoice.Msats / 1000 }}
</span>
<span class="mx-3 my-1">description</span>
<span class="text-ellipsis overflow-hidden font-mono me-3 my-1">
<span v-if="invoice.DescriptionMarketId">
<span v-if="invoice.Description">
<span>{{ invoice.Description }}</span>
<router-link :to="'/market/' + invoice.DescriptionMarketId">[market]</router-link>
</span>
<span v-else>&lt;empty&gt;</span>
</span>
<span v-else>
<span v-if="invoice.Description">{{ invoice.Description }}</span>
<span v-else>&lt;empty&gt;</span>
</span>
</span> </span>
</div> </div>
</div> </div>
@ -83,6 +97,15 @@ await (async () => {
const url = window.origin + '/api/invoice/' + route.params.id const url = window.origin + '/api/invoice/' + route.params.id
const res = await fetch(url) const res = await fetch(url)
const body = await res.json() const body = await res.json()
if (body.Description) {
const regexp = /\[market:(?<id>[0-9]+)\]/
const m = body.Description.match(regexp)
const marketId = m.groups?.id
if (marketId) {
body.DescriptionMarketId = marketId
body.Description = body.Description.replace(regexp, '')
}
}
invoice.value = body invoice.value = body
})() })()
</script> </script>

View File

@ -62,5 +62,5 @@ a.selected {
} }
.text-muted { .text-muted {
opacity: 0.5 opacity: 0.67
} }