Redirect after payment
This commit is contained in:
parent
921623ee4d
commit
e5f5759871
1
go.mod
1
go.mod
|
@ -92,6 +92,7 @@ require (
|
|||
google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c // indirect
|
||||
google.golang.org/grpc v1.24.0 // indirect
|
||||
gopkg.in/errgo.v1 v1.0.1 // indirect
|
||||
gopkg.in/guregu/null.v4 v4.0.0 // indirect
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1 // indirect
|
||||
gopkg.in/macaroon.v2 v2.1.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.3 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -358,6 +358,8 @@ gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
|
|||
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
|
||||
gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI=
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc=
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA=
|
||||
gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I=
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<link rel="stylesheet" href="/market.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#091833" />
|
||||
{{ if eq .ENV "development" }}
|
||||
|
@ -38,7 +39,13 @@
|
|||
|_| \___/_____|</pre>
|
||||
</strong>
|
||||
</code>
|
||||
<div class="font-mono mb-1">Payment Required</div>
|
||||
<div class="font-mono mb-1">
|
||||
<div class="mb-1">Payment Required</div>
|
||||
<div id="paid" class="yes" hidden>
|
||||
<div>Paid</div>
|
||||
<div id="countdown">Redirecting in 3 ...</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="qr">
|
||||
<a href="lightning:{{.lnurl}}">
|
||||
<img class="m-auto mb-1" src="data:image/png;base64,{{.qr}}" width="100%" />
|
||||
|
@ -55,7 +62,28 @@
|
|||
</div>
|
||||
</div>
|
||||
</body>
|
||||
{{ if .RedirectAfterPayment }}
|
||||
<script>
|
||||
const invoiceId = "{{.Invoice.Id}}"
|
||||
const paid = document.querySelector("#paid")
|
||||
const countdown = document.querySelector("#countdown")
|
||||
const interval = setInterval(async () => {
|
||||
const body = await fetch(`/api/invoice/${invoiceId}`)
|
||||
.then((r) => r.json())
|
||||
.catch(console.error)
|
||||
if (body.ConfirmedAt) {
|
||||
paid.removeAttribute("hidden")
|
||||
clearInterval(interval)
|
||||
let timer = 2
|
||||
const redirect = setInterval(() => {
|
||||
countdown.textContent = `Redirecting in ${timer--} ...`
|
||||
if (timer === -1) {
|
||||
window.location.href = "https://{{.PUBLIC_URL}}/market/{{.MarketId}}";
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
}, 1000)
|
||||
</script>
|
||||
{{ end }}
|
||||
|
||||
</html>
|
|
@ -112,7 +112,7 @@ func (db *DB) CreateInvoice(invoice *Invoice) error {
|
|||
|
||||
func (db *DB) FetchInvoice(invoiceId string, invoice *Invoice) error {
|
||||
if err := db.QueryRow(""+
|
||||
"SELECT id, pubkey, msats, preimage, hash, bolt11, created_at, expires_at FROM invoices WHERE id = $1", invoiceId).Scan(&invoice.Id, &invoice.Pubkey, &invoice.Msats, &invoice.Preimage, &invoice.PaymentHash, &invoice.PaymentRequest, &invoice.CreatedAt, &invoice.ExpiresAt); err != nil {
|
||||
"SELECT id, pubkey, msats, preimage, hash, bolt11, created_at, expires_at, confirmed_at, held_since FROM invoices WHERE id = $1", invoiceId).Scan(&invoice.Id, &invoice.Pubkey, &invoice.Msats, &invoice.Preimage, &invoice.PaymentHash, &invoice.PaymentRequest, &invoice.CreatedAt, &invoice.ExpiresAt, &invoice.ConfirmedAt, &invoice.HeldSince); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
16
src/lnd.go
16
src/lnd.go
|
@ -122,3 +122,19 @@ func invoice(c echo.Context) error {
|
|||
}
|
||||
return c.Render(http.StatusOK, "invoice.html", data)
|
||||
}
|
||||
|
||||
func invoiceStatus(c echo.Context) error {
|
||||
invoiceId := c.Param("id")
|
||||
var invoice Invoice
|
||||
if err := db.FetchInvoice(invoiceId, &invoice); err == sql.ErrNoRows {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
session := c.Get("session").(Session)
|
||||
if invoice.Pubkey != session.Pubkey {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
|
||||
}
|
||||
invoice.Preimage = ""
|
||||
return c.JSON(http.StatusOK, invoice)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"gopkg.in/guregu/null.v4"
|
||||
)
|
||||
|
||||
type Market struct {
|
||||
|
@ -43,8 +44,8 @@ type Invoice struct {
|
|||
PaymentHash string
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
ConfirmedAt time.Time
|
||||
HeldSince time.Time
|
||||
ConfirmedAt null.Time
|
||||
HeldSince null.Time
|
||||
}
|
||||
|
||||
func costFunction(b float64, q1 float64, q2 float64) float64 {
|
||||
|
@ -63,6 +64,7 @@ func BinaryLMSR(invariant int, funding int, q1 int, q2 int, dq1 int) float64 {
|
|||
}
|
||||
|
||||
func order(c echo.Context) error {
|
||||
marketId := c.Param("id")
|
||||
// (TBD) Step 0: If SELL order, check share balance of user
|
||||
// (TBD) Step 1: respond with HODL invoice
|
||||
o := new(Order)
|
||||
|
@ -86,11 +88,14 @@ func order(c echo.Context) error {
|
|||
}
|
||||
go lnd.CheckInvoice(invoice.PaymentHash)
|
||||
data := map[string]any{
|
||||
"session": c.Get("session"),
|
||||
"ENV": ENV,
|
||||
"lnurl": invoice.PaymentRequest,
|
||||
"qr": qr,
|
||||
"Invoice": invoice,
|
||||
"session": c.Get("session"),
|
||||
"ENV": ENV,
|
||||
"lnurl": invoice.PaymentRequest,
|
||||
"qr": qr,
|
||||
"Invoice": invoice,
|
||||
"RedirectAfterPayment": true,
|
||||
"PUBLIC_URL": PUBLIC_URL,
|
||||
"MarketId": marketId,
|
||||
}
|
||||
return c.Render(http.StatusPaymentRequired, "invoice.html", data)
|
||||
// Step 2: After payment, confirm order if no matching order was found
|
||||
|
|
|
@ -66,6 +66,7 @@ func main() {
|
|||
e.GET("/market/:id", sessionGuard(market))
|
||||
e.POST("/market/:id/order", sessionGuard(order))
|
||||
e.GET("/invoice/:id", sessionGuard(invoice))
|
||||
e.GET("/api/invoice/:id", sessionGuard(invoiceStatus))
|
||||
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||
Format: "${time_custom} ${method} ${uri} ${status}\n",
|
||||
CustomTimeFormat: "2006-01-02 15:04:05.00000-0700",
|
||||
|
|
Loading…
Reference in New Issue