diff --git a/db/db.go b/db/db.go index fb5e8ca..3ea6524 100644 --- a/db/db.go +++ b/db/db.go @@ -4,8 +4,9 @@ import ( "database/sql" "errors" "fmt" - _ "github.com/lib/pq" "os" + + _ "github.com/lib/pq" ) type Card struct { @@ -29,6 +30,7 @@ type Card struct { One_time_code string Card_name string Allow_negative_balance string + Nostr_priv_key string } type Payment struct { @@ -56,6 +58,11 @@ type Card_wipe_info struct { Uid string } +const ( + NostrPay = iota + NostrRec = iota +) + func open() (*sql.DB, error) { // get connection string from environment variables @@ -720,6 +727,62 @@ func Get_card_txs(card_id int, max_txs int) ([]Transaction, error) { return transactions, nil } +func Get_latest_card_tx(card_id int, pay_rec int) (Transaction, error) { + // open the database + var t Transaction + db, err := open() + + if err != nil { + return t, err + } + + defer db.Close() + + // query the database + sqlStatement := `SELECT card_id, ` + + `card_payments.card_payment_id AS tx_id, 'payment' AS tx_type, ` + + `amount_msats as tx_amount_msats, ` + + `TO_CHAR(payment_status_time, 'DD/MM/YYYY HH24:MI:SS') AS tx_time ` + + `FROM card_payments WHERE card_id = $1 AND payment_status != 'FAILED' ` + + `AND payment_status != '' ` + + `AND amount_msats != 0 ORDER BY payment_status_time DESC LIMIT $2` + if pay_rec == NostrRec { + sqlStatement = `SELECT card_id, card_receipts.card_receipt_id AS tx_id, ` + + `'receipt' AS tx_type, amount_msats as tx_amount_msats, ` + + `TO_CHAR(receipt_status_time, 'DD/MM/YYYY HH24:MI:SS') AS tx_time ` + + `FROM card_receipts WHERE card_id = $1 ` + + `AND receipt_status = 'SETTLED' ORDER BY receipt_status_time DESC LIMIT $2` + } + rows, err := db.Query(sqlStatement, card_id, 1) + + if err != nil { + return t, err + } + + defer rows.Close() + + // prepare the results + + // var transactions []Transaction + + // Loop through rows, using Scan to assign column data to struct fields. + for rows.Next() { + err := rows.Scan(&t.Card_id, &t.Tx_id, &t.Tx_type, &t.Tx_amount_msats, &t.Tx_time) + + if err != nil { + return t, err + } + // transactions = append(transactions, t) + } + + err = rows.Err() + + if err != nil { + return t, err + } + + return t, nil +} func Get_card_total_sats(card_id int) (int, error) { db, err := open() diff --git a/go.mod b/go.mod index 5223a0d..6e63122 100644 --- a/go.mod +++ b/go.mod @@ -52,6 +52,9 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-macaroon-bakery/macaroonpb v1.0.0 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.2.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -72,6 +75,7 @@ require ( github.com/jessevdk/go-flags v1.5.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jonboulle/clockwork v0.3.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/jrick/logrotate v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kkdai/bstream v1.0.0 // indirect @@ -86,16 +90,19 @@ require ( github.com/lightningnetwork/lnd/tlv v1.0.3 // indirect github.com/lightningnetwork/lnd/tor v1.1.0 // indirect github.com/ltcsuite/ltcd v0.22.1-beta // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.50 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nbd-wtf/go-nostr v0.18.10 // indirect github.com/nbd-wtf/ln-decodepay v1.11.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect + github.com/puzpuzpuz/xsync v1.5.2 // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/sendgrid/rest v2.6.9+incompatible // indirect github.com/sendgrid/sendgrid-go v3.12.0+incompatible // indirect @@ -104,6 +111,9 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/testify v1.8.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect @@ -127,9 +137,10 @@ require ( go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.23.0 // indirect golang.org/x/crypto v0.3.0 // indirect + golang.org/x/exp v0.0.0-20221106115401-f9659909a136 // indirect golang.org/x/mod v0.7.0 // indirect golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.2.0 // indirect diff --git a/go.sum b/go.sum index b9afa5f..3fbc337 100644 --- a/go.sum +++ b/go.sum @@ -240,6 +240,12 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-macaroon-bakery/macaroonpb v1.0.0 h1:It9exBaRMZ9iix1iJ6gwzfwsDE6ExNuwtAJ9e09v6XE= github.com/go-macaroon-bakery/macaroonpb v1.0.0/go.mod h1:UzrGOcbiwTXISFP2XDLDPjfhMINZa+fX/7A2lMd31zc= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.2.0 h1:u0p9s3xLYpZCA1z5JgCkMeB34CKCMMQbM+G8Ii7YD0I= +github.com/gobwas/ws v1.2.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -418,6 +424,8 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -503,6 +511,8 @@ github.com/lightningnetwork/lnd/tor v1.1.0/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvK github.com/ltcsuite/ltcd v0.22.1-beta h1:aXeIMuzwPss4VABDyc7Zbx+NMLYFaG3YkNTPNkKL9XA= github.com/ltcsuite/ltcd v0.22.1-beta/go.mod h1:O9R9U/mbZwRgr3So8TlNmW7CPc2ZQVhWyVlhXrqu/vo= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -535,6 +545,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbd-wtf/go-nostr v0.18.10 h1:9kD9U1QkAvqW4CH4CdKagY2wwyZoH80tO/voMZiSisg= +github.com/nbd-wtf/go-nostr v0.18.10/go.mod h1:F9y6+M8askJCjilLgMC3rD0moA6UtG1MCnyClNYXeys= github.com/nbd-wtf/ln-decodepay v1.11.1 h1:MPiT4a4qZ2cKY27Aj0dI8sLFrLz5Ycu72Z3EG1HfPjk= github.com/nbd-wtf/ln-decodepay v1.11.1/go.mod h1:xzBXPaCj/7oRRaui+iYSIxy5LYUjoPfAyAGq2WCyNKk= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= @@ -596,6 +608,8 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/puzpuzpuz/xsync v1.5.2 h1:yRAP4wqSOZG+/4pxJ08fPTwrfL0IzE/LKQ/cw509qGY= +github.com/puzpuzpuz/xsync v1.5.2/go.mod h1:K98BYhX3k1dQ2M63t1YNVDanbwUPmBCAhNmVrrxfiGg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -658,6 +672,12 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= @@ -795,6 +815,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20221106115401-f9659909a136 h1:Fq7F/w7MAa1KJ5bt2aJ62ihqp9HDcRuyILskkpIAurw= +golang.org/x/exp v0.0.0-20221106115401-f9659909a136/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -969,6 +991,8 @@ golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/lnd/lnd.go b/lnd/lnd.go index c5e0c1a..b16fe27 100644 --- a/lnd/lnd.go +++ b/lnd/lnd.go @@ -5,12 +5,13 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - log "github.com/sirupsen/logrus" "io" "io/ioutil" "strconv" "time" + log "github.com/sirupsen/logrus" + decodepay "github.com/fiatjaf/ln-decodepay" lnrpc "github.com/lightningnetwork/lnd/lnrpc" invoicesrpc "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" @@ -21,6 +22,8 @@ import ( "gopkg.in/macaroon.v2" + nostrfy "github.com/boltcard/boltcard/nostr" + "github.com/boltcard/boltcard/db" "github.com/boltcard/boltcard/email" ) @@ -186,7 +189,7 @@ func Monitor_invoice_state(r_hash []byte) { } go email.Send_balance_email(c.Email_address, card_id) - + go nostrfy.SendNostrfication(card_id, c.Card_name, db.NostrRec) return } @@ -294,6 +297,6 @@ func PayInvoice(card_payment_id int, invoice string) { } go email.Send_balance_email(c.Email_address, card_id) - + go nostrfy.SendNostrfication(card_id, c.Card_name, db.NostrPay) return } diff --git a/nostr/nostrfy.go b/nostr/nostrfy.go new file mode 100644 index 0000000..42aa3ef --- /dev/null +++ b/nostr/nostrfy.go @@ -0,0 +1,96 @@ +package nostrfy + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + + "github.com/boltcard/boltcard/db" + "github.com/nbd-wtf/go-nostr" + "github.com/nbd-wtf/go-nostr/nip04" + log "github.com/sirupsen/logrus" +) + +func SendNostrfication(card_id int, card_name string, payOrRec int) { + requestURL := fmt.Sprintf("https://%s/.well-known/nostr.json?name=%s", db.Get_setting("HOST_DOMAIN"), card_name) + req, err := http.NewRequest(http.MethodGet, requestURL, nil) + if err != nil { + log.Warn(err.Error()) + return + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + log.Warn(err.Error()) + return + } + + resBody, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Warn(err.Error()) + } + nipNames := make(map[string]interface{}) + if strings.Contains(string(resBody), "names") { + var res map[string]any + if err := json.Unmarshal([]byte(resBody), &res); err != nil { + log.Warn(err.Error()) + return + } + nnames := res["names"].(map[string]any) + for key, value := range nnames { + nipNames[key] = value.(string) + } + } else { + log.Warn("No NIP-05 addresses...Unable to send payment/receipt info") + return + } + + bolt_bot_privkey := db.Get_setting("NOSTR_BOT_PRIVKEY_HEX") + nostr_rel_list := db.Get_setting("NOSTR_RELAYS_LIST") + if bolt_bot_privkey != "" && nostr_rel_list != "" && len(nipNames) != 0 { + last_tnx, err := db.Get_latest_card_tx(card_id, payOrRec) + if err != nil { + log.Warn(err.Error()) + return + } + nmsg := fmt.Sprintf("you made payment of %d sats via BoltCard", last_tnx.Tx_amount_msats/1000) + if payOrRec == db.NostrRec { + nmsg = fmt.Sprintf("you received %d sats via BoltCard service", last_tnx.Tx_amount_msats/1000) + } + tags := make(nostr.Tags, 0) + for nkey, npub := range nipNames { + msg := fmt.Sprintf("Hey %s, %s - %s", nkey, nmsg, last_tnx.Tx_time) + pub, _ := nostr.GetPublicKey(bolt_bot_privkey) + css, _ := nip04.ComputeSharedSecret(npub.(string), bolt_bot_privkey) + emsg, _ := nip04.Encrypt(msg, css) + tag1 := nostr.Tag{"p", npub.(string)} + tt := tags.AppendUnique(tag1) + ev := nostr.Event{ + PubKey: pub, + CreatedAt: nostr.Now(), + Kind: 4, + Tags: tt, + Content: emsg, + } + // calling Sign sets the event ID field and the event Sig field + ev.Sign(bolt_bot_privkey) + for _, url := range []string{nostr_rel_list} { + ctx := context.WithValue(context.Background(), "url", url) + relay, err := nostr.RelayConnect(ctx, url) + if err != nil { + log.Warn(err.Error()) + continue + } + _, err = relay.Publish(ctx, ev) + if err != nil { + log.Warn(err.Error()) + continue + } + log.WithFields(log.Fields{"published to ": url}).Info("payment/reciept message sent") + } + } + } +}