diff --git a/.prettierignore b/.prettierignore
index e69de29b..c4c1df60 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -0,0 +1 @@
+frontend/src/assets/lotties
\ No newline at end of file
diff --git a/README.md b/README.md
index d2f10f7f..4edf3cef 100644
--- a/README.md
+++ b/README.md
@@ -115,8 +115,6 @@ Note that the PostgreSQL user account must be granted appropriate permissions to
We use [testify/mock](https://github.com/stretchr/testify) to facilitate mocking in tests. Instead of writing mocks manually, we generate them using [vektra/mockery](https://github.com/vektra/mockery). To regenerate them, [install mockery](https://vektra.github.io/mockery/latest/installation) and run it in the project's root directory:
-> Use `go install github.com/vektra/mockery/v2@v2.52.1` as go 1.24.0 is currently not supported by Alby Hub.
-
$ mockery
Mockery loads its configuration from the .mockery.yaml file in the root directory of this project. To add mocks for new interfaces, add them to the configuration file and run mockery.
diff --git a/api/api.go b/api/api.go
index 6cc7af99..c9b093a4 100644
--- a/api/api.go
+++ b/api/api.go
@@ -755,11 +755,11 @@ func (api *api) SignMessage(ctx context.Context, message string) (*SignMessageRe
}, nil
}
-func (api *api) RedeemOnchainFunds(ctx context.Context, toAddress string, amount uint64, sendAll bool) (*RedeemOnchainFundsResponse, error) {
+func (api *api) RedeemOnchainFunds(ctx context.Context, toAddress string, amount uint64, feeRate *uint64, sendAll bool) (*RedeemOnchainFundsResponse, error) {
if api.svc.GetLNClient() == nil {
return nil, errors.New("LNClient not started")
}
- txId, err := api.svc.GetLNClient().RedeemOnchainFunds(ctx, toAddress, amount, sendAll)
+ txId, err := api.svc.GetLNClient().RedeemOnchainFunds(ctx, toAddress, amount, feeRate, sendAll)
if err != nil {
return nil, err
}
diff --git a/api/models.go b/api/models.go
index ffeda0f1..3282cc90 100644
--- a/api/models.go
+++ b/api/models.go
@@ -34,7 +34,7 @@ type API interface {
GetNewOnchainAddress(ctx context.Context) (string, error)
GetUnusedOnchainAddress(ctx context.Context) (string, error)
SignMessage(ctx context.Context, message string) (*SignMessageResponse, error)
- RedeemOnchainFunds(ctx context.Context, toAddress string, amount uint64, sendAll bool) (*RedeemOnchainFundsResponse, error)
+ RedeemOnchainFunds(ctx context.Context, toAddress string, amount uint64, feeRate *uint64, sendAll bool) (*RedeemOnchainFundsResponse, error)
GetBalances(ctx context.Context) (*BalancesResponse, error)
ListTransactions(ctx context.Context, appId *uint, limit uint64, offset uint64) (*ListTransactionsResponse, error)
ListOnchainTransactions(ctx context.Context) ([]lnclient.OnchainTransaction, error)
@@ -235,9 +235,10 @@ type CloseChannelResponse = lnclient.CloseChannelResponse
type UpdateChannelRequest = lnclient.UpdateChannelRequest
type RedeemOnchainFundsRequest struct {
- ToAddress string `json:"toAddress"`
- Amount uint64 `json:"amount"`
- SendAll bool `json:"sendAll"`
+ ToAddress string `json:"toAddress"`
+ Amount uint64 `json:"amount"`
+ FeeRate *uint64 `json:"feeRate"`
+ SendAll bool `json:"sendAll"`
}
type RedeemOnchainFundsResponse struct {
diff --git a/frontend/src/screens/wallet/WithdrawOnchainFunds.tsx b/frontend/src/screens/wallet/WithdrawOnchainFunds.tsx
index 571fd137..abad9595 100644
--- a/frontend/src/screens/wallet/WithdrawOnchainFunds.tsx
+++ b/frontend/src/screens/wallet/WithdrawOnchainFunds.tsx
@@ -1,4 +1,9 @@
-import { AlertTriangleIcon, CopyIcon, ExternalLinkIcon } from "lucide-react";
+import {
+ AlertTriangleIcon,
+ ChevronDown,
+ CopyIcon,
+ ExternalLinkIcon,
+} from "lucide-react";
import React from "react";
import AppHeader from "src/components/AppHeader";
import ExternalLink from "src/components/ExternalLink";
@@ -23,6 +28,8 @@ import { useToast } from "src/components/ui/use-toast";
import { ONCHAIN_DUST_SATS } from "src/constants";
import { useBalances } from "src/hooks/useBalances";
import { useChannels } from "src/hooks/useChannels";
+import { useInfo } from "src/hooks/useInfo";
+import { useMempoolApi } from "src/hooks/useMempoolApi";
import { copyToClipboard } from "src/lib/clipboard";
import { RedeemOnchainFundsResponse } from "src/types";
@@ -31,11 +38,20 @@ import { request } from "src/utils/request";
export default function WithdrawOnchainFunds() {
const [isLoading, setLoading] = React.useState(false);
const { toast } = useToast();
+ const { data: info } = useInfo();
const { data: balances } = useBalances();
+ const { data: recommendedFees } = useMempoolApi<{
+ fastestFee: number;
+ halfHourFee: number;
+ economyFee: number;
+ minimumFee: number;
+ }>("/v1/fees/recommended");
const { data: channels } = useChannels();
const [onchainAddress, setOnchainAddress] = React.useState("");
const [amount, setAmount] = React.useState("");
+ const [feeRate, setFeeRate] = React.useState("");
const [sendAll, setSendAll] = React.useState(false);
+ const [showAdvanced, setShowAdvanced] = React.useState(false);
const [transactionId, setTransactionId] = React.useState("");
const [confirmDialogOpen, setConfirmDialogOpen] = React.useState(false);
@@ -73,6 +89,7 @@ export default function WithdrawOnchainFunds() {
toAddress: onchainAddress,
amount: +amount,
sendAll,
+ ...(feeRate && { feeRate: +feeRate }),
}),
}
);
@@ -90,7 +107,7 @@ export default function WithdrawOnchainFunds() {
});
}
setLoading(false);
- }, [amount, onchainAddress, sendAll, toast]);
+ }, [amount, feeRate, onchainAddress, sendAll, toast]);
if (transactionId) {
return (
@@ -123,7 +140,7 @@ export default function WithdrawOnchainFunds() {
);
}
- if (!balances) {
+ if (!info || !balances || !recommendedFees) {
return
+ Please double-check the destination address. This transaction + cannot be reversed. +
- -- Please double-check the destination address. This transaction cannot - be reversed. -
+ {(info?.backendType === "LDK" || info?.backendType === "LND") && ( + <> + {showAdvanced && ( +
+ {" "}
+ {" "}
+