mirror of
https://github.com/bumi/lntip
synced 2026-02-17 22:47:50 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 561610a7b9 | |||
| 6569ac0ded | |||
| 2a4b943887 | |||
| 4fb8fa9a73 | |||
| 492ffb2d3f | |||
| 148dfcba22 | |||
| 1292e5498f | |||
| 9756507514 | |||
| ced2d68630 | |||
| d36f7a49f5 | |||
| 1fff67684a | |||
| 8ff22327c9 | |||
| 7efef4a2b6 | |||
| 031daed750 | |||
| 7283544b40 | |||
| 20e2d8b7e9 | |||
| 1515765c3f | |||
| d403c19aab | |||
| 6e4af5610f | |||
| 19210cc3ce | |||
| 71f6c862fa | |||
| 91c62ed7ed | |||
| fec31b2bd1 | |||
| 6355ce2cc5 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
custom: https://ln.michaelbumann.com?lightning=lnurlp:ln.michaelbumann.com/.well-known/lnurlp/sats
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
vendor
|
||||
config.toml
|
||||
|
||||
data-dir*
|
||||
1
.lndonate
Normal file
1
.lndonate
Normal file
@@ -0,0 +1 @@
|
||||
lnurlp://ln.michaelbumann.com/.well-known/lnurlp/bumi
|
||||
69
README.md
69
README.md
@@ -1,26 +1,30 @@
|
||||
# LnMe - your friendly ⚡ payment page
|
||||
|
||||
LnMe is a personal Bitcoin Lightning payment website and payment widget.
|
||||
LnMe is a personal Bitcoin Lightning payment page/widget and self-hosted [Lightning Address](https://lightningaddress.com/) server.
|
||||
|
||||

|
||||
|
||||
It is a small service written in Go that connects to a [lnd node](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md) and exposes a simple HTTP JSON API to create and monitor invoices.
|
||||
It comes with a configurable personal payment website and offers a JavaScript widget to integrate in existing websites.
|
||||
**See it in action: [ln.michaelbumann.com](https://ln.michaelbumann.com/) - my lightning address: bumi@ln.michaelbumann.com**
|
||||
|
||||
If [webln](https://github.com/wbobeirne/webln) is available the widget automatically use webln to request the payment;
|
||||
otherwise an overlay will be shown with the payment request and a QR code.
|
||||
LnMe focusses on simplicity and ease of deployment. It connects to an existing lightning node (currently LND is supported).
|
||||
|
||||
## Motivation
|
||||
LnMe is one [simple executable](https://github.com/bumi/lnme/releases) file that can be deployed anywhere with no dependencies. (on your own node or for example with [one click on Heroku](#heroku))
|
||||
|
||||
I wanted a simple way for people to send Lightning payments using my own lightning node.
|
||||
|
||||
BTCPay Server is too big and hard to run for that and I do not need most of its features.
|
||||
## Features
|
||||
|
||||
- [x] Embeded payment page - customizable (see demo)
|
||||
- [x] [Lightning Address](https://lightningaddress.com/) support
|
||||
- [x] WebLN integration - if [WebLN](https://webln.dev/) is not available a QRcode and the invoice will be shown
|
||||
- [x] [JavaScript widget](#javascript-widget-integration) for existing websites
|
||||
- [x] [Invoice API](https://github.com/bumi/lnme/wiki/API) - simple REST API to create LN invoices from existing JS code
|
||||
- [ ] [LNURL-pay](https://github.com/fiatjaf/lnurl-rfc/blob/luds/06.md) support
|
||||
|
||||
## Installation
|
||||
|
||||
LnMe connects to your [LND node](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md), so a running LND node is required.
|
||||
LnMe can easily run next to LND on the same system.
|
||||
LnMe can easily run next to LND on the same system or any other hosting provider.
|
||||
|
||||
There are no other dependencies. Simply download the binary and run it!
|
||||
|
||||
1. Download the latest [release](https://github.com/bumi/lnme/releases)
|
||||
2. Run `lnme`
|
||||
@@ -55,6 +59,7 @@ Instead of the path to the macaroon and cert files you can also provide the hex
|
||||
* `static-path`: Path to a folder that you want to serve with LnMe (e.g. /home/bitcoin/lnme/website). Use this if you want to customize your ⚡website. default: disabled
|
||||
* `disable-website`: Disable the default LnMe website. Disable the website if you only want to embed the LnMe widget on your existing website.
|
||||
* `disable-cors`: Disable CORS headers. (default: false)
|
||||
* `disable-ln-address`: Disable [Lightning Address](https://lightningaddress.com/) handling.
|
||||
* `port`: Port to listen on. (default: 1323)
|
||||
* `request-limit`: Limit the allowed requests per second. (default: 5)
|
||||
|
||||
@@ -84,17 +89,36 @@ All environment variables must be prefixed by `LNME_` use `_` instead of `-`
|
||||
|
||||
$ LNME_LND_ADDRESS=127.0.0.1:10005 lnme
|
||||
|
||||
### LND Permissions
|
||||
|
||||
### Deployment
|
||||
LnMe needs the following LND permissions:
|
||||
|
||||
It is the easiest to run LnMe on the same node as LND. But you can run it anywhere as long as your LND node is accessible.
|
||||
* Read/Write permission for invoices
|
||||
* Write permission for onchain address (if you want to use the onchain option)
|
||||
|
||||
#### Heroku
|
||||
Use the LND [macaroon bakery](http://macaroon-bakery.freedomnode.com/) to create a new macaroon for LnMe.
|
||||
|
||||
To get the HEX versions of the files use `xxd -plain` e.g. `xxd -plain invoice.macaroon | tr -d '\n'`
|
||||
|
||||
### TOR
|
||||
|
||||
LnMe can connect to your lightning node through [Tor](https://www.torproject.org/). You need to have Tor installed on your system and then simply provide your LND `.onion` address (don't forget to specify the port).
|
||||
|
||||
|
||||
## Deployment
|
||||
|
||||
It is the easiest to run LnMe on the same node as LND. But you can run it anywhere as long as your LND node is accessible. Simply run the binary and make sure the PORT is accessible.
|
||||
|
||||
### Heroku
|
||||
One click deployment with Heroku:
|
||||
|
||||
You will need your LND address, the LND tls certificate (HEX) and the macaroon (HEX).
|
||||
|
||||
[](https://heroku.com/deploy?template=https://github.com/bumi/lnme)
|
||||
|
||||
#### Notes
|
||||
Here is a [Video Demo of the Heroku deployment](https://www.youtube.com/watch?v=hSFXhnLp_Rc)
|
||||
|
||||
### Deployment Notes
|
||||
|
||||
To run LnMe as systemd service have a look at the [systemd service example config](https://github.com/bumi/lnme/blob/master/examples/lnme.service)
|
||||
|
||||
@@ -109,6 +133,18 @@ lnme.michaelbumann.com {
|
||||
`$ caddy --config /etc/caddy/Caddyfile`
|
||||
|
||||
|
||||
## Feature Usage
|
||||
|
||||
### Lightning Address
|
||||
|
||||
The Lightning Address is an Internet Identifier that allows anyone to send you Bitcoin over the Lightning Network.
|
||||
Lightning Address builds on [LNURL-pay](https://github.com/fiatjaf/lnurl-rfc/blob/luds/06.md) LnMe handles the necessary requests for you.
|
||||
|
||||
For more information check out the website: [lightningaddress.com](https://lightningaddress.com/)
|
||||
|
||||
Your Lightning Address: `{anything}@{your domain}`
|
||||
|
||||
|
||||
### Customize your ⚡ website
|
||||
|
||||
LnMe comes with a default website but you can easily configure and build your own using the the LnMe JavaScript widget or JSON API.
|
||||
@@ -168,6 +204,11 @@ lnme.watchPayment().then(invoice => {
|
||||
|
||||
```
|
||||
|
||||
## Motivation
|
||||
|
||||
I wanted a simple way for people to send Lightning payments using my own lightning node.
|
||||
BTCPay Server is too big and hard to run for that and I do not need most of its features.
|
||||
|
||||
## Development
|
||||
|
||||
Use `go run` to ron the service locally:
|
||||
|
||||
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ go 1.15
|
||||
replace go.etcd.io/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b
|
||||
require (
|
||||
github.com/GeertJohan/go.rice v1.0.2
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/didip/tollbooth/v6 v6.1.1
|
||||
github.com/knadh/koanf v1.2.1
|
||||
github.com/labstack/echo/v4 v4.5.0
|
||||
|
||||
7
go.sum
7
go.sum
@@ -135,6 +135,8 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbp
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
|
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -568,6 +570,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rB
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -599,6 +603,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -636,6 +642,7 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM=
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
|
||||
27
ln/lnd.go
27
ln/lnd.go
@@ -7,12 +7,15 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"gopkg.in/macaroon.v2"
|
||||
|
||||
"github.com/cretz/bine/tor"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
@@ -43,13 +46,14 @@ type LNDclient struct {
|
||||
}
|
||||
|
||||
// AddInvoice generates an invoice with the given price and memo.
|
||||
func (c LNDclient) AddInvoice(value int64, memo string) (Invoice, error) {
|
||||
func (c LNDclient) AddInvoice(value int64, memo string, descriptionHash []byte) (Invoice, error) {
|
||||
result := Invoice{}
|
||||
|
||||
stdOutLogger.Printf("Adding invoice: memo=%s value=%v ", memo, value)
|
||||
stdOutLogger.Printf("Adding invoice: memo=%s value=%v", memo, value)
|
||||
invoice := lnrpc.Invoice{
|
||||
Memo: memo,
|
||||
Value: value,
|
||||
Memo: memo,
|
||||
DescriptionHash: descriptionHash,
|
||||
Value: value,
|
||||
}
|
||||
res, err := c.lndClient.AddInvoice(c.ctx, &invoice)
|
||||
if err != nil {
|
||||
@@ -132,6 +136,21 @@ func NewLNDclient(lndOptions LNDoptions) (LNDclient, error) {
|
||||
grpc.WithTransportCredentials(creds),
|
||||
}
|
||||
|
||||
if strings.Contains(lndOptions.Address, ".onion") {
|
||||
// Start Tor
|
||||
t, err := tor.Start(nil, nil)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
torDialer, err := t.Dialer(context.Background(), nil)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
opts = append(opts, grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
return torDialer.DialContext(ctx, "tcp", addr)
|
||||
}))
|
||||
}
|
||||
|
||||
var macaroonData []byte
|
||||
if lndOptions.MacaroonHex != "" {
|
||||
macBytes, err := hex.DecodeString(lndOptions.MacaroonHex)
|
||||
|
||||
45
lnme.go
45
lnme.go
@@ -1,14 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/bumi/lnme/ln"
|
||||
"github.com/bumi/lnme/lnurl"
|
||||
"github.com/didip/tollbooth/v6"
|
||||
"github.com/didip/tollbooth/v6/limiter"
|
||||
"github.com/knadh/koanf"
|
||||
@@ -105,7 +109,7 @@ func main() {
|
||||
return c.JSON(http.StatusBadRequest, "Bad request")
|
||||
}
|
||||
|
||||
invoice, err := lnClient.AddInvoice(i.Value, i.Memo)
|
||||
invoice, err := lnClient.AddInvoice(i.Value, i.Memo, nil)
|
||||
if err != nil {
|
||||
stdOutLogger.Printf("Error creating invoice: %s", err)
|
||||
return c.JSON(http.StatusInternalServerError, "Error adding invoice")
|
||||
@@ -137,6 +141,44 @@ func main() {
|
||||
return c.JSON(http.StatusOK, invoice)
|
||||
})
|
||||
|
||||
if !cfg.Bool("disable-ln-address") {
|
||||
e.GET("/.well-known/lnurlp/:name", func(c echo.Context) error {
|
||||
name := c.Param("name")
|
||||
lightningAddress := name + "@" + c.Request().Host
|
||||
lnurlMetadata := "[[\"text/identifier\", \"" + lightningAddress + "\"], [\"text/plain\", \"Sats for " + lightningAddress + "\"]]"
|
||||
|
||||
if amount := c.QueryParam("amount"); amount == "" {
|
||||
lnurlPayResponse1 := lnurl.LNURLPayResponse1{
|
||||
LNURLResponse: lnurl.LNURLResponse{Status: "OK"},
|
||||
Callback: fmt.Sprintf("%s://%s%s", c.Scheme(), c.Request().Host, c.Request().URL.Path),
|
||||
MinSendable: 1000,
|
||||
MaxSendable: 100000000,
|
||||
EncodedMetadata: lnurlMetadata,
|
||||
CommentAllowed: 0,
|
||||
Tag: "payRequest",
|
||||
}
|
||||
return c.JSON(http.StatusOK, lnurlPayResponse1)
|
||||
} else {
|
||||
stdOutLogger.Printf("New LightningAddress request amount: %s", amount)
|
||||
msats, err := strconv.ParseInt(amount, 10, 64)
|
||||
if err != nil || msats < 1000 {
|
||||
return c.JSON(http.StatusOK, lnurl.LNURLErrorResponse{Status: "ERROR", Reason: "Invalid Amount"})
|
||||
}
|
||||
sats := msats / 1000 // we need sats
|
||||
metadataHash := sha256.Sum256([]byte(lnurlMetadata))
|
||||
invoice, err := lnClient.AddInvoice(sats, lightningAddress, metadataHash[:])
|
||||
lnurlPayResponse2 := lnurl.LNURLPayResponse2{
|
||||
LNURLResponse: lnurl.LNURLResponse{Status: "OK"},
|
||||
PR: invoice.PaymentRequest,
|
||||
Routes: make([][]lnurl.RouteInfo, 0),
|
||||
Disposable: false,
|
||||
SuccessAction: &lnurl.SuccessAction{Tag: "message", Message: "Thanks, payment received!"},
|
||||
}
|
||||
return c.JSON(http.StatusOK, lnurlPayResponse2)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Debug test endpoint
|
||||
e.GET("/ping", func(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, "pong")
|
||||
@@ -157,6 +199,7 @@ func LoadConfig() *koanf.Koanf {
|
||||
f.String("lnd-macaroon-path", "~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon", "Path to the LND macaroon file.")
|
||||
f.String("lnd-cert-path", "~/.lnd/tls.cert", "Path to the LND tls.cert file.")
|
||||
f.Bool("disable-website", false, "Disable default embedded website.")
|
||||
f.Bool("disable-ln-address", false, "Disable Lightning Address handling")
|
||||
f.Bool("disable-cors", false, "Disable CORS headers.")
|
||||
f.Float64("request-limit", 5, "Request limit per second.")
|
||||
f.String("static-path", "", "Path to a static assets directory.")
|
||||
|
||||
52
lnurl/types.go
Normal file
52
lnurl/types.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// THANKS: https://github.com/fiatjaf/go-lnurl/blob/d50a8e916232580895822178fe36e0f5cf400554/base.go
|
||||
// only using the LNURL types here
|
||||
package lnurl
|
||||
|
||||
import "net/url"
|
||||
|
||||
type LNURLResponse struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type LNURLPayResponse1 struct {
|
||||
LNURLResponse
|
||||
Callback string `json:"callback"`
|
||||
CallbackURL *url.URL `json:"-"`
|
||||
Tag string `json:"tag"`
|
||||
MaxSendable int64 `json:"maxSendable"`
|
||||
MinSendable int64 `json:"minSendable"`
|
||||
EncodedMetadata string `json:"metadata"`
|
||||
Metadata Metadata `json:"-"`
|
||||
CommentAllowed int64 `json:"commentAllowed"`
|
||||
}
|
||||
|
||||
type LNURLPayResponse2 struct {
|
||||
LNURLResponse
|
||||
SuccessAction *SuccessAction `json:"successAction"`
|
||||
Routes [][]RouteInfo `json:"routes"`
|
||||
PR string `json:"pr"`
|
||||
Disposable bool `json:"disposable,omitempty"`
|
||||
}
|
||||
|
||||
type RouteInfo struct {
|
||||
NodeId string `json:"nodeId"`
|
||||
ChannelUpdate string `json:"channelUpdate"`
|
||||
}
|
||||
|
||||
type SuccessAction struct {
|
||||
Tag string `json:"tag"`
|
||||
Description string `json:"description,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Ciphertext string `json:"ciphertext,omitempty"`
|
||||
IV string `json:"iv,omitempty"`
|
||||
}
|
||||
|
||||
type LNURLErrorResponse struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
URL *url.URL `json:"-"`
|
||||
}
|
||||
|
||||
type Metadata [][]string
|
||||
Reference in New Issue
Block a user