diff --git a/.github/workflows/http.yml b/.github/workflows/http.yml index c0145bfc..1f96453f 100644 --- a/.github/workflows/http.yml +++ b/.github/workflows/http.yml @@ -30,19 +30,16 @@ jobs: [ { arch: x86_64, - breez_arch: linux-amd64, alby_arch: x86_64-unknown-linux-gnu, os: ubuntu-20.04, }, { arch: armv6, - breez_arch: "", alby_arch: arm-unknown-linux-gnueabihf, os: ubuntu-20.04, }, { arch: aarch64, - breez_arch: linux-aarch64, alby_arch: aarch64-unknown-linux-gnu, os: ubuntu-20.04, }, @@ -113,7 +110,7 @@ jobs: echo "GOARCH=arm" >> $GITHUB_ENV echo "GOARM=6" >> $GITHUB_ENV echo "CC=$GITHUB_WORKSPACE/armv6-unknown-linux-gnueabihf/bin/armv6-unknown-linux-gnueabihf-gcc" >> $GITHUB_ENV - echo "GOTAGS=-tags skip_breez,netgo" >> $GITHUB_ENV + echo "GOTAGS=-tags netgo" >> $GITHUB_ENV - name: Install ARM64 cross-compiler if: matrix.build.arch == 'aarch64' @@ -143,10 +140,6 @@ jobs: if: runner.os == 'Linux' run: | mkdir -p ./build/bin/${{ env.PACKAGE_NAME }}/lib - if [ "${{ matrix.build.breez_arch }}" != "" ]; then - cp `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/${{ matrix.build.breez_arch }}/libbreez_sdk_bindings.so ./build/bin/${{ env.PACKAGE_NAME }}/lib/ - fi - cp `go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go`/glalby/${{ matrix.build.alby_arch }}/libglalby_bindings.so ./build/bin/${{ env.PACKAGE_NAME }}/lib/ cp `go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go`/ldk_node/${{ matrix.build.alby_arch }}/libldk_node.so ./build/bin/${{ env.PACKAGE_NAME }}/lib/ shell: bash @@ -158,8 +151,6 @@ jobs: - name: Copy shared libraries to the output directory if: runner.os == 'macOS' run: | - lipo -create -output ./build/bin/${{ env.PACKAGE_NAME }}/lib/libbreez_sdk_bindings.dylib `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/darwin-aarch64/libbreez_sdk_bindings.dylib `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/darwin-amd64/libbreez_sdk_bindings.dylib - cp `go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go`/glalby/universal-macos/libglalby_bindings.dylib ./build/bin/${{ env.PACKAGE_NAME }}/lib/ cp `go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go`/ldk_node/universal-macos/libldk_node.dylib ./build/bin/${{ env.PACKAGE_NAME }}/lib/ shell: bash diff --git a/.github/workflows/wails.yml b/.github/workflows/wails.yml index 12bb7b49..3f13ecc3 100644 --- a/.github/workflows/wails.yml +++ b/.github/workflows/wails.yml @@ -101,8 +101,6 @@ jobs: - name: Copy shared libraries if: runner.os == 'Windows' run: | - cp `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/windows-amd64/breez_sdk_bindings.dll ./ - cp `go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go`/glalby/x86_64-pc-windows-msvc/glalby_bindings.dll ./ cp `go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go`/ldk_node/x86_64-pc-windows-msvc/ldk_node.dll ./ shell: bash @@ -142,8 +140,6 @@ jobs: - name: Copy DLLs to the output directory if: runner.os == 'Windows' run: | - cp breez_sdk_bindings.dll ./build/bin/ - cp glalby_bindings.dll ./build/bin/ cp ldk_node.dll ./build/bin/ shell: bash @@ -151,8 +147,6 @@ jobs: if: runner.os == 'Linux' run: | mkdir -p ./build/bin/${{ env.PACKAGE_NAME }}/lib - cp `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/linux-amd64/libbreez_sdk_bindings.so ./build/bin/${{ env.PACKAGE_NAME }}/lib/ - cp `go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go`/glalby/x86_64-unknown-linux-gnu/libglalby_bindings.so ./build/bin/${{ env.PACKAGE_NAME }}/lib/ cp `go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go`/ldk_node/x86_64-unknown-linux-gnu/libldk_node.so ./build/bin/${{ env.PACKAGE_NAME }}/lib/ mkdir -p ./build/bin/${{ env.PACKAGE_NAME }}/bin mv "./build/bin/${{ env.EXEC_NAME }}" ./build/bin/${{ env.PACKAGE_NAME }}/bin/ @@ -167,8 +161,6 @@ jobs: if: runner.os == 'macOS' run: | mkdir -p "./build/bin/${{ env.EXEC_NAME }}.app/Contents/Frameworks" - lipo -create -output "./build/bin/${{ env.EXEC_NAME }}.app/Contents/Frameworks/libbreez_sdk_bindings.dylib" `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/darwin-aarch64/libbreez_sdk_bindings.dylib `go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go`/breez_sdk/lib/darwin-amd64/libbreez_sdk_bindings.dylib - cp `go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go`/glalby/universal-macos/libglalby_bindings.dylib "./build/bin/${{ env.EXEC_NAME }}.app/Contents/Frameworks/" cp `go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go`/ldk_node/universal-macos/libldk_node.dylib "./build/bin/${{ env.EXEC_NAME }}.app/Contents/Frameworks/" shell: bash diff --git a/Dockerfile b/Dockerfile index d06fb4d8..9b5aa6cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,8 +49,6 @@ ENV LD_LIBRARY_PATH=/usr/lib/nwc # # # Copy the binaries and entrypoint from the builder image. COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=builder /build/libbreez_sdk_bindings.so /usr/lib/nwc/ -COPY --from=builder /build/libglalby_bindings.so /usr/lib/nwc/ COPY --from=builder /build/libldk_node.so /usr/lib/nwc/ COPY --from=builder /build/main /bin/ diff --git a/README.md b/README.md index 6253e321..6ff1b497 100644 --- a/README.md +++ b/README.md @@ -138,10 +138,6 @@ For more information refer to: $ go run -ldflags="-X 'github.com/getAlby/hub/version.Tag=v0.6.0'" cmd/http/main.go -### Windows - -Breez SDK requires gcc to build the Breez bindings. Run `choco install mingw` and copy the breez SDK bindings file into the root of this directory (from your go installation directory) as per the [Breez SDK instructions](https://github.com/breez/breez-sdk-go?tab=readme-ov-file#windows). ALSO copy the bindings file into the output directory alongside the .exe in order to run it. - ## Optional configuration parameters The following configuration options can be set as environment variables or in a .env file @@ -356,10 +352,6 @@ You can also contribute to our [bounty program](https://github.com/getAlby/light - ⚠️ PAYMENT_FAILED error code not supported -### Breez - -(Supported methods coming soon) - ## Node Distributions Run NWC on your own node! @@ -488,7 +480,7 @@ At a high level Alby Hub is an [NWC](https://nwc.dev) wallet service which allow ### LNClient -The LNClient interface abstracts the differences between wallet implementations and allows users to run Alby Hub with their preferred wallet, such as LDK, LND, Phoenixd, Cashu, Breez, Greenlight. +The LNClient interface abstracts the differences between wallet implementations and allows users to run Alby Hub with their preferred wallet, such as LDK, LND, Phoenixd, Cashu. ### Transactions Service diff --git a/api/api.go b/api/api.go index cda9575b..23270089 100644 --- a/api/api.go +++ b/api/api.go @@ -889,13 +889,6 @@ func (api *api) Setup(ctx context.Context, setupRequest *SetupRequest) error { return err } } - if setupRequest.BreezAPIKey != "" { - err = api.cfg.SetUpdate("BreezAPIKey", setupRequest.BreezAPIKey, setupRequest.UnlockPassword) - if err != nil { - logger.Logger.WithError(err).Error("Failed to save breez api key") - return err - } - } if setupRequest.Mnemonic != "" { err = api.cfg.SetUpdate("Mnemonic", setupRequest.Mnemonic, setupRequest.UnlockPassword) if err != nil { @@ -903,13 +896,6 @@ func (api *api) Setup(ctx context.Context, setupRequest *SetupRequest) error { return err } } - if setupRequest.GreenlightInviteCode != "" { - err = api.cfg.SetUpdate("GreenlightInviteCode", setupRequest.GreenlightInviteCode, setupRequest.UnlockPassword) - if err != nil { - logger.Logger.WithError(err).Error("Failed to save greenlight invite code") - return err - } - } if setupRequest.LNDAddress != "" { err = api.cfg.SetUpdate("LNDAddress", setupRequest.LNDAddress, setupRequest.UnlockPassword) if err != nil { diff --git a/api/models.go b/api/models.go index 706c3828..1a25ddce 100644 --- a/api/models.go +++ b/api/models.go @@ -130,13 +130,8 @@ type SetupRequest struct { LNBackendType string `json:"backendType"` UnlockPassword string `json:"unlockPassword"` - // Breez / Greenlight - Mnemonic string `json:"mnemonic"` - GreenlightInviteCode string `json:"greenlightInviteCode"` - NextBackupReminder string `json:"nextBackupReminder"` - - // Breez fields - BreezAPIKey string `json:"breezApiKey"` + Mnemonic string `json:"mnemonic"` + NextBackupReminder string `json:"nextBackupReminder"` // LND fields LNDAddress string `json:"lndAddress"` diff --git a/build/darwin/gon-sign.json b/build/darwin/gon-sign.json index 7f1f7a7e..8168756f 100644 --- a/build/darwin/gon-sign.json +++ b/build/darwin/gon-sign.json @@ -1,9 +1,7 @@ { "source": [ "./build/bin/AlbyHub.app", - "./build/bin/AlbyHub.app/Contents/MacOS/AlbyHub", - "./build/bin/AlbyHub.app/Contents/Frameworks/libbreez_sdk_bindings.dylib", - "./build/bin/AlbyHub.app/Contents/Frameworks/libglalby_bindings.dylib" + "./build/bin/AlbyHub.app/Contents/MacOS/AlbyHub" ], "bundle_id": "com.getalby.AlbyHub", "sign": { diff --git a/build/docker/copy_dylibs.sh b/build/docker/copy_dylibs.sh index d649960c..7eaa94e3 100644 --- a/build/docker/copy_dylibs.sh +++ b/build/docker/copy_dylibs.sh @@ -3,12 +3,8 @@ ARCH="$1" if [[ "$ARCH" == "amd64" ]]; then - cp "$(go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go)"/breez_sdk/lib/linux-amd64/libbreez_sdk_bindings.so ./ - cp "$(go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go)"/glalby/x86_64-unknown-linux-gnu/libglalby_bindings.so ./ cp "$(go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go)"/ldk_node/x86_64-unknown-linux-gnu/libldk_node.so ./ elif [[ "$ARCH" == "arm64" ]]; then - cp "$(go list -m -f "{{.Dir}}" github.com/breez/breez-sdk-go)"/breez_sdk/lib/linux-aarch64/libbreez_sdk_bindings.so ./ - cp "$(go list -m -f "{{.Dir}}" github.com/getAlby/glalby-go)"/glalby/aarch64-unknown-linux-gnu/libglalby_bindings.so ./ cp "$(go list -m -f "{{.Dir}}" github.com/getAlby/ldk-node-go)"/ldk_node/aarch64-unknown-linux-gnu/libldk_node.so ./ else echo "Invalid ARCH value" diff --git a/config/models.go b/config/models.go index 58b67eff..91e3905e 100644 --- a/config/models.go +++ b/config/models.go @@ -1,12 +1,10 @@ package config const ( - LNDBackendType = "LND" - GreenlightBackendType = "GREENLIGHT" - LDKBackendType = "LDK" - BreezBackendType = "BREEZ" - PhoenixBackendType = "PHOENIX" - CashuBackendType = "CASHU" + LNDBackendType = "LND" + LDKBackendType = "LDK" + PhoenixBackendType = "PHOENIX" + CashuBackendType = "CASHU" ) const ( diff --git a/frontend/src/components/BreezRedeem.tsx b/frontend/src/components/BreezRedeem.tsx deleted file mode 100644 index 6217578c..00000000 --- a/frontend/src/components/BreezRedeem.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { RocketIcon } from "lucide-react"; -import { Alert, AlertDescription, AlertTitle } from "src/components/ui/alert"; -import { LinkButton } from "src/components/ui/button"; -import { ONCHAIN_DUST_SATS } from "src/constants"; -import { useBalances } from "src/hooks/useBalances"; -import { useInfo } from "src/hooks/useInfo"; - -export default function BreezRedeem() { - const { data: info } = useInfo(); - if (info?.backendType !== "BREEZ") { - return null; - } - return ; -} - -function BreezRedeemInternal() { - const { data: balances } = useBalances(); - - if (!balances || balances.onchain.spendable <= ONCHAIN_DUST_SATS) { - return null; - } - - return ( -
- - - Breez channel closed - -
- One of your Breez channels was closed and you have{" "} - {balances.onchain.spendable} sats to redeem. -
- - Redeem - -
-
-
- ); -} diff --git a/frontend/src/lib/backendType.ts b/frontend/src/lib/backendType.ts index c429a022..51df4948 100644 --- a/frontend/src/lib/backendType.ts +++ b/frontend/src/lib/backendType.ts @@ -12,16 +12,6 @@ export const backendTypeConfigs: Record = { hasChannelManagement: true, hasNodeBackup: false, }, - BREEZ: { - hasMnemonic: true, - hasChannelManagement: false, - hasNodeBackup: false, - }, - GREENLIGHT: { - hasMnemonic: true, - hasChannelManagement: true, - hasNodeBackup: false, - }, LDK: { hasMnemonic: true, hasChannelManagement: true, diff --git a/frontend/src/routes.tsx b/frontend/src/routes.tsx index fa3486ee..be9068a6 100644 --- a/frontend/src/routes.tsx +++ b/frontend/src/routes.tsx @@ -59,9 +59,7 @@ import { SetupFinish } from "src/screens/setup/SetupFinish"; import { SetupNode } from "src/screens/setup/SetupNode"; import { SetupPassword } from "src/screens/setup/SetupPassword"; import { SetupSecurity } from "src/screens/setup/SetupSecurity"; -import { BreezForm } from "src/screens/setup/node/BreezForm"; import { CashuForm } from "src/screens/setup/node/CashuForm"; -import { GreenlightForm } from "src/screens/setup/node/GreenlightForm"; import { LDKForm } from "src/screens/setup/node/LDKForm"; import { LNDForm } from "src/screens/setup/node/LNDForm"; import { PhoenixdForm } from "src/screens/setup/node/PhoenixdForm"; @@ -431,14 +429,6 @@ const routes = [ index: true, element: , }, - { - path: "breez", - element: , - }, - { - path: "greenlight", - element: , - }, { path: "cashu", element: , diff --git a/frontend/src/screens/setup/node/BreezForm.tsx b/frontend/src/screens/setup/node/BreezForm.tsx deleted file mode 100644 index 508ed5f1..00000000 --- a/frontend/src/screens/setup/node/BreezForm.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React from "react"; -import { useNavigate } from "react-router-dom"; -import Container from "src/components/Container"; -import TwoColumnLayoutHeader from "src/components/TwoColumnLayoutHeader"; -import { Button } from "src/components/ui/button"; -import { Input } from "src/components/ui/input"; -import { Label } from "src/components/ui/label"; -import { useToast } from "src/components/ui/use-toast"; -import useSetupStore from "src/state/SetupStore"; - -export function BreezForm() { - const { toast } = useToast(); - const navigate = useNavigate(); - const setupStore = useSetupStore(); - const [greenlightInviteCode, setGreenlightInviteCode] = - React.useState(setupStore.nodeInfo.greenlightInviteCode || ""); - const [breezApiKey, setBreezApiKey] = React.useState( - setupStore.nodeInfo.breezApiKey || "" - ); - - async function handleSubmit(data: object) { - setupStore.updateNodeInfo({ - backendType: "BREEZ", - ...data, - }); - navigate("/setup/import-mnemonic"); - } - - function onSubmit(e: React.FormEvent) { - e.preventDefault(); - if (!greenlightInviteCode || !breezApiKey) { - toast({ - title: "Please fill out all fields", - variant: "destructive", - }); - return; - } - handleSubmit({ - greenlightInviteCode, - breezApiKey, - }); - } - - return ( - - -
-
- - setGreenlightInviteCode(e.target.value)} - value={greenlightInviteCode} - type="text" - id="greenlight-invite-code" - placeholder="XXXX-YYYY" - /> -
-
- - setBreezApiKey(e.target.value)} - value={breezApiKey} - autoComplete="off" - type="text" - id="breez-api-key" - /> -
- -
-
- ); -} diff --git a/frontend/src/screens/setup/node/GreenlightForm.tsx b/frontend/src/screens/setup/node/GreenlightForm.tsx deleted file mode 100644 index bdc928d2..00000000 --- a/frontend/src/screens/setup/node/GreenlightForm.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from "react"; -import { useNavigate } from "react-router-dom"; -import Container from "src/components/Container"; -import TwoColumnLayoutHeader from "src/components/TwoColumnLayoutHeader"; -import { Button } from "src/components/ui/button"; -import { Input } from "src/components/ui/input"; -import { Label } from "src/components/ui/label"; -import { useToast } from "src/components/ui/use-toast"; -import useSetupStore from "src/state/SetupStore"; - -export function GreenlightForm() { - const { toast } = useToast(); - const navigate = useNavigate(); - const setupStore = useSetupStore(); - const [greenlightInviteCode, setGreenlightInviteCode] = - React.useState(setupStore.nodeInfo.greenlightInviteCode || ""); - - async function handleSubmit(data: object) { - setupStore.updateNodeInfo({ - backendType: "GREENLIGHT", - ...data, - }); - navigate("/setup/import-mnemonic"); - } - - function onSubmit(e: React.FormEvent) { - e.preventDefault(); - if (!greenlightInviteCode) { - toast({ - title: "Please fill out all fields", - variant: "destructive", - }); - return; - } - handleSubmit({ - greenlightInviteCode, - }); - } - - return ( - - -
-
- - setGreenlightInviteCode(e.target.value)} - value={greenlightInviteCode} - type="text" - id="greenlight-invite-code" - placeholder="XXXX-YYYY" - /> -
- -
-
- ); -} diff --git a/frontend/src/screens/wallet/index.tsx b/frontend/src/screens/wallet/index.tsx index 3be8e37d..fd90bbcd 100644 --- a/frontend/src/screens/wallet/index.tsx +++ b/frontend/src/screens/wallet/index.tsx @@ -6,7 +6,6 @@ import { } from "lucide-react"; import { Link } from "react-router-dom"; import AppHeader from "src/components/AppHeader"; -import BreezRedeem from "src/components/BreezRedeem"; import ExternalLink from "src/components/ExternalLink"; import FormattedFiatAmount from "src/components/FormattedFiatAmount"; import Loading from "src/components/Loading"; @@ -78,7 +77,6 @@ function Wallet() { )} -
diff --git a/frontend/src/types.ts b/frontend/src/types.ts index cd570111..886848b8 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -11,13 +11,7 @@ import { WalletMinimal, } from "lucide-react"; -export type BackendType = - | "LND" - | "BREEZ" - | "GREENLIGHT" - | "LDK" - | "PHOENIX" - | "CASHU"; +export type BackendType = "LND" | "LDK" | "PHOENIX" | "CASHU"; export type Nip47RequestMethod = | "get_info" @@ -331,8 +325,6 @@ export type SetupNodeInfo = Partial<{ mnemonic?: string; nextBackupReminder?: string; - greenlightInviteCode?: string; - breezApiKey?: string; lndAddress?: string; lndCertHex?: string; diff --git a/go.mod b/go.mod index 6e928772..1e7d73ac 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,7 @@ toolchain go1.23.3 require ( github.com/adrg/xdg v0.5.3 - github.com/breez/breez-sdk-go v0.5.2 github.com/elnosh/gonuts v0.4.0 - github.com/getAlby/glalby-go v0.0.0-20240621192717-95673c864d59 github.com/getAlby/ldk-node-go v0.0.0-20250313063409-c465f4e6e089 github.com/go-gormigrate/gormigrate/v2 v2.1.3 github.com/labstack/echo/v4 v4.13.3 diff --git a/go.sum b/go.sum index 927f6cd7..d5db9912 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= -github.com/breez/breez-sdk-go v0.5.2 h1:frqX14cKTM2egWP7C53u3SzBkYQrgx9P7si/Ig9Droo= -github.com/breez/breez-sdk-go v0.5.2/go.mod h1:EalYMEeQVwRzr6UXnF4QpLlpuWNwQQN9xwtDKNIutBo= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= @@ -205,8 +203,6 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/getAlby/glalby-go v0.0.0-20240621192717-95673c864d59 h1:fSqdXE9uKhLcOOQaLtzN+D8RN3oEcZQkGX5E8PyiKy0= -github.com/getAlby/glalby-go v0.0.0-20240621192717-95673c864d59/go.mod h1:ViyJvjlvv0GCesTJ7mb3fBo4G+/qsujDAFN90xZ7a9U= github.com/getAlby/ldk-node-go v0.0.0-20250313063409-c465f4e6e089 h1:39wtrlg8SxbjJDj/hGdhS4GPlDk9kwxTy36kvrDP5mU= github.com/getAlby/ldk-node-go v0.0.0-20250313063409-c465f4e6e089/go.mod h1:8BRjtKcz8E0RyYTPEbMS8VIdgredcGSLne8vHDtcRLg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= diff --git a/lnclient/breez/breez.go b/lnclient/breez/breez.go deleted file mode 100644 index cbfaa347..00000000 --- a/lnclient/breez/breez.go +++ /dev/null @@ -1,503 +0,0 @@ -//go:build !skip_breez - -package breez - -import ( - "context" - "encoding/hex" - "errors" - "log" - "os" - "path/filepath" - "strings" - "time" - - "github.com/breez/breez-sdk-go/breez_sdk" - decodepay "github.com/nbd-wtf/ln-decodepay" - "github.com/sirupsen/logrus" - - "github.com/getAlby/hub/lnclient" - "github.com/getAlby/hub/logger" -) - -type BreezService struct { - listener *BreezListener - svc *breez_sdk.BlockingBreezServices - pubkey string -} -type BreezListener struct { -} - -func (listener BreezListener) Log(l breez_sdk.LogEntry) { - logLevel := logrus.InfoLevel - if l.Level == "TRACE" || l.Level == "DEBUG" || strings.Contains(l.Line, "connection to node lost") || strings.Contains(l.Line, "Restore channel") { - logLevel = logrus.DebugLevel - } - - logger.Logger.WithField("level", l.Level).Log(logLevel, l.Line) -} - -func (BreezListener) OnEvent(e breez_sdk.BreezEvent) { - log.Printf("received event %#v", e) -} - -func NewBreezService(mnemonic, apiKey, inviteCode, workDir string) (result lnclient.LNClient, err error) { - if mnemonic == "" || apiKey == "" || inviteCode == "" || workDir == "" { - return nil, errors.New("one or more required breez configuration are missing") - } - - // create dir if not exists - newpath := filepath.Join(workDir) - err = os.MkdirAll(newpath, os.ModePerm) - if err != nil { - return nil, err - } - seed, err := breez_sdk.MnemonicToSeed(mnemonic) - if err != nil { - return nil, err - } - nodeConfig := breez_sdk.NodeConfigGreenlight{ - Config: breez_sdk.GreenlightNodeConfig{ - InviteCode: &inviteCode, - }, - } - listener := BreezListener{} - config := breez_sdk.DefaultConfig(breez_sdk.EnvironmentTypeProduction, apiKey, nodeConfig) - config.WorkingDir = workDir - breez_sdk.SetLogStream(listener) - svc, err := breez_sdk.Connect(breez_sdk.ConnectRequest{ - Config: config, - Seed: seed, - }, listener) - if err != nil { - return nil, err - } - - nodeInfo, err := svc.NodeInfo() - if err != nil { - return nil, err - } - logger.Logger.WithField("info", nodeInfo).Info("Node info") - logger.Logger.WithFields(logrus.Fields{ - "ln balance": nodeInfo.ChannelsBalanceMsat, - "balance": nodeInfo.OnchainBalanceMsat, - "max_payable_msat": nodeInfo.MaxPayableMsat, - "max_receivable_msat": nodeInfo.MaxReceivableMsat, - "max_single_payment_amount_msat": nodeInfo.MaxSinglePaymentAmountMsat, - "connected_peers": nodeInfo.ConnectedPeers, - "inbound_liquidity_msats": nodeInfo.InboundLiquidityMsats, - }).Info("node balances and peers") - - return &BreezService{ - listener: &listener, - svc: svc, - pubkey: nodeInfo.Id, - }, nil -} - -func (bs *BreezService) Shutdown() error { - return bs.svc.Disconnect() -} - -func (bs *BreezService) SendPaymentSync(ctx context.Context, payReq string, amount *uint64) (*lnclient.PayInvoiceResponse, error) { - if amount != nil { - return nil, errors.New("0-amount invoices not supported") - } - sendPaymentRequest := breez_sdk.SendPaymentRequest{ - Bolt11: payReq, - } - resp, err := bs.svc.SendPayment(sendPaymentRequest) - if err != nil { - return nil, err - } - var lnDetails breez_sdk.PaymentDetailsLn - if resp.Payment.Details != nil { - lnDetails, _ = resp.Payment.Details.(breez_sdk.PaymentDetailsLn) - } - return &lnclient.PayInvoiceResponse{ - Preimage: lnDetails.Data.PaymentPreimage, - }, nil - -} - -func (bs *BreezService) SendKeysend(ctx context.Context, amount uint64, destination string, custom_records []lnclient.TLVRecord, preimage string) (*lnclient.PayKeysendResponse, error) { - // TODO: re-enable when passing custom preimage is possible - /*extraTlvs := []breez_sdk.TlvEntry{} - for _, record := range custom_records { - decodedValue, err := hex.DecodeString(record.Value) - if err != nil { - return "", "", 0, err - } - extraTlvs = append(extraTlvs, breez_sdk.TlvEntry{ - FieldNumber: record.Type, - Value: decodedValue, - }) - } - - sendSpontaneousPaymentRequest := breez_sdk.SendSpontaneousPaymentRequest{ - NodeId: destination, - AmountMsat: amount, - ExtraTlvs: &extraTlvs, - } - resp, err := bs.svc.SendSpontaneousPayment(sendSpontaneousPaymentRequest) - if err != nil { - return "", "", 0, err - } - var lnDetails breez_sdk.PaymentDetailsLn - if resp.Payment.Details != nil { - lnDetails, _ = resp.Payment.Details.(breez_sdk.PaymentDetailsLn) - } - return lnDetails.Data.PaymentHash, lnDetails.Data.PaymentPreimage, resp.Payment.FeeMsat, nil*/ - return nil, errors.New("not supported") -} - -func (bs *BreezService) MakeInvoice(ctx context.Context, amount int64, description string, descriptionHash string, expiry int64) (transaction *lnclient.Transaction, err error) { - if expiry == 0 { - expiry = lnclient.DEFAULT_INVOICE_EXPIRY - } - - expiry32 := uint32(expiry) - receivePaymentRequest := breez_sdk.ReceivePaymentRequest{ - // amount provided in msat - AmountMsat: uint64(amount), - Description: description, - Expiry: &expiry32, - } - resp, err := bs.svc.ReceivePayment(receivePaymentRequest) - if err != nil { - return nil, err - } - - tx := &lnclient.Transaction{ - Type: "incoming", - Invoice: resp.LnInvoice.Bolt11, - Preimage: hex.EncodeToString(resp.LnInvoice.PaymentSecret), - PaymentHash: resp.LnInvoice.PaymentHash, - FeesPaid: 0, - CreatedAt: int64(resp.LnInvoice.Timestamp), - SettledAt: nil, - Metadata: nil, - } - - if resp.LnInvoice.Description != nil { - tx.Description = *resp.LnInvoice.Description - } - if resp.LnInvoice.DescriptionHash != nil { - tx.DescriptionHash = *resp.LnInvoice.DescriptionHash - } - if resp.LnInvoice.AmountMsat != nil { - tx.Amount = int64(*resp.LnInvoice.AmountMsat) - } - invExpiry := int64(resp.LnInvoice.Expiry) - tx.ExpiresAt = &invExpiry - return tx, nil -} - -func (bs *BreezService) LookupInvoice(ctx context.Context, paymentHash string) (transaction *lnclient.Transaction, err error) { - log.Printf("p: %v", paymentHash) - payment, err := bs.svc.PaymentByHash(paymentHash) - if err != nil { - return nil, err - } - if payment != nil { - log.Printf("p: %v", payment) - transaction, err = breezPaymentToTransaction(payment) - if err != nil { - return nil, err - } - return transaction, nil - } else { - return nil, errors.New("not found") - } -} - -func (bs *BreezService) ListTransactions(ctx context.Context, from, until, limit, offset uint64, unpaid bool, invoiceType string) (transactions []lnclient.Transaction, err error) { - - request := breez_sdk.ListPaymentsRequest{} - if limit > 0 { - limit32 := uint32(limit) - request.Limit = &limit32 - } - if offset > 0 { - offset32 := uint32(offset) - request.Offset = &offset32 - } - if from > 0 { - from64 := int64(from) - request.FromTimestamp = &from64 - } - if until > 0 { - until64 := int64(until) - request.ToTimestamp = &until64 - } - - payments, err := bs.svc.ListPayments(request) - if err != nil { - return nil, err - } - - transactions = []lnclient.Transaction{} - for _, payment := range payments { - if payment.PaymentType != breez_sdk.PaymentTypeReceived && payment.PaymentType != breez_sdk.PaymentTypeSent { - // skip other types of payments for now - continue - } - - transaction, err := breezPaymentToTransaction(&payment) - if err == nil { - transactions = append(transactions, *transaction) - } - } - return transactions, nil -} - -func (bs *BreezService) GetInfo(ctx context.Context) (info *lnclient.NodeInfo, err error) { - return &lnclient.NodeInfo{ - Alias: "breez", - Color: "", - Pubkey: "", - Network: "mainnet", - BlockHeight: 0, - BlockHash: "", - }, nil -} - -func (bs *BreezService) ListChannels(ctx context.Context) ([]lnclient.Channel, error) { - channels := []lnclient.Channel{} - return channels, nil -} - -func (bs *BreezService) GetNodeConnectionInfo(ctx context.Context) (nodeConnectionInfo *lnclient.NodeConnectionInfo, err error) { - return &lnclient.NodeConnectionInfo{}, nil -} - -func (bs *BreezService) ConnectPeer(ctx context.Context, connectPeerRequest *lnclient.ConnectPeerRequest) error { - return nil -} -func (bs *BreezService) OpenChannel(ctx context.Context, openChannelRequest *lnclient.OpenChannelRequest) (*lnclient.OpenChannelResponse, error) { - return nil, nil -} - -func (bs *BreezService) CloseChannel(ctx context.Context, closeChannelRequest *lnclient.CloseChannelRequest) (*lnclient.CloseChannelResponse, error) { - return nil, nil -} - -func breezPaymentToTransaction(payment *breez_sdk.Payment) (*lnclient.Transaction, error) { - var lnDetails breez_sdk.PaymentDetailsLn - if payment.Details != nil { - lnDetails, _ = payment.Details.(breez_sdk.PaymentDetailsLn) - } - var txType string - if payment.PaymentType == breez_sdk.PaymentTypeSent { - txType = "outgoing" - } else { - txType = "incoming" - } - - createdAt := payment.PaymentTime - var expiresAt *int64 - description := lnDetails.Data.Label - descriptionHash := "" - - if lnDetails.Data.Bolt11 != "" { - // TODO: Breez should provide these details so we don't need to manually decode the invoice - paymentRequest, err := decodepay.Decodepay(strings.ToLower(lnDetails.Data.Bolt11)) - if err != nil { - log.Printf("Failed to decode bolt11 invoice: %v", payment) - return nil, err - } - - createdAt = int64(paymentRequest.CreatedAt) - expiresAtUnix := time.UnixMilli(int64(paymentRequest.CreatedAt) * 1000).Add(time.Duration(paymentRequest.Expiry) * time.Second).Unix() - expiresAt = &expiresAtUnix - description = paymentRequest.Description - descriptionHash = paymentRequest.DescriptionHash - } - - tx := &lnclient.Transaction{ - Type: txType, - Invoice: lnDetails.Data.Bolt11, - Preimage: lnDetails.Data.PaymentPreimage, - PaymentHash: lnDetails.Data.PaymentHash, - Amount: int64(payment.AmountMsat), - FeesPaid: int64(payment.FeeMsat), - CreatedAt: createdAt, - ExpiresAt: expiresAt, - Metadata: nil, - Description: description, - DescriptionHash: descriptionHash, - } - if payment.Status == breez_sdk.PaymentStatusComplete { - settledAt := payment.PaymentTime - tx.SettledAt = &settledAt - } - - if payment.Description != nil { - tx.Description = *payment.Description - } - - return tx, nil -} - -func (bs *BreezService) GetNewOnchainAddress(ctx context.Context) (string, error) { - // The below code works but is not needed and there's no Breez UI to support it. - // Plus, it creates complexity with the deposit limits. - /*swapInfo, err := bs.svc.ReceiveOnchain(breez_sdk.ReceiveOnchainRequest{}) - - if err != nil { - logger.Logger.Errorf("Failed to get onchain address: %v", err) - return "", err - } - logger.Logger.Infof("This address has deposit limits! Min: %d Max: %d", swapInfo.MinAllowedDeposit, swapInfo.MaxAllowedDeposit) - - return swapInfo.BitcoinAddress, nil*/ - return "", nil -} - -func (bs *BreezService) GetOnchainBalance(ctx context.Context) (*lnclient.OnchainBalanceResponse, error) { - response, err := bs.svc.NodeInfo() - - if err != nil { - logger.Logger.Errorf("Failed to get node info: %v", err) - return nil, err - } - - return &lnclient.OnchainBalanceResponse{ - Spendable: int64(response.OnchainBalanceMsat) / 1000, - Total: int64(response.OnchainBalanceMsat+response.PendingOnchainBalanceMsat) / 1000, - }, nil -} - -func (bs *BreezService) RedeemOnchainFunds(ctx context.Context, toAddress string, amount uint64, sendAll bool) (txId string, err error) { - if !sendAll { - return "", errors.New("only send all is supported") - } - - if toAddress == "" { - return "", errors.New("No address provided") - } - - recommendedFees, err := bs.svc.RecommendedFees() - if err != nil { - logger.Logger.Errorf("Failed to get recommended fees info: %v", err) - return "", err - } - - satPerVbyte := uint32(recommendedFees.FastestFee) - prepareReq := breez_sdk.PrepareRedeemOnchainFundsRequest{SatPerVbyte: satPerVbyte, ToAddress: toAddress} - prepareRedeemOnchainFundsResponse, err := bs.svc.PrepareRedeemOnchainFunds(prepareReq) - - if err != nil { - logger.Logger.Errorf("Failed to prepare onchain address: %v", err) - return "", err - } - logger.Logger.Infof("PrepareRedeemOnchainFunds response: %#v", prepareRedeemOnchainFundsResponse) - - redeemReq := breez_sdk.RedeemOnchainFundsRequest{SatPerVbyte: satPerVbyte, ToAddress: toAddress} - redeemOnchainFundsResponse, err := bs.svc.RedeemOnchainFunds(redeemReq) - - if err != nil { - logger.Logger.Errorf("Failed to redeem onchain funds: %v", err) - return "", err - } - - logger.Logger.Infof("RedeemOnchainFunds response: %#v", redeemOnchainFundsResponse) - return hex.EncodeToString(redeemOnchainFundsResponse.Txid), nil -} - -func (bs *BreezService) ResetRouter(key string) error { - return nil -} - -func (bs *BreezService) SendPaymentProbes(ctx context.Context, invoice string) error { - return nil -} - -func (bs *BreezService) SendSpontaneousPaymentProbes(ctx context.Context, amountMsat uint64, nodeId string) error { - return nil -} - -func (bs *BreezService) ListPeers(ctx context.Context) ([]lnclient.PeerDetails, error) { - return nil, nil -} - -func (bs *BreezService) GetLogOutput(ctx context.Context, maxLen int) ([]byte, error) { - return []byte{}, nil -} - -func (bs *BreezService) GetNodeStatus(ctx context.Context) (nodeStatus *lnclient.NodeStatus, err error) { - return &lnclient.NodeStatus{ - IsReady: true, - }, nil -} - -func (bs *BreezService) SignMessage(ctx context.Context, message string) (string, error) { - resp, err := bs.svc.SignMessage(breez_sdk.SignMessageRequest{ - Message: message, - }) - if err != nil { - return "", err - } - - return resp.Signature, nil -} - -func (bs *BreezService) GetBalances(ctx context.Context) (*lnclient.BalancesResponse, error) { - info, err := bs.svc.NodeInfo() - if err != nil { - return nil, err - } - - return &lnclient.BalancesResponse{ - Onchain: lnclient.OnchainBalanceResponse{ - Spendable: int64(info.OnchainBalanceMsat) / 1000, - Total: int64(info.OnchainBalanceMsat+info.PendingOnchainBalanceMsat) / 1000, - }, - Lightning: lnclient.LightningBalanceResponse{ - TotalSpendable: int64(info.MaxPayableMsat), - TotalReceivable: int64(info.MaxReceivableMsat), - NextMaxSpendable: int64(info.MaxSinglePaymentAmountMsat), - NextMaxReceivable: int64(info.MaxReceivableMsat), - NextMaxSpendableMPP: int64(info.MaxSinglePaymentAmountMsat), - NextMaxReceivableMPP: int64(info.MaxReceivableMsat), - }, - }, nil -} - -func (bs *BreezService) GetStorageDir() (string, error) { - return "", nil -} - -func (bs *BreezService) GetNetworkGraph(ctx context.Context, nodeIds []string) (lnclient.NetworkGraphResponse, error) { - return nil, nil -} - -func (bs *BreezService) UpdateLastWalletSyncRequest() {} - -func (bs *BreezService) UpdateChannel(ctx context.Context, updateChannelRequest *lnclient.UpdateChannelRequest) error { - return nil -} - -func (bs *BreezService) DisconnectPeer(ctx context.Context, peerId string) error { - return nil -} - -func (bs *BreezService) GetSupportedNIP47Methods() []string { - return []string{"pay_invoice" /*"pay_keysend",*/, "get_balance", "get_budget", "get_info", "make_invoice", "lookup_invoice", "list_transactions", "multi_pay_invoice", "multi_pay_keysend", "sign_message"} -} - -func (bs *BreezService) GetSupportedNIP47NotificationTypes() []string { - return []string{} -} - -func (bs *BreezService) GetPubkey() string { - return bs.pubkey -} - -func (bs *BreezService) GetCustomNodeCommandDefinitions() []lnclient.CustomNodeCommandDef { - return nil -} - -func (bs *BreezService) ExecuteCustomNodeCommand(ctx context.Context, command *lnclient.CustomNodeCommandRequest) (*lnclient.CustomNodeCommandResponse, error) { - return nil, nil -} diff --git a/lnclient/breez/breez_stub.go b/lnclient/breez/breez_stub.go deleted file mode 100644 index e7169c88..00000000 --- a/lnclient/breez/breez_stub.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build skip_breez - -package breez - -import ( - "github.com/getAlby/hub/lnclient" -) - -func NewBreezService(mnemonic, apiKey, inviteCode, workDir string) (result lnclient.LNClient, err error) { - panic("not implemented") - return nil, nil -} diff --git a/lnclient/greenlight/greenlight.go b/lnclient/greenlight/greenlight.go deleted file mode 100644 index 48e61190..00000000 --- a/lnclient/greenlight/greenlight.go +++ /dev/null @@ -1,699 +0,0 @@ -package greenlight - -import ( - "context" - "errors" - "log" - "math/rand" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "time" - - // "github.com/getAlby/hub/glalby" // for local development only - - "github.com/getAlby/glalby-go/glalby" - decodepay "github.com/nbd-wtf/ln-decodepay" - "github.com/sirupsen/logrus" - - "github.com/getAlby/hub/config" - "github.com/getAlby/hub/lnclient" - "github.com/getAlby/hub/logger" -) - -type GreenlightService struct { - workdir string - client *glalby.BlockingGreenlightAlbyClient - pubkey string -} - -const DEVICE_CREDENTIALS_KEY = "GreenlightCreds" - -func NewGreenlightService(cfg config.Config, mnemonic, inviteCode, workDir, encryptionKey string) (result lnclient.LNClient, err error) { - if mnemonic == "" || inviteCode == "" || workDir == "" { - return nil, errors.New("one or more required greenlight configuration are missing") - } - - // create dir if not exists - newpath := filepath.Join(workDir) - err = os.MkdirAll(newpath, os.ModePerm) - if err != nil { - log.Printf("Failed to create greenlight working dir: %v", err) - return nil, err - } - - var credentials *glalby.GreenlightCredentials - existingDeviceCreds, _ := cfg.Get(DEVICE_CREDENTIALS_KEY, encryptionKey) - - if existingDeviceCreds != "" { - credentials = &glalby.GreenlightCredentials{ - GlCreds: existingDeviceCreds, - } - logger.Logger.Info("Using saved greenlight credentials") - } - - if credentials == nil { - logger.Logger.Info("No greenlight credentials found, attempting to recover existing node") - recoveredCredentials, err := glalby.Recover(mnemonic) - credentials = &recoveredCredentials - - if err != nil { - logger.Logger.Errorf("Failed to recover node: %v", err) - logger.Logger.Infof("Trying to register instead...") - recoveredCredentials, err := glalby.Register(mnemonic, inviteCode) - credentials = &recoveredCredentials - - if err != nil { - logger.Logger.WithError(err).Error("Failed to register new node") - return nil, err - } - } - - if credentials == nil || credentials.GlCreds == "" { - return nil, errors.New("unexpected response from Recover") - } - err = cfg.SetUpdate(DEVICE_CREDENTIALS_KEY, credentials.GlCreds, encryptionKey) - if err != nil { - logger.Logger.WithError(err).Error("Failed to save greenlight credentials") - return nil, err - } - } - - client, err := glalby.NewBlockingGreenlightAlbyClient(mnemonic, *credentials) - - if err != nil { - log.Printf("Failed to create greenlight alby client: %v", err) - return nil, err - } - if client == nil { - logger.Logger.Error("unexpected response from NewBlockingGreenlightAlbyClient") - } - - nodeInfo, err := client.GetInfo() - - gs := GreenlightService{ - workdir: newpath, - client: client, - pubkey: nodeInfo.Pubkey, - } - - if err != nil { - return nil, err - } - - log.Printf("Node info: %v", nodeInfo) - - return &gs, nil -} - -func (gs *GreenlightService) Shutdown() error { - _, err := gs.client.Shutdown() - if err != nil { - logger.Logger.WithError(err).Error("Failed to shutdown greenlight node") - return err - } - return nil -} - -func (gs *GreenlightService) SendPaymentSync(ctx context.Context, payReq string, amount *uint64) (*lnclient.PayInvoiceResponse, error) { - if amount != nil { - return nil, errors.New("0-amount invoices not supported") - } - response, err := gs.client.Pay(glalby.PayRequest{ - Bolt11: payReq, - }) - - if err != nil { - logger.Logger.Errorf("Failed to send payment: %v", err) - return nil, err - } - log.Printf("SendPaymentSync succeeded: %v", response.Preimage) - return &lnclient.PayInvoiceResponse{ - Preimage: response.Preimage, - }, nil -} - -func (gs *GreenlightService) SendKeysend(ctx context.Context, amount uint64, destination string, custom_records []lnclient.TLVRecord, preimage string) (*lnclient.PayKeysendResponse, error) { - - // TODO: re-enable when passing custom preimage is possible - /*extraTlvs := []glalby.TlvEntry{} - - for _, customRecord := range custom_records { - - extraTlvs = append(extraTlvs, glalby.TlvEntry{ - Ty: customRecord.Type, - Value: customRecord.Value, // glalby expects hex-encoded TLV values - }) - } - - // TODO: support passing custom preimage - response, err := gs.client.KeySend(glalby.KeySendRequest{ - Destination: destination, - AmountMsat: &amount, - ExtraTlvs: &extraTlvs, - }) - - if err != nil { - logger.Logger.Errorf("Failed to send keysend payment: %v", err) - return "", "", 0, err - } - - // TODO: get payment hash from response - - return "", response.PaymentPreimage, 0, nil*/ - return nil, errors.New("not supported") -} - -func (gs *GreenlightService) MakeInvoice(ctx context.Context, amount int64, description string, descriptionHash string, expiry int64) (transaction *lnclient.Transaction, err error) { - if expiry == 0 { - expiry = lnclient.DEFAULT_INVOICE_EXPIRY - } - uexpiry := uint64(expiry) - // TODO: it seems description hash cannot be passed to greenlight - invoice, err := gs.client.MakeInvoice(glalby.MakeInvoiceRequest{ - AmountMsat: uint64(amount), - Description: description, - Label: "label_" + strconv.Itoa(rand.Int()), - Expiry: &uexpiry, - }) - - if err != nil { - logger.Logger.Errorf("MakeInvoice failed: %v", err) - return nil, err - } - - paymentRequest, err := decodepay.Decodepay(strings.ToLower(invoice.Bolt11)) - if err != nil { - logger.Logger.WithFields(logrus.Fields{ - "invoice": invoice.Bolt11, - }).Errorf("Failed to decode bolt11 invoice: %v", invoice.Bolt11) - return nil, err - } - - description = paymentRequest.Description - descriptionHash = paymentRequest.DescriptionHash - expiresAt := int64(invoice.ExpiresAt) - transaction = &lnclient.Transaction{ - Type: "incoming", - Invoice: invoice.Bolt11, - Description: description, - DescriptionHash: descriptionHash, - Preimage: "", // TODO: set preimage to enable self-payments - PaymentHash: invoice.PaymentHash, - ExpiresAt: &expiresAt, - Amount: amount, - CreatedAt: int64(paymentRequest.CreatedAt), - } - - return transaction, nil -} - -func (gs *GreenlightService) LookupInvoice(ctx context.Context, paymentHash string) (transaction *lnclient.Transaction, err error) { - response, err := gs.client.ListInvoices(glalby.ListInvoicesRequest{ - PaymentHash: &paymentHash, - }) - - if err != nil { - logger.Logger.Errorf("ListInvoices failed: %v", err) - return nil, err - } - - if len(response.Invoices) == 0 { - return nil, errors.New("invoice not found") - } - invoice := response.Invoices[0] - - if invoice.Bolt11 == nil { - return nil, errors.New("not a Bolt11 invoice") - } - - transaction, err = gs.greenlightInvoiceToTransaction(&invoice) - - if err != nil { - logger.Logger.Errorf("Failed to map invoice: %v", err) - return nil, err - } - - return transaction, nil -} - -func (gs *GreenlightService) ListTransactions(ctx context.Context, from, until, limit, offset uint64, unpaid bool, invoiceType string) (transactions []lnclient.Transaction, err error) { - listInvoicesResponse, err := gs.client.ListInvoices(glalby.ListInvoicesRequest{}) - - if err != nil { - logger.Logger.Errorf("ListInvoices failed: %v", err) - return nil, err - } - - transactions = []lnclient.Transaction{} - - if err != nil { - log.Printf("ListInvoices failed: %v", err) - return nil, err - } - - for _, invoice := range listInvoicesResponse.Invoices { - if invoice.PaidAt == nil { - // skip unpaid invoices - continue - } - - transaction, err := gs.greenlightInvoiceToTransaction(&invoice) - if err != nil { - continue - } - - transactions = append(transactions, *transaction) - } - - listPaymentsResponse, err := gs.client.ListPayments(glalby.ListPaymentsRequest{}) - - if err != nil { - logger.Logger.Errorf("ListPayments failed: %v", err) - return nil, err - } - - for _, payment := range listPaymentsResponse.Payments { - description := "" - descriptionHash := "" - bolt11 := "" - var expiresAt *int64 - if payment.Bolt11 != nil { - // TODO: Greenlight should provide these details so we don't need to manually decode the invoice - bolt11 := *payment.Bolt11 - paymentRequest, err := decodepay.Decodepay(strings.ToLower(bolt11)) - if err != nil { - log.Printf("Failed to decode bolt11 invoice: %v", bolt11) - return nil, err - } - - description = paymentRequest.Description - descriptionHash = paymentRequest.DescriptionHash - expiresAtUnix := time.UnixMilli(int64(paymentRequest.CreatedAt) * 1000).Add(time.Duration(paymentRequest.Expiry) * time.Second).Unix() - expiresAt = &expiresAtUnix - } - - preimage := "" - if payment.Preimage != nil { - preimage = *payment.Preimage - } - var amount int64 = 0 - var fee int64 = 0 - if payment.AmountSentMsat != nil { - amount = int64(*payment.AmountSentMsat) - if payment.AmountMsat != nil { - fee = amount - int64(*payment.AmountMsat) - } - } - var settledAt *int64 - if payment.CompletedAt != nil { - completedAt := int64(*payment.CompletedAt) - settledAt = &completedAt - } - - transactions = append(transactions, lnclient.Transaction{ - Type: "outgoing", - Invoice: bolt11, - Description: description, - DescriptionHash: descriptionHash, - Preimage: preimage, - PaymentHash: payment.PaymentHash, - ExpiresAt: expiresAt, - Amount: amount, - FeesPaid: fee, - CreatedAt: int64(payment.CreatedAt), - SettledAt: settledAt, - }) - } - - // sort by created date descending - sort.SliceStable(transactions, func(i, j int) bool { - return transactions[i].CreatedAt > transactions[j].CreatedAt - }) - - return transactions, nil -} - -func (gs *GreenlightService) GetInfo(ctx context.Context) (info *lnclient.NodeInfo, err error) { - nodeInfo, err := gs.client.GetInfo() - - if err != nil { - logger.Logger.Errorf("GetInfo failed: %v", err) - return nil, err - } - - return &lnclient.NodeInfo{ - Alias: nodeInfo.Alias, - Color: nodeInfo.Color, - Pubkey: nodeInfo.Pubkey, - Network: nodeInfo.Network, - BlockHeight: nodeInfo.BlockHeight, - BlockHash: "", - }, nil -} - -func (gs *GreenlightService) ListChannels(ctx context.Context) ([]lnclient.Channel, error) { - response, err := gs.client.ListFunds(glalby.ListFundsRequest{}) - - if err != nil { - logger.Logger.Errorf("Failed to list funds: %v", err) - return nil, err - } - - channels := []lnclient.Channel{} - - for _, glChannel := range response.Channels { - if glChannel.ChannelId == nil { - continue - } - - var localAmount uint64 - if glChannel.OurAmountMsat != nil { - localAmount = *glChannel.OurAmountMsat - } - var totalAmount uint64 - if glChannel.AmountMsat != nil { - totalAmount = *glChannel.AmountMsat - } - - channels = append(channels, lnclient.Channel{ - LocalBalance: int64(localAmount), - LocalSpendableBalance: int64(localAmount), - RemoteBalance: int64(totalAmount - localAmount), - RemotePubkey: glChannel.PeerId, - Id: *glChannel.ChannelId, - Active: glChannel.State == 2, - FundingTxId: glChannel.FundingTxid, - // TODO: add Public property - }) - } - - return channels, nil -} - -func (gs *GreenlightService) GetNodeConnectionInfo(ctx context.Context) (nodeConnectionInfo *lnclient.NodeConnectionInfo, err error) { - info, err := gs.GetInfo(ctx) - if err != nil { - logger.Logger.Errorf("GetInfo failed: %v", err) - return nil, err - } - return &lnclient.NodeConnectionInfo{ - Pubkey: info.Pubkey, - }, nil -} - -func (gs *GreenlightService) ConnectPeer(ctx context.Context, connectPeerRequest *lnclient.ConnectPeerRequest) error { - var host *string - if connectPeerRequest.Address != "" { - host = &connectPeerRequest.Address - } - var port *uint16 - if connectPeerRequest.Port > 0 { - port = &connectPeerRequest.Port - } - _, err := gs.client.ConnectPeer(glalby.ConnectPeerRequest{ - Id: connectPeerRequest.Pubkey, - Host: host, - Port: port, - }) - if err != nil { - logger.Logger.Errorf("ConnectPeer failed: %v", err) - return err - } - return nil -} - -func (gs *GreenlightService) OpenChannel(ctx context.Context, openChannelRequest *lnclient.OpenChannelRequest) (*lnclient.OpenChannelResponse, error) { - - amountMsat := uint64(openChannelRequest.AmountSats) * 1000 - // minConf := uint32(0) // - response, err := gs.client.FundChannel(glalby.FundChannelRequest{ - Id: openChannelRequest.Pubkey, - AmountMsat: &amountMsat, - Announce: &openChannelRequest.Public, - // Minconf: &minConf, - }) - if err != nil { - logger.Logger.Errorf("OpenChannel failed: %v", err) - return nil, err - } - - return &lnclient.OpenChannelResponse{ - FundingTxId: response.Txid, - }, nil -} - -func (gs *GreenlightService) CloseChannel(ctx context.Context, closeChannelRequest *lnclient.CloseChannelRequest) (*lnclient.CloseChannelResponse, error) { - _, err := gs.client.Close(glalby.CloseRequest{ - Id: closeChannelRequest.ChannelId, - }) - if err != nil { - logger.Logger.WithError(err).Error("CloseChannel failed") - return nil, err - } - - return &lnclient.CloseChannelResponse{}, nil -} - -func (gs *GreenlightService) GetNewOnchainAddress(ctx context.Context) (string, error) { - - newAddressResponse, err := gs.client.NewAddress(glalby.NewAddressRequest{}) - if err != nil { - logger.Logger.Errorf("NewAddress failed: %v", err) - return "", err - } - if newAddressResponse.Bech32 == nil { - return "", errors.New("no Bech32 in new address response") - } - - return *newAddressResponse.Bech32, nil -} - -func (gs *GreenlightService) GetOnchainBalance(ctx context.Context) (*lnclient.OnchainBalanceResponse, error) { - response, err := gs.client.ListFunds(glalby.ListFundsRequest{}) - logger.Logger.WithField("response", response).Debug("Listed funds") - - if err != nil { - logger.Logger.Errorf("Failed to list funds: %v", err) - return nil, err - } - - var spendableBalance int64 = 0 - var pendingBalance int64 = 0 - for _, output := range response.Outputs { - if output.AmountMsat != nil { - if output.Status == 1 { - spendableBalance += int64(*output.AmountMsat) - } else { - pendingBalance += int64(*output.AmountMsat) - } - } - } - - return &lnclient.OnchainBalanceResponse{ - Spendable: spendableBalance / 1000, - Total: (spendableBalance + pendingBalance) / 1000, - }, nil -} - -func (gs *GreenlightService) RedeemOnchainFunds(ctx context.Context, toAddress string, amount uint64, sendAll bool) (string, error) { - if !sendAll { - return "", errors.New("only send all is supported") - } - amountAll := glalby.AmountOrAll(glalby.AmountOrAllAll{}) - txId, err := gs.client.Withdraw(glalby.WithdrawRequest{ - Destination: toAddress, - Amount: &amountAll, - }) - if err != nil { - logger.Logger.WithError(err).Error("Withdraw failed") - return "", err - } - logger.Logger.WithField("txId", txId).Info("Redeeming On-Chain funds") - - return txId.Txid, nil -} - -func (gs *GreenlightService) SendPaymentProbes(ctx context.Context, invoice string) error { - return nil -} - -func (gs *GreenlightService) SendSpontaneousPaymentProbes(ctx context.Context, amountMsat uint64, nodeId string) error { - return nil -} - -func (gs *GreenlightService) ListPeers(ctx context.Context) ([]lnclient.PeerDetails, error) { - return nil, nil -} - -func (gs *GreenlightService) GetLogOutput(ctx context.Context, maxLen int) ([]byte, error) { - return []byte{}, nil -} - -func (gs *GreenlightService) SignMessage(ctx context.Context, message string) (string, error) { - response, err := gs.client.SignMessage(glalby.SignMessageRequest{ - Message: message, - }) - - if err != nil { - logger.Logger.Errorf("SignMessage failed: %v", err) - return "", err - } - - return response.Zbase, nil -} - -func (gs *GreenlightService) greenlightInvoiceToTransaction(invoice *glalby.ListInvoicesInvoice) (*lnclient.Transaction, error) { - description := "" - descriptionHash := "" - if invoice.Description != nil { - description = *invoice.Description - } - bolt11 := *invoice.Bolt11 - paymentRequest, err := decodepay.Decodepay(strings.ToLower(bolt11)) - if err != nil { - logger.Logger.WithFields(logrus.Fields{ - "invoice": bolt11, - }).Errorf("Failed to decode bolt11 invoice: %v", bolt11) - return nil, err - } - if description == "" { - description = paymentRequest.Description - } - descriptionHash = paymentRequest.DescriptionHash - - expiresAt := int64(invoice.ExpiresAt) - - var amount int64 = 0 - var fee int64 = 0 - if invoice.AmountReceivedMsat != nil { - amount = int64(*invoice.AmountReceivedMsat) - if invoice.AmountMsat != nil { - fee = int64(*invoice.AmountMsat) - amount - } - } - - preimage := "" - var settledAt *int64 - if invoice.PaidAt != nil { - preimage = *invoice.PaymentPreimage - paidAt := int64(*invoice.PaidAt) - settledAt = &paidAt - } - - transaction := &lnclient.Transaction{ - Type: "incoming", - Invoice: bolt11, - Description: description, - DescriptionHash: descriptionHash, - PaymentHash: invoice.PaymentHash, - ExpiresAt: &expiresAt, - Amount: amount, - FeesPaid: fee, - CreatedAt: int64(paymentRequest.CreatedAt), - Preimage: preimage, - SettledAt: settledAt, - } - return transaction, nil -} - -func (gs *GreenlightService) ResetRouter(key string) error { - return nil -} - -func (gs *GreenlightService) GetBalances(ctx context.Context) (*lnclient.BalancesResponse, error) { - onchainBalance, err := gs.GetOnchainBalance(ctx) - if err != nil { - logger.Logger.WithError(err).Error("Failed to retrieve onchain balance") - return nil, err - } - - response, err := gs.client.ListFunds(glalby.ListFundsRequest{}) - - if err != nil { - logger.Logger.Errorf("Failed to list funds: %v", err) - return nil, err - } - - var totalReceivable int64 = 0 - var totalSpendable int64 = 0 - var nextMaxReceivable int64 = 0 - var nextMaxSpendable int64 = 0 - var nextMaxReceivableMPP int64 = 0 - var nextMaxSpendableMPP int64 = 0 - for _, channel := range response.Channels { - if channel.OurAmountMsat != nil && channel.AmountMsat != nil && channel.Connected { - - channelReceivable := int64(*channel.AmountMsat - *channel.OurAmountMsat) - channelSpendable := int64(*channel.OurAmountMsat) - - nextMaxReceivable = max(nextMaxReceivable, channelReceivable) - nextMaxSpendable = max(nextMaxSpendable, channelSpendable) - - nextMaxReceivableMPP += channelReceivable - nextMaxSpendableMPP += channelSpendable - - totalReceivable += channelReceivable - totalSpendable += channelSpendable - } - } - - return &lnclient.BalancesResponse{ - Onchain: *onchainBalance, - Lightning: lnclient.LightningBalanceResponse{ - TotalSpendable: totalSpendable, - TotalReceivable: totalReceivable, - NextMaxSpendable: nextMaxSpendable, - NextMaxReceivable: nextMaxReceivable, - NextMaxSpendableMPP: nextMaxSpendableMPP, - NextMaxReceivableMPP: nextMaxReceivableMPP, - }, - }, nil - -} - -func (gs *GreenlightService) GetStorageDir() (string, error) { - return "", nil -} - -func (gs *GreenlightService) GetNodeStatus(ctx context.Context) (nodeStatus *lnclient.NodeStatus, err error) { - return &lnclient.NodeStatus{ - IsReady: true, - }, nil -} - -func (gs *GreenlightService) GetNetworkGraph(ctx context.Context, nodeIds []string) (lnclient.NetworkGraphResponse, error) { - return nil, nil -} - -func (gs *GreenlightService) UpdateLastWalletSyncRequest() {} - -func (gs *GreenlightService) UpdateChannel(ctx context.Context, updateChannelRequest *lnclient.UpdateChannelRequest) error { - return nil -} - -func (gs *GreenlightService) DisconnectPeer(ctx context.Context, peerId string) error { - return nil -} - -func (gs *GreenlightService) GetSupportedNIP47Methods() []string { - return []string{"pay_invoice" /*"pay_keysend",*/, "get_balance", "get_budget", "get_info", "make_invoice", "lookup_invoice", "list_transactions", "multi_pay_invoice", "multi_pay_keysend", "sign_message"} -} - -func (gs *GreenlightService) GetSupportedNIP47NotificationTypes() []string { - return []string{} -} - -func (gs *GreenlightService) GetPubkey() string { - return gs.pubkey -} - -func (gs *GreenlightService) GetCustomNodeCommandDefinitions() []lnclient.CustomNodeCommandDef { - return nil -} - -func (gs *GreenlightService) ExecuteCustomNodeCommand(ctx context.Context, command *lnclient.CustomNodeCommandRequest) (*lnclient.CustomNodeCommandResponse, error) { - return nil, nil -} diff --git a/service/start.go b/service/start.go index fd72ff5f..cb50dfab 100644 --- a/service/start.go +++ b/service/start.go @@ -17,9 +17,7 @@ import ( "github.com/getAlby/hub/config" "github.com/getAlby/hub/events" "github.com/getAlby/hub/lnclient" - "github.com/getAlby/hub/lnclient/breez" "github.com/getAlby/hub/lnclient/cashu" - "github.com/getAlby/hub/lnclient/greenlight" "github.com/getAlby/hub/lnclient/ldk" "github.com/getAlby/hub/lnclient/lnd" "github.com/getAlby/hub/lnclient/phoenixd" @@ -328,19 +326,6 @@ func (svc *service) launchLNBackend(ctx context.Context, encryptionKey string) e svc.startupState = startupState } lnClient, err = ldk.NewLDKService(ctx, svc.cfg, svc.eventPublisher, mnemonic, ldkWorkdir, svc.cfg.GetEnv().LDKNetwork, vssToken, setStartupState) - case config.GreenlightBackendType: - Mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey) - GreenlightInviteCode, _ := svc.cfg.Get("GreenlightInviteCode", encryptionKey) - GreenlightWorkdir := path.Join(svc.cfg.GetEnv().Workdir, "greenlight") - - lnClient, err = greenlight.NewGreenlightService(svc.cfg, Mnemonic, GreenlightInviteCode, GreenlightWorkdir, encryptionKey) - case config.BreezBackendType: - Mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey) - BreezAPIKey, _ := svc.cfg.Get("BreezAPIKey", encryptionKey) - GreenlightInviteCode, _ := svc.cfg.Get("GreenlightInviteCode", encryptionKey) - BreezWorkdir := path.Join(svc.cfg.GetEnv().Workdir, "breez") - - lnClient, err = breez.NewBreezService(Mnemonic, BreezAPIKey, GreenlightInviteCode, BreezWorkdir) case config.PhoenixBackendType: PhoenixdAddress, _ := svc.cfg.Get("PhoenixdAddress", encryptionKey) PhoenixdAuthorization, _ := svc.cfg.Get("PhoenixdAuthorization", encryptionKey)