mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
chore: remove unused green and breezlight backends
This commit is contained in:
parent
473105ff62
commit
e107e05d80
22 changed files with 10 additions and 1508 deletions
11
.github/workflows/http.yml
vendored
11
.github/workflows/http.yml
vendored
|
|
@ -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
|
||||
|
||||
|
|
|
|||
8
.github/workflows/wails.yml
vendored
8
.github/workflows/wails.yml
vendored
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
||||
|
|
|
|||
10
README.md
10
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
|
||||
|
||||
|
|
|
|||
14
api/api.go
14
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 {
|
||||
|
|
|
|||
|
|
@ -130,14 +130,9 @@ 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"`
|
||||
|
||||
// LND fields
|
||||
LNDAddress string `json:"lndAddress"`
|
||||
LNDCertFile string `json:"lndCertFile"`
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package config
|
|||
|
||||
const (
|
||||
LNDBackendType = "LND"
|
||||
GreenlightBackendType = "GREENLIGHT"
|
||||
LDKBackendType = "LDK"
|
||||
BreezBackendType = "BREEZ"
|
||||
PhoenixBackendType = "PHOENIX"
|
||||
CashuBackendType = "CASHU"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 <BreezRedeemInternal />;
|
||||
}
|
||||
|
||||
function BreezRedeemInternal() {
|
||||
const { data: balances } = useBalances();
|
||||
|
||||
if (!balances || balances.onchain.spendable <= ONCHAIN_DUST_SATS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-8">
|
||||
<Alert>
|
||||
<RocketIcon className="h-4 w-4" />
|
||||
<AlertTitle>Breez channel closed</AlertTitle>
|
||||
<AlertDescription>
|
||||
<div className="mb-2">
|
||||
One of your Breez channels was closed and you have{" "}
|
||||
{balances.onchain.spendable} sats to redeem.
|
||||
</div>
|
||||
<LinkButton to={"/wallet/withdraw"} size={"sm"}>
|
||||
Redeem
|
||||
</LinkButton>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -12,16 +12,6 @@ export const backendTypeConfigs: Record<BackendType, BackendTypeConfig> = {
|
|||
hasChannelManagement: true,
|
||||
hasNodeBackup: false,
|
||||
},
|
||||
BREEZ: {
|
||||
hasMnemonic: true,
|
||||
hasChannelManagement: false,
|
||||
hasNodeBackup: false,
|
||||
},
|
||||
GREENLIGHT: {
|
||||
hasMnemonic: true,
|
||||
hasChannelManagement: true,
|
||||
hasNodeBackup: false,
|
||||
},
|
||||
LDK: {
|
||||
hasMnemonic: true,
|
||||
hasChannelManagement: true,
|
||||
|
|
|
|||
|
|
@ -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: <SetupNode />,
|
||||
},
|
||||
{
|
||||
path: "breez",
|
||||
element: <BreezForm />,
|
||||
},
|
||||
{
|
||||
path: "greenlight",
|
||||
element: <GreenlightForm />,
|
||||
},
|
||||
{
|
||||
path: "cashu",
|
||||
element: <CashuForm />,
|
||||
|
|
|
|||
|
|
@ -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<string>(setupStore.nodeInfo.greenlightInviteCode || "");
|
||||
const [breezApiKey, setBreezApiKey] = React.useState<string>(
|
||||
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 (
|
||||
<Container>
|
||||
<TwoColumnLayoutHeader
|
||||
title={"Configure Breez"}
|
||||
description={"Fill out wallet details to finish setup."}
|
||||
/>
|
||||
<form className="w-full grid gap-5 mt-6" onSubmit={onSubmit}>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="greenlight-invite-code">Greenlight Invite Code</Label>
|
||||
<Input
|
||||
name="greenlight-invite-code"
|
||||
onChange={(e) => setGreenlightInviteCode(e.target.value)}
|
||||
value={greenlightInviteCode}
|
||||
type="text"
|
||||
id="greenlight-invite-code"
|
||||
placeholder="XXXX-YYYY"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="breez-api-key">Breez API Key</Label>
|
||||
<Input
|
||||
name="breez-api-key"
|
||||
onChange={(e) => setBreezApiKey(e.target.value)}
|
||||
value={breezApiKey}
|
||||
autoComplete="off"
|
||||
type="text"
|
||||
id="breez-api-key"
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit">Next</Button>
|
||||
</form>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
@ -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<string>(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 (
|
||||
<Container>
|
||||
<TwoColumnLayoutHeader
|
||||
title="Configure Greenlight"
|
||||
description="Fill out wallet details to finish setup."
|
||||
/>
|
||||
<form onSubmit={onSubmit} className="w-full grid gap-5 mt-6">
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="greenlight-invite-code">Greenlight Invite Code</Label>
|
||||
<Input
|
||||
name="greenlight-invite-code"
|
||||
onChange={(e) => setGreenlightInviteCode(e.target.value)}
|
||||
value={greenlightInviteCode}
|
||||
type="text"
|
||||
id="greenlight-invite-code"
|
||||
placeholder="XXXX-YYYY"
|
||||
/>
|
||||
</div>
|
||||
<Button>Next</Button>
|
||||
</form>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
@ -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() {
|
|||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<BreezRedeem />
|
||||
<div className="flex flex-col xl:flex-row justify-between xl:items-center gap-5">
|
||||
<div className="flex flex-col gap-1 text-center xl:text-left">
|
||||
<div className="text-5xl font-medium balance sensitive slashed-zero">
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
2
go.mod
2
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
|
||||
|
|
|
|||
4
go.sum
4
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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue