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/genproto v0.0.0-20190927181202-20e1ac93f88c // indirect
|
||||||
google.golang.org/grpc v1.24.0 // indirect
|
google.golang.org/grpc v1.24.0 // indirect
|
||||||
gopkg.in/errgo.v1 v1.0.1 // 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-bakery.v2 v2.0.1 // indirect
|
||||||
gopkg.in/macaroon.v2 v2.1.0 // indirect
|
gopkg.in/macaroon.v2 v2.1.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.3 // 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.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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
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 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc=
|
||||||
gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA=
|
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=
|
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="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<link rel="stylesheet" href="/index.css" />
|
<link rel="stylesheet" href="/index.css" />
|
||||||
|
<link rel="stylesheet" href="/market.css" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#091833" />
|
<meta name="theme-color" content="#091833" />
|
||||||
{{ if eq .ENV "development" }}
|
{{ if eq .ENV "development" }}
|
||||||
@ -38,7 +39,13 @@
|
|||||||
|_| \___/_____|</pre>
|
|_| \___/_____|</pre>
|
||||||
</strong>
|
</strong>
|
||||||
</code>
|
</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">
|
<div id="qr">
|
||||||
<a href="lightning:{{.lnurl}}">
|
<a href="lightning:{{.lnurl}}">
|
||||||
<img class="m-auto mb-1" src="data:image/png;base64,{{.qr}}" width="100%" />
|
<img class="m-auto mb-1" src="data:image/png;base64,{{.qr}}" width="100%" />
|
||||||
@ -55,7 +62,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
{{ if .RedirectAfterPayment }}
|
||||||
<script>
|
<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>
|
</script>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -112,7 +112,7 @@ func (db *DB) CreateInvoice(invoice *Invoice) error {
|
|||||||
|
|
||||||
func (db *DB) FetchInvoice(invoiceId string, invoice *Invoice) error {
|
func (db *DB) FetchInvoice(invoiceId string, invoice *Invoice) error {
|
||||||
if err := db.QueryRow(""+
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
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)
|
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"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
"gopkg.in/guregu/null.v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Market struct {
|
type Market struct {
|
||||||
@ -43,8 +44,8 @@ type Invoice struct {
|
|||||||
PaymentHash string
|
PaymentHash string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
ExpiresAt time.Time
|
ExpiresAt time.Time
|
||||||
ConfirmedAt time.Time
|
ConfirmedAt null.Time
|
||||||
HeldSince time.Time
|
HeldSince null.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func costFunction(b float64, q1 float64, q2 float64) float64 {
|
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 {
|
func order(c echo.Context) error {
|
||||||
|
marketId := c.Param("id")
|
||||||
// (TBD) Step 0: If SELL order, check share balance of user
|
// (TBD) Step 0: If SELL order, check share balance of user
|
||||||
// (TBD) Step 1: respond with HODL invoice
|
// (TBD) Step 1: respond with HODL invoice
|
||||||
o := new(Order)
|
o := new(Order)
|
||||||
@ -86,11 +88,14 @@ func order(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
go lnd.CheckInvoice(invoice.PaymentHash)
|
go lnd.CheckInvoice(invoice.PaymentHash)
|
||||||
data := map[string]any{
|
data := map[string]any{
|
||||||
"session": c.Get("session"),
|
"session": c.Get("session"),
|
||||||
"ENV": ENV,
|
"ENV": ENV,
|
||||||
"lnurl": invoice.PaymentRequest,
|
"lnurl": invoice.PaymentRequest,
|
||||||
"qr": qr,
|
"qr": qr,
|
||||||
"Invoice": invoice,
|
"Invoice": invoice,
|
||||||
|
"RedirectAfterPayment": true,
|
||||||
|
"PUBLIC_URL": PUBLIC_URL,
|
||||||
|
"MarketId": marketId,
|
||||||
}
|
}
|
||||||
return c.Render(http.StatusPaymentRequired, "invoice.html", data)
|
return c.Render(http.StatusPaymentRequired, "invoice.html", data)
|
||||||
// Step 2: After payment, confirm order if no matching order was found
|
// 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.GET("/market/:id", sessionGuard(market))
|
||||||
e.POST("/market/:id/order", sessionGuard(order))
|
e.POST("/market/:id/order", sessionGuard(order))
|
||||||
e.GET("/invoice/:id", sessionGuard(invoice))
|
e.GET("/invoice/:id", sessionGuard(invoice))
|
||||||
|
e.GET("/api/invoice/:id", sessionGuard(invoiceStatus))
|
||||||
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||||
Format: "${time_custom} ${method} ${uri} ${status}\n",
|
Format: "${time_custom} ${method} ${uri} ${status}\n",
|
||||||
CustomTimeFormat: "2006-01-02 15:04:05.00000-0700",
|
CustomTimeFormat: "2006-01-02 15:04:05.00000-0700",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user