diff --git a/alby.go b/alby.go index 8cff560a..87fee178 100644 --- a/alby.go +++ b/alby.go @@ -93,6 +93,21 @@ func (svc *AlbyOAuthService) MakeInvoice(ctx context.Context, senderPubkey strin }).Errorf("App not found: %v", err) return "", "", err } + + // amount provided in msat, but Alby API currently only supports sats. Will get truncated to a whole sat value + var amountSat int64 = amount / 1000 + // make sure amount is not converted to 0 + if (amount > 0 && amountSat == 0) { + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "amount": amount, + "description": description, + "descriptionHash": descriptionHash, + "expiry": expiry, + }).Errorf("Value must be 1 sat or greater"); + return "", "", errors.New("Value must be 1 sat or greater") + } + svc.Logger.WithFields(logrus.Fields{ "senderPubkey": senderPubkey, "amount": amount, @@ -110,7 +125,7 @@ func (svc *AlbyOAuthService) MakeInvoice(ctx context.Context, senderPubkey strin body := bytes.NewBuffer([]byte{}) payload := &MakeInvoiceRequest{ - Amount: amount, + Amount: amountSat, Description: description, DescriptionHash: descriptionHash, // TODO: support expiry diff --git a/go.mod b/go.mod index b0bf125c..c82c8063 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( google.golang.org/grpc v1.53.0 gopkg.in/DataDog/dd-trace-go.v1 v1.47.0 gopkg.in/macaroon.v2 v2.1.0 - gorm.io/gorm v1.24.0 + gorm.io/gorm v1.25.0 ) require ( @@ -152,12 +152,12 @@ require ( go.uber.org/zap v1.24.0 // indirect go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.9.0 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect @@ -186,12 +186,14 @@ require ( github.com/getsentry/sentry-go v0.23.0 github.com/glebarez/sqlite v1.5.0 github.com/gorilla/websocket v1.5.0 // indirect + github.com/jackc/pgx/v5 v5.4.3 github.com/joho/godotenv v1.5.1 github.com/kelseyhightower/envconfig v1.4.0 github.com/lightningnetwork/lnd v0.15.5-beta.rc2 + github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/sirupsen/logrus v1.9.0 github.com/valyala/fastjson v1.6.3 // indirect github.com/ziflex/lecho/v3 v3.5.0 golang.org/x/exp v0.0.0-20221106115401-f9659909a136 // indirect - gorm.io/driver/postgres v1.4.4 + gorm.io/driver/postgres v1.5.2 ) diff --git a/go.sum b/go.sum index b756cd19..feeb197c 100644 --- a/go.sum +++ b/go.sum @@ -202,6 +202,7 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2U github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/decred/dcrd/lru v1.1.1 h1:kWFDaW0OWx6AD6Ki342c+JPmHbiVdE6rK81pT3fuo/Y= github.com/decred/dcrd/lru v1.1.1/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -266,6 +267,7 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 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-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -282,6 +284,7 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -451,6 +454,8 @@ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgS github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0= github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= +github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -592,6 +597,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -900,8 +907,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -988,8 +995,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1080,13 +1087,13 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.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= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1096,8 +1103,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1314,11 +1321,13 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.4.4 h1:zt1fxJ+C+ajparn0SteEnkoPg0BQ6wOWXEQ99bteAmw= -gorm.io/driver/postgres v1.4.4/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= -gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74= +gorm.io/driver/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw= +gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/driver/sqlserver v1.0.4 h1:V15fszi0XAo7fbx3/cF50ngshDSN4QT0MXpWTylyPTY= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= +gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/handle_balance_request.go b/handle_balance_request.go index 7a115044..586daf2a 100644 --- a/handle_balance_request.go +++ b/handle_balance_request.go @@ -49,7 +49,7 @@ func (svc *Service) HandleGetBalanceEvent(ctx context.Context, request *Nip47Req "eventKind": event.Kind, "appId": app.ID, }).Infof("Failed to fetch balance: %v", err) - nostrEvent.State = "error" + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_ERROR svc.db.Save(&nostrEvent) return svc.createResponse(event, Nip47Response{ Error: &Nip47Error{ @@ -72,7 +72,7 @@ func (svc *Service) HandleGetBalanceEvent(ctx context.Context, request *Nip47Req responsePayload.BudgetRenewal = appPermission.BudgetRenewal } - nostrEvent.State = "executed" + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_EXECUTED svc.db.Save(&nostrEvent) return svc.createResponse(event, Nip47Response{ ResultType: NIP_47_GET_BALANCE_METHOD, diff --git a/handle_make_invoice_request.go b/handle_make_invoice_request.go index c3e548d0..96790a3f 100644 --- a/handle_make_invoice_request.go +++ b/handle_make_invoice_request.go @@ -53,6 +53,21 @@ func (svc *Service) HandleMakeInvoiceEvent(ctx context.Context, request *Nip47Re return nil, err } + if makeInvoiceParams.Description != "" && makeInvoiceParams.DescriptionHash != "" { + svc.Logger.WithFields(logrus.Fields{ + "eventId": event.ID, + "eventKind": event.Kind, + "appId": app.ID, + }).Errorf("Only one of description, description_hash can be provided") + + return svc.createResponse(event, Nip47Response{ + Error: &Nip47Error{ + Code: NIP_47_OTHER, + Message: "Only one of description, description_hash can be provided", + }, + }, ss) + } + svc.Logger.WithFields(logrus.Fields{ "eventId": event.ID, "eventKind": event.Kind, @@ -63,6 +78,8 @@ func (svc *Service) HandleMakeInvoiceEvent(ctx context.Context, request *Nip47Re "expiry": makeInvoiceParams.Expiry, }).Info("Making invoice") + + invoice, paymentHash, err := svc.lnClient.MakeInvoice(ctx, event.PubKey, makeInvoiceParams.Amount, makeInvoiceParams.Description, makeInvoiceParams.DescriptionHash, makeInvoiceParams.Expiry) if err != nil { svc.Logger.WithFields(logrus.Fields{ @@ -74,7 +91,7 @@ func (svc *Service) HandleMakeInvoiceEvent(ctx context.Context, request *Nip47Re "descriptionHash": makeInvoiceParams.DescriptionHash, "expiry": makeInvoiceParams.Expiry, }).Infof("Failed to make invoice: %v", err) - nostrEvent.State = "error" + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_ERROR svc.db.Save(&nostrEvent) return svc.createResponse(event, Nip47Response{ Error: &Nip47Error{ @@ -89,10 +106,10 @@ func (svc *Service) HandleMakeInvoiceEvent(ctx context.Context, request *Nip47Re PaymentHash: paymentHash, } - nostrEvent.State = "executed" + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_EXECUTED svc.db.Save(&nostrEvent) return svc.createResponse(event, Nip47Response{ - ResultType: NIP_47_GET_BALANCE_METHOD, + ResultType: NIP_47_MAKE_INVOICE_METHOD, Result: responsePayload, }, ss) diff --git a/handle_payment_request.go b/handle_payment_request.go index 3aee1daa..3355eeff 100644 --- a/handle_payment_request.go +++ b/handle_payment_request.go @@ -89,7 +89,7 @@ func (svc *Service) HandlePayInvoiceEvent(ctx context.Context, request *Nip47Req "appId": app.ID, "bolt11": bolt11, }).Infof("Failed to send payment: %v", err) - nostrEvent.State = "error" + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_ERROR svc.db.Save(&nostrEvent) return svc.createResponse(event, Nip47Response{ Error: &Nip47Error{ @@ -99,7 +99,7 @@ func (svc *Service) HandlePayInvoiceEvent(ctx context.Context, request *Nip47Req }, ss) } payment.Preimage = preimage - nostrEvent.State = "executed" + nostrEvent.State = NOSTR_EVENT_STATE_HANDLER_EXECUTED svc.db.Save(&nostrEvent) svc.db.Save(&payment) return svc.createResponse(event, Nip47Response{ diff --git a/lnd.go b/lnd.go index fa1ebac4..3954ca28 100644 --- a/lnd.go +++ b/lnd.go @@ -3,7 +3,7 @@ package main import ( "context" "encoding/hex" - "fmt" + "errors" "github.com/getAlby/nostr-wallet-connect/lnd" @@ -51,7 +51,29 @@ func (svc *LNDService) GetBalance(ctx context.Context, senderPubkey string) (bal } func (svc *LNDService) MakeInvoice(ctx context.Context, senderPubkey string, amount int64, description string, descriptionHash string, expiry int64) (invoice string, paymentHash string, err error) { - return "", "", fmt.Errorf("not implemented") + var descriptionHashBytes []byte + + if descriptionHash != "" { + descriptionHashBytes, err = hex.DecodeString(descriptionHash) + + if err != nil || len(descriptionHashBytes) != 32 { + svc.Logger.WithFields(logrus.Fields{ + "senderPubkey": senderPubkey, + "amount": amount, + "description": description, + "descriptionHash": descriptionHash, + "expiry": expiry, + }).Errorf("Invalid description hash") + return "", "", errors.New("Description hash must be 32 bytes hex") + } + } + + resp, err := svc.client.AddInvoice(ctx, &lnrpc.Invoice{ValueMsat: amount, Memo: description, DescriptionHash: descriptionHashBytes, Expiry: expiry}) + if err != nil { + return "", "", err + } + + return resp.GetPaymentRequest(), hex.EncodeToString(resp.GetRHash()), nil } func (svc *LNDService) SendPaymentSync(ctx context.Context, senderPubkey, payReq string) (preimage string, err error) { diff --git a/main.go b/main.go index 8db651fe..305b605b 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "database/sql" "fmt" "net/http" "os" @@ -21,6 +22,10 @@ import ( "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" "gorm.io/driver/postgres" "gorm.io/gorm" + + "github.com/jackc/pgx/v5/stdlib" + sqltrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql" + gormtrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/gorm.io/gorm.v1" ) func main() { @@ -34,12 +39,28 @@ func main() { } var db *gorm.DB + var sqlDb *sql.DB if strings.HasPrefix(cfg.DatabaseUri, "postgres://") || strings.HasPrefix(cfg.DatabaseUri, "postgresql://") || strings.HasPrefix(cfg.DatabaseUri, "unix://") { - db, err = gorm.Open(postgres.Open(cfg.DatabaseUri), &gorm.Config{}) - if err != nil { - log.Fatalf("Failed to open DB %v", err) + if os.Getenv("DATADOG_AGENT_URL") != "" { + sqltrace.Register("pgx", &stdlib.Driver{}, sqltrace.WithServiceName("nostr-wallet-connect")) + sqlDb, err = sqltrace.Open("pgx", cfg.DatabaseUri) + if err != nil { + log.Fatalf("Failed to open DB %v", err) + } + db, err = gormtrace.Open(postgres.New(postgres.Config{Conn: sqlDb}), &gorm.Config{}) + if err != nil { + log.Fatalf("Failed to open DB %v", err) + } + } else { + db, err = gorm.Open(postgres.Open(cfg.DatabaseUri), &gorm.Config{}) + if err != nil { + log.Fatalf("Failed to open DB %v", err) + } + sqlDb, err = db.DB() + if err != nil { + log.Fatalf("Failed to set DB config: %v", err) + } } - } else { db, err = gorm.Open(sqlite.Open(cfg.DatabaseUri), &gorm.Config{}) if err != nil { @@ -49,10 +70,10 @@ func main() { cfg.DatabaseMaxConns = 1 // Enable foreign keys for sqlite db.Exec("PRAGMA foreign_keys=ON;") - } - sqlDb, err := db.DB() - if err != nil { - log.Fatalf("Failed set DB config: %v", err) + sqlDb, err = db.DB() + if err != nil { + log.Fatalf("Failed to set DB config: %v", err) + } } sqlDb.SetMaxOpenConns(cfg.DatabaseMaxConns) sqlDb.SetMaxIdleConns(cfg.DatabaseMaxIdleConns) diff --git a/models.go b/models.go index b82d54ab..b7e38908 100644 --- a/models.go +++ b/models.go @@ -21,9 +21,18 @@ const ( NIP_47_ERROR_UNAUTHORIZED = "UNAUTHORIZED" NIP_47_ERROR_EXPIRED = "EXPIRED" NIP_47_ERROR_RESTRICTED = "RESTRICTED" + NIP_47_OTHER = "OTHER" NIP_47_CAPABILITIES = "pay_invoice,get_balance" ) +const ( + NOSTR_EVENT_STATE_HANDLER_EXECUTED = "executed" + NOSTR_EVENT_STATE_HANDLER_ERROR = "error" + NOSTR_EVENT_STATE_PUBLISH_CONFIRMED = "replied" + NOSTR_EVENT_STATE_PUBLISH_FAILED = "failed" + NOSTR_EVENT_STATE_PUBLISH_UNCONFIRMED = "sent" +) + var nip47MethodDescriptions = map[string]string{ NIP_47_GET_BALANCE_METHOD: "Read your balance.", NIP_47_PAY_INVOICE_METHOD: "Send payments from your wallet.", diff --git a/service.go b/service.go index 12f9e786..dba42a42 100644 --- a/service.go +++ b/service.go @@ -26,6 +26,7 @@ type Service struct { var supportedMethods = map[string]bool{ NIP_47_PAY_INVOICE_METHOD: true, NIP_47_GET_BALANCE_METHOD: true, + NIP_47_MAKE_INVOICE_METHOD: true, } func (svc *Service) GetUser(c echo.Context) (user *User, err error) { @@ -79,7 +80,7 @@ func (svc *Service) StartSubscription(ctx context.Context, sub *nostr.Subscripti nostrEvent.ReplyId = resp.ID // https://github.com/nbd-wtf/go-nostr/blob/master/relay.go#L321 if status == nostr.PublishStatusSucceeded { - nostrEvent.State = "replied" + nostrEvent.State = NOSTR_EVENT_STATE_PUBLISH_CONFIRMED nostrEvent.RepliedAt = time.Now() svc.db.Save(&nostrEvent) svc.Logger.WithFields(logrus.Fields{ @@ -90,7 +91,7 @@ func (svc *Service) StartSubscription(ctx context.Context, sub *nostr.Subscripti "appId": nostrEvent.AppId, }).Info("Published reply") } else if status == nostr.PublishStatusFailed { - nostrEvent.State = "failed" + nostrEvent.State = NOSTR_EVENT_STATE_PUBLISH_FAILED svc.db.Save(&nostrEvent) svc.Logger.WithFields(logrus.Fields{ "nostrEventId": nostrEvent.ID, @@ -100,7 +101,7 @@ func (svc *Service) StartSubscription(ctx context.Context, sub *nostr.Subscripti "appId": nostrEvent.AppId, }).Info("Failed to publish reply") } else { - nostrEvent.State = "sent" + nostrEvent.State = NOSTR_EVENT_STATE_PUBLISH_UNCONFIRMED svc.db.Save(&nostrEvent) svc.Logger.WithFields(logrus.Fields{ "nostrEventId": nostrEvent.ID, diff --git a/service_test.go b/service_test.go index b113a3b5..72d9dde3 100644 --- a/service_test.go +++ b/service_test.go @@ -28,7 +28,6 @@ const nip47MakeInvoiceJson = ` "params": { "amount": 1000, "description": "[[\"text/identifier\",\"hello@getalby.com\"],[\"text/plain\",\"Sats for Alby\"]]", - "description_hash": "7da78494568d0c8afcd972ea5f5464d6f8d222025c04704e3d19c338ed61cd1f", "expiry": 3600 } }