mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
feat: Split new channel flow into "Increase Spending Balance" and "Increase Receiving Capacity" (#500)
This commit is contained in:
parent
85381b9183
commit
42d70d53ac
15 changed files with 445 additions and 158 deletions
|
|
@ -662,6 +662,16 @@ func (svc *albyOAuthService) GetChannelPeerSuggestions(ctx context.Context) ([]C
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: remove once alby API is updated
|
||||
for i, suggestion := range suggestions {
|
||||
if suggestion.BrokenLspType != "" {
|
||||
suggestions[i].LspType = suggestion.BrokenLspType
|
||||
}
|
||||
if suggestion.BrokenLspUrl != "" {
|
||||
suggestions[i].LspUrl = suggestion.BrokenLspUrl
|
||||
}
|
||||
}
|
||||
|
||||
logger.Logger.WithFields(logrus.Fields{"channel_suggestions": suggestions}).Info("Alby channel peer suggestions response")
|
||||
return suggestions, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ type ChannelPeerSuggestion struct {
|
|||
MinimumChannelSize uint64 `json:"minimumChannelSize"`
|
||||
Name string `json:"name"`
|
||||
Image string `json:"image"`
|
||||
Lsp string `json:"lsp"`
|
||||
BrokenLspUrl string `json:"lsp_url"`
|
||||
BrokenLspType string `json:"lsp_type"`
|
||||
LspUrl string `json:"lspUrl"`
|
||||
LspType string `json:"lspType"`
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
|
|
|
|||
116
api/lsp.go
116
api/lsp.go
|
|
@ -28,33 +28,12 @@ type lspInfo struct {
|
|||
}
|
||||
|
||||
func (api *api) NewInstantChannelInvoice(ctx context.Context, request *NewInstantChannelInvoiceRequest) (*NewInstantChannelInvoiceResponse, error) {
|
||||
var selectedLsp lsp.LSP
|
||||
switch request.LSP {
|
||||
case "VOLTAGE":
|
||||
selectedLsp = lsp.VoltageLSP()
|
||||
case "OLYMPUS_FLOW_2_0":
|
||||
selectedLsp = lsp.OlympusLSP()
|
||||
case "OLYMPUS_MUTINYNET_FLOW_2_0":
|
||||
selectedLsp = lsp.OlympusMutinynetFlowLSP()
|
||||
case "OLYMPUS_MUTINYNET_LSPS1":
|
||||
selectedLsp = lsp.OlympusMutinynetLSPS1LSP()
|
||||
case "ALBY":
|
||||
selectedLsp = lsp.AlbyPlebsLSP()
|
||||
case "ALBY_MUTINYNET":
|
||||
selectedLsp = lsp.AlbyMutinynetPlebsLSP()
|
||||
case "MEGALITH":
|
||||
selectedLsp = lsp.MegalithLSP()
|
||||
case "MEGALITH_MUTINYNET":
|
||||
selectedLsp = lsp.MegalithMutinynetLSP()
|
||||
default:
|
||||
return nil, errors.New("unknown LSP")
|
||||
}
|
||||
|
||||
if api.svc.GetLNClient() == nil {
|
||||
return nil, errors.New("LNClient not started")
|
||||
}
|
||||
|
||||
if selectedLsp.LspType != lsp.LSP_TYPE_LSPS1 && request.Public {
|
||||
if request.LSPType != lsp.LSP_TYPE_LSPS1 && request.Public {
|
||||
return nil, errors.New("This LSP option does not support public channels")
|
||||
}
|
||||
|
||||
|
|
@ -62,17 +41,17 @@ func (api *api) NewInstantChannelInvoice(ctx context.Context, request *NewInstan
|
|||
|
||||
var lspInfo *lspInfo
|
||||
var err error
|
||||
switch selectedLsp.LspType {
|
||||
switch request.LSPType {
|
||||
case lsp.LSP_TYPE_FLOW_2_0:
|
||||
fallthrough
|
||||
case lsp.LSP_TYPE_PMLSP:
|
||||
lspInfo, err = api.getFlowLSPInfo(selectedLsp.Url + "/info")
|
||||
lspInfo, err = api.getFlowLSPInfo(request.LSPUrl + "/info")
|
||||
|
||||
case lsp.LSP_TYPE_LSPS1:
|
||||
lspInfo, err = api.getLSPS1LSPInfo(selectedLsp.Url + "/get_info")
|
||||
lspInfo, err = api.getLSPS1LSPInfo(request.LSPUrl + "/get_info")
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported LSP type: %v", selectedLsp.LspType)
|
||||
return nil, fmt.Errorf("unsupported LSP type: %v", request.LSPType)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).Error("Failed to request LSP info")
|
||||
|
|
@ -84,7 +63,7 @@ func (api *api) NewInstantChannelInvoice(ctx context.Context, request *NewInstan
|
|||
nodeInfo, err := api.svc.GetLNClient().GetInfo(ctx)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to request own node info", err)
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -105,16 +84,13 @@ func (api *api) NewInstantChannelInvoice(ctx context.Context, request *NewInstan
|
|||
invoice := ""
|
||||
var fee uint64 = 0
|
||||
|
||||
switch selectedLsp.LspType {
|
||||
switch request.LSPType {
|
||||
case lsp.LSP_TYPE_FLOW_2_0:
|
||||
invoice, fee, err = api.requestFlow20WrappedInvoice(ctx, &selectedLsp, request.Amount, nodeInfo.Pubkey)
|
||||
invoice, fee, err = api.requestFlow20WrappedInvoice(ctx, request, nodeInfo.Pubkey)
|
||||
case lsp.LSP_TYPE_PMLSP:
|
||||
invoice, fee, err = api.requestPMLSPInvoice(&selectedLsp, request.Amount, nodeInfo.Pubkey)
|
||||
invoice, fee, err = api.requestPMLSPInvoice(request, nodeInfo.Pubkey)
|
||||
case lsp.LSP_TYPE_LSPS1:
|
||||
invoice, fee, err = api.requestLSPS1Invoice(ctx, &selectedLsp, request.Amount, nodeInfo.Pubkey, request.Public, lspInfo.MaxChannelExpiryBlocks)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported LSP type: %v", selectedLsp.LspType)
|
||||
invoice, fee, err = api.requestLSPS1Invoice(ctx, request, nodeInfo.Pubkey, lspInfo.MaxChannelExpiryBlocks)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).Error("Failed to request invoice")
|
||||
|
|
@ -291,7 +267,7 @@ func (api *api) getFlowLSPInfo(url string) (*lspInfo, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *lsp.LSP, amount uint64, pubkey string) (invoice string, fee uint64, err error) {
|
||||
func (api *api) requestFlow20WrappedInvoice(ctx context.Context, request *NewInstantChannelInvoiceRequest, pubkey string) (invoice string, fee uint64, err error) {
|
||||
logger.Logger.Infoln("Requesting fee information")
|
||||
|
||||
type FeeRequest struct {
|
||||
|
|
@ -309,7 +285,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
Timeout: time.Second * 10,
|
||||
}
|
||||
payloadBytes, err := json.Marshal(FeeRequest{
|
||||
AmountMsat: amount * 1000,
|
||||
AmountMsat: request.Amount * 1000,
|
||||
Pubkey: pubkey,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -317,10 +293,10 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
}
|
||||
bodyReader := bytes.NewReader(payloadBytes)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, selectedLsp.Url+"/fee", bodyReader)
|
||||
req, err := http.NewRequest(http.MethodPost, request.LSPUrl+"/fee", bodyReader)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to create lsp fee request")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -330,7 +306,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to request lsp fee")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -340,7 +316,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to read response body")
|
||||
return "", 0, errors.New("failed to read response body")
|
||||
}
|
||||
|
|
@ -356,13 +332,13 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
err = json.Unmarshal(body, &feeResponse)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to deserialize json")
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", selectedLsp.Url, string(body))
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", request.LSPUrl, string(body))
|
||||
}
|
||||
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
"feeResponse": feeResponse,
|
||||
}).Info("Got fee response")
|
||||
if feeResponse.Id == "" {
|
||||
|
|
@ -376,7 +352,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
|
||||
// because we don't want the sender to pay the fee
|
||||
// see: https://docs.voltage.cloud/voltage-lsp#gqBqV
|
||||
makeInvoiceResponse, err := api.svc.GetLNClient().MakeInvoice(ctx, int64(amount)*1000-int64(feeResponse.FeeAmountMsat), "", "", 60*60)
|
||||
makeInvoiceResponse, err := api.svc.GetLNClient().MakeInvoice(ctx, int64(request.Amount)*1000-int64(feeResponse.FeeAmountMsat), "", "", 60*60)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).Error("Failed to request own invoice")
|
||||
return "", 0, fmt.Errorf("failed to request own invoice %v", err)
|
||||
|
|
@ -406,10 +382,10 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
}
|
||||
bodyReader := bytes.NewReader(payloadBytes)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, selectedLsp.Url+"/proposal", bodyReader)
|
||||
req, err := http.NewRequest(http.MethodPost, request.LSPUrl+"/proposal", bodyReader)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to create lsp fee request")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -419,7 +395,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to request lsp fee")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -429,7 +405,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to read response body")
|
||||
return "", 0, errors.New("failed to read response body")
|
||||
}
|
||||
|
|
@ -445,14 +421,14 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
err = json.Unmarshal(body, &proposalResponse)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to deserialize json")
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", selectedLsp.Url, string(body))
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", request.LSPUrl, string(body))
|
||||
}
|
||||
logger.Logger.WithField("proposalResponse", proposalResponse).Info("Got proposal response")
|
||||
if proposalResponse.Bolt11 == "" {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
"proposalResponse": proposalResponse,
|
||||
}).Error("No bolt11 in proposal response")
|
||||
return "", 0, fmt.Errorf("no bolt11 in proposal response %v", proposalResponse)
|
||||
|
|
@ -463,7 +439,7 @@ func (api *api) requestFlow20WrappedInvoice(ctx context.Context, selectedLsp *ls
|
|||
return invoice, fee, nil
|
||||
}
|
||||
|
||||
func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey string) (invoice string, fee uint64, err error) {
|
||||
func (api *api) requestPMLSPInvoice(request *NewInstantChannelInvoiceRequest, pubkey string) (invoice string, fee uint64, err error) {
|
||||
type NewInstantChannelRequest struct {
|
||||
Amount uint64 `json:"amount"`
|
||||
Pubkey string `json:"pubkey"`
|
||||
|
|
@ -473,7 +449,7 @@ func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey
|
|||
Timeout: time.Second * 10,
|
||||
}
|
||||
payloadBytes, err := json.Marshal(NewInstantChannelRequest{
|
||||
Amount: amount,
|
||||
Amount: request.Amount,
|
||||
Pubkey: pubkey,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -481,10 +457,10 @@ func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey
|
|||
}
|
||||
bodyReader := bytes.NewReader(payloadBytes)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, selectedLsp.Url+"/new-channel", bodyReader)
|
||||
req, err := http.NewRequest(http.MethodPost, request.LSPUrl+"/new-channel", bodyReader)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to create new channel request")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -494,7 +470,7 @@ func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey
|
|||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to request new channel invoice")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -504,7 +480,7 @@ func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey
|
|||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to read response body")
|
||||
return "", 0, errors.New("failed to read response body")
|
||||
}
|
||||
|
|
@ -527,9 +503,9 @@ func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey
|
|||
err = json.Unmarshal(body, &newChannelResponse)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to deserialize json")
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", selectedLsp.Url, string(body))
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", request.LSPUrl, string(body))
|
||||
}
|
||||
|
||||
invoice = newChannelResponse.Invoice
|
||||
|
|
@ -538,7 +514,7 @@ func (api *api) requestPMLSPInvoice(selectedLsp *lsp.LSP, amount uint64, pubkey
|
|||
return invoice, fee, nil
|
||||
}
|
||||
|
||||
func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, amount uint64, pubkey string, public bool, channelExpiryBlocks uint64) (invoice string, fee uint64, err error) {
|
||||
func (api *api) requestLSPS1Invoice(ctx context.Context, request *NewInstantChannelInvoiceRequest, pubkey string, channelExpiryBlocks uint64) (invoice string, fee uint64, err error) {
|
||||
client := http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
}
|
||||
|
|
@ -563,7 +539,7 @@ func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, a
|
|||
|
||||
var requiredChannelConfirmations uint64 = 0
|
||||
|
||||
if public {
|
||||
if request.Public {
|
||||
// as per BOLT-7 6 confirmations are required for the channel to be gossiped
|
||||
// https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#requirements
|
||||
requiredChannelConfirmations = 6
|
||||
|
|
@ -571,14 +547,14 @@ func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, a
|
|||
|
||||
newLSPS1ChannelRequest := NewLSPS1ChannelRequest{
|
||||
PublicKey: pubkey,
|
||||
LSPBalanceSat: strconv.FormatUint(amount, 10),
|
||||
LSPBalanceSat: strconv.FormatUint(request.Amount, 10),
|
||||
ClientBalanceSat: "0",
|
||||
RequiredChannelConfirmations: requiredChannelConfirmations,
|
||||
FundingConfirmsWithinBlocks: 6,
|
||||
ChannelExpiryBlocks: channelExpiryBlocks,
|
||||
Token: "",
|
||||
RefundOnchainAddress: refundAddress,
|
||||
AnnounceChannel: public,
|
||||
AnnounceChannel: request.Public,
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(newLSPS1ChannelRequest)
|
||||
|
|
@ -587,10 +563,10 @@ func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, a
|
|||
}
|
||||
bodyReader := bytes.NewReader(payloadBytes)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, selectedLsp.Url+"/create_order", bodyReader)
|
||||
req, err := http.NewRequest(http.MethodPost, request.LSPUrl+"/create_order", bodyReader)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to create new channel request")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -600,7 +576,7 @@ func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, a
|
|||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to request new channel invoice")
|
||||
return "", 0, err
|
||||
}
|
||||
|
|
@ -610,7 +586,7 @@ func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, a
|
|||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to read response body")
|
||||
return "", 0, errors.New("failed to read response body")
|
||||
}
|
||||
|
|
@ -642,16 +618,16 @@ func (api *api) requestLSPS1Invoice(ctx context.Context, selectedLsp *lsp.LSP, a
|
|||
err = json.Unmarshal(body, &newChannelResponse)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to deserialize json")
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", selectedLsp.Url, string(body))
|
||||
return "", 0, fmt.Errorf("failed to deserialize json %s %s", request.LSPUrl, string(body))
|
||||
}
|
||||
|
||||
invoice = newChannelResponse.Payment.Bolt11.Invoice
|
||||
fee, err = strconv.ParseUint(newChannelResponse.Payment.Bolt11.FeeTotalSat, 10, 64)
|
||||
if err != nil {
|
||||
logger.Logger.WithError(err).WithFields(logrus.Fields{
|
||||
"url": selectedLsp.Url,
|
||||
"url": request.LSPUrl,
|
||||
}).Error("Failed to parse fee")
|
||||
return "", 0, fmt.Errorf("failed to parse fee %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,9 +234,10 @@ type BasicRestoreWailsRequest struct {
|
|||
type NetworkGraphResponse = lnclient.NetworkGraphResponse
|
||||
|
||||
type NewInstantChannelInvoiceRequest struct {
|
||||
Amount uint64 `json:"amount"`
|
||||
LSP string `json:"lsp"`
|
||||
Public bool `json:"public"`
|
||||
Amount uint64 `json:"amount"`
|
||||
LSPType string `json:"lspType"`
|
||||
LSPUrl string `json:"lspUrl"`
|
||||
Public bool `json:"public"`
|
||||
}
|
||||
|
||||
type NewInstantChannelInvoiceResponse struct {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function SidebarHint() {
|
|||
// Don't distract with hints while opening a channel or on the settings page
|
||||
if (
|
||||
location.pathname.endsWith("/channels/order") ||
|
||||
location.pathname.endsWith("/channels/new") ||
|
||||
location.pathname.endsWith("/channels") ||
|
||||
location.pathname.startsWith("/settings")
|
||||
) {
|
||||
return null;
|
||||
|
|
@ -73,7 +73,7 @@ function SidebarHint() {
|
|||
title="Open Your First Channel"
|
||||
description="Deposit bitcoin by onchain or lightning payment to start using your new wallet."
|
||||
buttonText="Begin Now"
|
||||
buttonLink="/channels/new"
|
||||
buttonLink="/channels"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ import ShowApp from "src/screens/apps/ShowApp";
|
|||
import AppStore from "src/screens/appstore/AppStore";
|
||||
import Channels from "src/screens/channels/Channels";
|
||||
import { CurrentChannelOrder } from "src/screens/channels/CurrentChannelOrder";
|
||||
import NewChannel from "src/screens/channels/NewChannel";
|
||||
import IncreaseIncomingCapacity from "src/screens/channels/IncreaseIncomingCapacity";
|
||||
import IncreaseOutgoingCapacity from "src/screens/channels/IncreaseOutgoingCapacity";
|
||||
import MigrateAlbyFunds from "src/screens/onboarding/MigrateAlbyFunds";
|
||||
import { Success } from "src/screens/onboarding/Success";
|
||||
import BuyBitcoin from "src/screens/onchain/BuyBitcoin";
|
||||
|
|
@ -146,9 +147,14 @@ const routes = [
|
|||
element: <Channels />,
|
||||
},
|
||||
{
|
||||
path: "new",
|
||||
element: <NewChannel />,
|
||||
handle: { crumb: () => "New Channel" },
|
||||
path: "outgoing",
|
||||
element: <IncreaseOutgoingCapacity />,
|
||||
handle: { crumb: () => "Increase Spending Balance" },
|
||||
},
|
||||
{
|
||||
path: "incoming",
|
||||
element: <IncreaseIncomingCapacity />,
|
||||
handle: { crumb: () => "Increase Receiving Capacity" },
|
||||
},
|
||||
{
|
||||
path: "order",
|
||||
|
|
|
|||
|
|
@ -279,20 +279,21 @@ export default function Channels() {
|
|||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<div className="flex flex-row gap-10 items-center w-full">
|
||||
<div className="whitespace-nowrap flex flex-row items-center gap-2">
|
||||
Node
|
||||
</div>
|
||||
<div className="overflow-hidden text-ellipsis">
|
||||
<div
|
||||
className="flex flex-row gap-4 items-center w-full cursor-pointer"
|
||||
onClick={() => {
|
||||
if (!nodeConnectionInfo) {
|
||||
return;
|
||||
}
|
||||
copyToClipboard(nodeConnectionInfo.pubkey);
|
||||
}}
|
||||
>
|
||||
<div>Node</div>
|
||||
<div className="overflow-hidden text-ellipsis flex-1">
|
||||
{nodeConnectionInfo?.pubkey || "Loading..."}
|
||||
</div>
|
||||
{nodeConnectionInfo && (
|
||||
<CopyIcon
|
||||
className="shrink-0 w-4 h-4"
|
||||
onClick={() => {
|
||||
copyToClipboard(nodeConnectionInfo.pubkey);
|
||||
}}
|
||||
/>
|
||||
<CopyIcon className="shrink-0 w-4 h-4" />
|
||||
)}
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -340,9 +341,9 @@ export default function Channels() {
|
|||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link to="/channels/new">
|
||||
{/* <Link to="/channels/new">
|
||||
<Button>Open Channel</Button>
|
||||
</Link>
|
||||
</Link> */}
|
||||
</>
|
||||
}
|
||||
></AppHeader>
|
||||
|
|
@ -436,7 +437,7 @@ export default function Channels() {
|
|||
)}
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-end">
|
||||
<Link to="/channels/new">
|
||||
<Link to="/channels/outgoing">
|
||||
<Button variant="outline">Increase</Button>
|
||||
</Link>
|
||||
</CardFooter>
|
||||
|
|
@ -458,7 +459,7 @@ export default function Channels() {
|
|||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-end">
|
||||
<Link to="/channels/new">
|
||||
<Link to="/channels/incoming">
|
||||
<Button variant="outline">Increase</Button>
|
||||
</Link>
|
||||
</CardFooter>
|
||||
|
|
@ -471,7 +472,7 @@ export default function Channels() {
|
|||
title="No Channels Available"
|
||||
description="Connect to the Lightning Network by establishing your first channel and start transacting."
|
||||
buttonText="Open Channel"
|
||||
buttonLink="/channels/new"
|
||||
buttonLink="/channels/outgoing"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -565,12 +565,13 @@ function PayLightningChannelOrder({ order }: { order: NewChannelOrder }) {
|
|||
(async () => {
|
||||
try {
|
||||
setPrevChannels(channels);
|
||||
if (!order.lsp) {
|
||||
throw new Error("no lsp selected");
|
||||
if (!order.lspType || !order.lspUrl) {
|
||||
throw new Error("missing lsp info in order");
|
||||
}
|
||||
const newInstantChannelInvoiceRequest: NewInstantChannelInvoiceRequest =
|
||||
{
|
||||
lsp: order.lsp,
|
||||
lspType: order.lspType,
|
||||
lspUrl: order.lspUrl,
|
||||
amount: parseInt(order.amount),
|
||||
public: order.isPublic,
|
||||
};
|
||||
|
|
@ -596,15 +597,22 @@ function PayLightningChannelOrder({ order }: { order: NewChannelOrder }) {
|
|||
}
|
||||
return true;
|
||||
});
|
||||
}, [channels, csrf, order.amount, order.isPublic, order.lsp]);
|
||||
}, [
|
||||
channels,
|
||||
csrf,
|
||||
order.amount,
|
||||
order.isPublic,
|
||||
order.lspType,
|
||||
order.lspUrl,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<AppHeader
|
||||
title={"Buy an Instant Channel"}
|
||||
title={"Buy Channel"}
|
||||
description={
|
||||
wrappedInvoiceResponse
|
||||
? "Complete Payment to open an instant channel to your node"
|
||||
? "Complete Payment to open a channel to your node"
|
||||
: "Please wait, loading..."
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
302
frontend/src/screens/channels/IncreaseIncomingCapacity.tsx
Normal file
302
frontend/src/screens/channels/IncreaseIncomingCapacity.tsx
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
import { Box, Zap } from "lucide-react";
|
||||
import React, { FormEvent } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import AppHeader from "src/components/AppHeader";
|
||||
import ExternalLink from "src/components/ExternalLink";
|
||||
import Loading from "src/components/Loading";
|
||||
import { Button } from "src/components/ui/button";
|
||||
import { Checkbox } from "src/components/ui/checkbox";
|
||||
import { Input } from "src/components/ui/input";
|
||||
import { Label } from "src/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "src/components/ui/select";
|
||||
import { useChannelPeerSuggestions } from "src/hooks/useChannelPeerSuggestions";
|
||||
import { useInfo } from "src/hooks/useInfo";
|
||||
import { cn, formatAmount } from "src/lib/utils";
|
||||
import useChannelOrderStore from "src/state/ChannelOrderStore";
|
||||
import { Network, NewChannelOrder, RecommendedChannelPeer } from "src/types";
|
||||
|
||||
function getPeerKey(peer: RecommendedChannelPeer) {
|
||||
return JSON.stringify(peer);
|
||||
}
|
||||
|
||||
export default function IncreaseIncomingCapacity() {
|
||||
const { data: info } = useInfo();
|
||||
|
||||
if (!info?.network) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return <NewChannelInternal network={info.network} />;
|
||||
}
|
||||
|
||||
function NewChannelInternal({ network }: { network: Network }) {
|
||||
const { data: _channelPeerSuggestions } = useChannelPeerSuggestions();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [order, setOrder] = React.useState<Partial<NewChannelOrder>>({
|
||||
paymentMethod: "lightning",
|
||||
status: "pay",
|
||||
});
|
||||
|
||||
const [selectedPeer, setSelectedPeer] = React.useState<
|
||||
RecommendedChannelPeer | undefined
|
||||
>();
|
||||
|
||||
const channelPeerSuggestions = React.useMemo(() => {
|
||||
return _channelPeerSuggestions
|
||||
? [
|
||||
..._channelPeerSuggestions.filter(
|
||||
(peer) =>
|
||||
peer.paymentMethod === "lightning" && peer.lspType === "LSPS1"
|
||||
),
|
||||
]
|
||||
: undefined;
|
||||
}, [_channelPeerSuggestions]);
|
||||
|
||||
function setPublic(isPublic: boolean) {
|
||||
setOrder((current) => ({
|
||||
...current,
|
||||
isPublic,
|
||||
}));
|
||||
}
|
||||
|
||||
const setAmount = React.useCallback((amount: string) => {
|
||||
setOrder((current) => ({
|
||||
...current,
|
||||
amount,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!channelPeerSuggestions) {
|
||||
return;
|
||||
}
|
||||
const recommendedPeer = channelPeerSuggestions.find(
|
||||
(peer) =>
|
||||
peer.network === network && peer.paymentMethod === order.paymentMethod
|
||||
);
|
||||
|
||||
setSelectedPeer(recommendedPeer);
|
||||
}, [network, order.paymentMethod, channelPeerSuggestions]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (selectedPeer) {
|
||||
if (
|
||||
selectedPeer.paymentMethod === "lightning" &&
|
||||
order.paymentMethod === "lightning"
|
||||
) {
|
||||
setOrder((current) => ({
|
||||
...current,
|
||||
lspType: selectedPeer.lspType,
|
||||
lspUrl: selectedPeer.lspUrl,
|
||||
}));
|
||||
}
|
||||
setAmount(selectedPeer.minimumChannelSize.toString());
|
||||
}
|
||||
}, [order.paymentMethod, selectedPeer, setAmount]);
|
||||
|
||||
const selectedCardStyles = "border-primary border-2 font-medium";
|
||||
const presetAmounts = [1_000_000, 2_000_000, 3_000_000];
|
||||
|
||||
function onSubmit(e: FormEvent) {
|
||||
e.preventDefault();
|
||||
useChannelOrderStore.getState().setOrder(order as NewChannelOrder);
|
||||
navigate("/channels/order");
|
||||
}
|
||||
|
||||
if (!channelPeerSuggestions) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader
|
||||
title="Increase Receiving Capacity"
|
||||
description="Purchase a channel with incoming capacity to receive payments"
|
||||
/>
|
||||
<form
|
||||
onSubmit={onSubmit}
|
||||
className="md:max-w-md max-w-full flex flex-col gap-5"
|
||||
>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="amount">Channel size (sats)</Label>
|
||||
{order.amount && +order.amount < 200_000 && (
|
||||
<p className="text-muted-foreground text-xs">
|
||||
For a smooth experience consider a opening a channel of 200k sats
|
||||
in size or more.{" "}
|
||||
<ExternalLink
|
||||
to="https://guides.getalby.com/user-guide/v/alby-account-and-browser-extension/alby-hub/liquidity"
|
||||
className="underline"
|
||||
>
|
||||
Learn more
|
||||
</ExternalLink>
|
||||
</p>
|
||||
)}
|
||||
<Input
|
||||
id="amount"
|
||||
type="number"
|
||||
required
|
||||
min={selectedPeer?.minimumChannelSize || 100000}
|
||||
value={order.amount}
|
||||
onChange={(e) => {
|
||||
setAmount(e.target.value.trim());
|
||||
}}
|
||||
/>
|
||||
<div className="grid grid-cols-3 gap-1.5 text-muted-foreground text-xs">
|
||||
{presetAmounts.map((amount) => (
|
||||
<div
|
||||
key={amount}
|
||||
className={cn(
|
||||
"text-center border rounded p-2 cursor-pointer hover:border-muted-foreground",
|
||||
+(order.amount || "0") === amount &&
|
||||
"border-primary hover:border-primary"
|
||||
)}
|
||||
onClick={() => setAmount(amount.toString())}
|
||||
>
|
||||
{formatAmount(amount * 1000, 0)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="amount">Payment method</Label>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div
|
||||
//onClick={() => setPaymentMethod("onchain")}
|
||||
className="flex-1 opacity-50 select-none"
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-xl border bg-card text-card-foreground shadow p-5 flex flex-col items-center gap-3",
|
||||
order.paymentMethod === "onchain"
|
||||
? selectedCardStyles
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<Box className="w-4 h-4" />
|
||||
Onchain
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
to="#"
|
||||
//onClick={() => setPaymentMethod("lightning")}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-xl border bg-card text-card-foreground shadow p-5 flex flex-col items-center gap-3",
|
||||
order.paymentMethod === "lightning"
|
||||
? selectedCardStyles
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<Zap className="w-4 h-4" />
|
||||
Lightning
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
{selectedPeer && (
|
||||
<div className="grid gap-1.5">
|
||||
<Label>Channel peer</Label>
|
||||
<Select
|
||||
value={getPeerKey(selectedPeer)}
|
||||
onValueChange={(value) =>
|
||||
setSelectedPeer(
|
||||
channelPeerSuggestions.find((x) => getPeerKey(x) === value)
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select channel peer" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{channelPeerSuggestions
|
||||
.filter(
|
||||
(peer) =>
|
||||
peer.network === network &&
|
||||
peer.paymentMethod === order.paymentMethod
|
||||
)
|
||||
.map((peer) => (
|
||||
<SelectItem
|
||||
value={getPeerKey(peer)}
|
||||
key={getPeerKey(peer)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
{peer.name !== "Custom" && (
|
||||
<img
|
||||
src={peer.image}
|
||||
className="w-8 h-8 object-contain"
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
{peer.name}
|
||||
{peer.minimumChannelSize > 0 && (
|
||||
<span className="ml-4 text-xs text-muted-foreground">
|
||||
Min.{" "}
|
||||
{new Intl.NumberFormat().format(
|
||||
peer.minimumChannelSize
|
||||
)}{" "}
|
||||
sats
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{selectedPeer.name === "Custom" && (
|
||||
<>
|
||||
<div className="grid gap-1.5"></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{order.paymentMethod === "lightning" && (
|
||||
<NewChannelLightning order={order} setOrder={setOrder} />
|
||||
)}
|
||||
|
||||
<div className="mt-2 flex items-top space-x-2">
|
||||
<Checkbox
|
||||
id="public-channel"
|
||||
defaultChecked={order.isPublic}
|
||||
onCheckedChange={() => setPublic(!order.isPublic)}
|
||||
className="mr-2"
|
||||
/>
|
||||
<div className="grid gap-1.5 leading-none">
|
||||
<Label htmlFor="public-channel" className="flex items-center gap-2">
|
||||
Public Channel
|
||||
</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Enable if you want to receive keysend payments. (e.g. podcasting)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button size="lg">Next</Button>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
type NewChannelLightningProps = {
|
||||
order: Partial<NewChannelOrder>;
|
||||
setOrder(order: Partial<NewChannelOrder>): void;
|
||||
};
|
||||
|
||||
function NewChannelLightning(props: NewChannelLightningProps) {
|
||||
if (props.order.paymentMethod !== "lightning") {
|
||||
throw new Error("unexpected payment method");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ function getPeerKey(peer: RecommendedChannelPeer) {
|
|||
return JSON.stringify(peer);
|
||||
}
|
||||
|
||||
export default function NewChannel() {
|
||||
export default function IncreaseOutgoingCapacity() {
|
||||
const { data: info } = useInfo();
|
||||
|
||||
if (!info?.network) {
|
||||
|
|
@ -66,7 +66,13 @@ function NewChannelInternal({ network }: { network: Network }) {
|
|||
image: "",
|
||||
};
|
||||
return _channelPeerSuggestions
|
||||
? [..._channelPeerSuggestions, customOption]
|
||||
? [
|
||||
..._channelPeerSuggestions.filter(
|
||||
(peer) =>
|
||||
peer.paymentMethod !== "lightning" || peer.lspType !== "LSPS1"
|
||||
),
|
||||
customOption,
|
||||
]
|
||||
: undefined;
|
||||
}, [_channelPeerSuggestions, network]);
|
||||
|
||||
|
|
@ -121,7 +127,8 @@ function NewChannelInternal({ network }: { network: Network }) {
|
|||
) {
|
||||
setOrder((current) => ({
|
||||
...current,
|
||||
lsp: selectedPeer.lsp,
|
||||
lspType: selectedPeer.lspType,
|
||||
lspUrl: selectedPeer.lspUrl,
|
||||
}));
|
||||
}
|
||||
setAmount(selectedPeer.minimumChannelSize.toString());
|
||||
|
|
@ -144,7 +151,7 @@ function NewChannelInternal({ network }: { network: Network }) {
|
|||
return (
|
||||
<>
|
||||
<AppHeader
|
||||
title="Open a channel"
|
||||
title="Increase Spending Balance"
|
||||
description="Funds used to open a channel minus fees will be added to your spending balance"
|
||||
/>
|
||||
<form
|
||||
|
|
@ -53,7 +53,8 @@ export default function MigrateAlbyFunds() {
|
|||
}
|
||||
const newInstantChannelInvoiceRequest: NewInstantChannelInvoiceRequest =
|
||||
{
|
||||
lsp: "ALBY",
|
||||
lspUrl: "https://lsp.albylabs.com",
|
||||
lspType: "PMLSP",
|
||||
amount,
|
||||
public: false,
|
||||
};
|
||||
|
|
@ -213,7 +214,7 @@ export default function MigrateAlbyFunds() {
|
|||
>
|
||||
Migrate Funds and Open Channel
|
||||
</LoadingButton>
|
||||
<Link to="/channels/new">
|
||||
<Link to="/channels">
|
||||
<Button variant="link">Explore Other Options</Button>
|
||||
</Link>
|
||||
</form>
|
||||
|
|
@ -229,7 +230,7 @@ export default function MigrateAlbyFunds() {
|
|||
external wallet though.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Link to="/channels/new" className="w-full">
|
||||
<Link to="/channels" className="w-full">
|
||||
<Button className="w-full">Explore Other Options</Button>
|
||||
</Link>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ function OnboardingChecklist() {
|
|||
description:
|
||||
"Establish a new Lightning channel to enable fast and low-fee Bitcoin transactions.",
|
||||
checked: hasChannel,
|
||||
to: "/channels/new",
|
||||
to: "/channels",
|
||||
},
|
||||
{
|
||||
title: "Link your Alby Account",
|
||||
|
|
|
|||
|
|
@ -254,6 +254,8 @@ export type SetupNodeInfo = Partial<{
|
|||
phoenixdAuthorization?: string;
|
||||
}>;
|
||||
|
||||
export type LSPType = "LSPS1" | "Flow 2.0" | "PMLSP";
|
||||
|
||||
export type RecommendedChannelPeer = {
|
||||
network: Network;
|
||||
image: string;
|
||||
|
|
@ -267,7 +269,8 @@ export type RecommendedChannelPeer = {
|
|||
}
|
||||
| {
|
||||
paymentMethod: "lightning";
|
||||
lsp: string;
|
||||
lspType: LSPType;
|
||||
lspUrl: string;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -289,7 +292,8 @@ export type AlbyBalance = {
|
|||
|
||||
export type NewInstantChannelInvoiceRequest = {
|
||||
amount: number;
|
||||
lsp: string;
|
||||
lspType: LSPType;
|
||||
lspUrl: string;
|
||||
public: boolean;
|
||||
};
|
||||
|
||||
|
|
@ -334,6 +338,7 @@ export type NewChannelOrder = {
|
|||
}
|
||||
| {
|
||||
paymentMethod: "lightning";
|
||||
lsp: string;
|
||||
lspType: LSPType;
|
||||
lspUrl: string;
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -67,18 +67,16 @@ func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events
|
|||
"[::]:9735",
|
||||
}
|
||||
config.TrustedPeers0conf = []string{
|
||||
lsp.VoltageLSP().Pubkey,
|
||||
lsp.OlympusLSP().Pubkey,
|
||||
lsp.AlbyPlebsLSP().Pubkey,
|
||||
lsp.MegalithLSP().Pubkey,
|
||||
|
||||
// Mutinynet
|
||||
lsp.AlbyMutinynetPlebsLSP().Pubkey,
|
||||
lsp.OlympusMutinynetFlowLSP().Pubkey,
|
||||
lsp.OlympusMutinynetLSP().Pubkey,
|
||||
lsp.MegalithMutinynetLSP().Pubkey,
|
||||
}
|
||||
config.AnchorChannelsConfig.TrustedPeersNoReserve = []string{
|
||||
lsp.VoltageLSP().Pubkey,
|
||||
lsp.OlympusLSP().Pubkey,
|
||||
lsp.AlbyPlebsLSP().Pubkey,
|
||||
lsp.MegalithLSP().Pubkey,
|
||||
|
|
@ -86,7 +84,7 @@ func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events
|
|||
|
||||
// Mutinynet
|
||||
lsp.AlbyMutinynetPlebsLSP().Pubkey,
|
||||
lsp.OlympusMutinynetFlowLSP().Pubkey,
|
||||
lsp.OlympusMutinynetLSP().Pubkey,
|
||||
lsp.MegalithMutinynetLSP().Pubkey,
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +108,8 @@ func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events
|
|||
|
||||
// TODO: remove when https://github.com/lightningdevkit/rust-lightning/issues/2914 is merged
|
||||
// LDK default HTLC inflight value is 10% of the channel size. If an LSPS service is configured this will be set to 0.
|
||||
builder.SetLiquiditySourceLsps2("52.88.33.119:9735", lsp.VoltageLSP().Pubkey, nil)
|
||||
// The liquidity source below is not used because we do not use the native LDK-node LSPS2 API.
|
||||
builder.SetLiquiditySourceLsps2("52.88.33.119:9735", lsp.OlympusLSP().Pubkey, nil)
|
||||
|
||||
//builder.SetLogDirPath (filepath.Join(newpath, "./logs")); // missing?
|
||||
node, err := builder.Build()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package lsp
|
||||
|
||||
type LSP struct {
|
||||
Pubkey string
|
||||
Url string
|
||||
LspType string
|
||||
Pubkey string
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -12,73 +10,43 @@ const (
|
|||
LSP_TYPE_LSPS1 = "LSPS1"
|
||||
)
|
||||
|
||||
func VoltageLSP() LSP {
|
||||
func OlympusMutinynetLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "03aefa43fbb4009b21a4129d05953974b7dbabbbfb511921410080860fca8ee1f0",
|
||||
Url: "https://lsp.voltageapi.com/api/v1",
|
||||
LspType: LSP_TYPE_FLOW_2_0,
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
||||
func OlympusMutinynetFlowLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "032ae843e4d7d177f151d021ac8044b0636ec72b1ce3ffcde5c04748db2517ab03",
|
||||
Url: "https://mutinynet-flow.lnolymp.us/api/v1",
|
||||
LspType: LSP_TYPE_FLOW_2_0,
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
||||
func OlympusMutinynetLSPS1LSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "032ae843e4d7d177f151d021ac8044b0636ec72b1ce3ffcde5c04748db2517ab03",
|
||||
Url: "https://mutinynet-lsps1.lnolymp.us/api/v1",
|
||||
LspType: LSP_TYPE_LSPS1,
|
||||
Pubkey: "032ae843e4d7d177f151d021ac8044b0636ec72b1ce3ffcde5c04748db2517ab03",
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
||||
func OlympusLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "031b301307574bbe9b9ac7b79cbe1700e31e544513eae0b5d7497483083f99e581",
|
||||
Url: "https://0conf.lnolymp.us/api/v1",
|
||||
LspType: LSP_TYPE_FLOW_2_0,
|
||||
Pubkey: "031b301307574bbe9b9ac7b79cbe1700e31e544513eae0b5d7497483083f99e581",
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
||||
func AlbyPlebsLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "029ca15ad2ea3077f5f0524c4c9bc266854c14b9fc81b9cc3d6b48e2460af13f65",
|
||||
Url: "https://lsp.albylabs.com",
|
||||
LspType: LSP_TYPE_PMLSP,
|
||||
Pubkey: "029ca15ad2ea3077f5f0524c4c9bc266854c14b9fc81b9cc3d6b48e2460af13f65",
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
func AlbyMutinynetPlebsLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "02f7029c14f3d805843e065d42e9bdc57f5f414249f335906bbe282ff99b2be17a",
|
||||
Url: "https://lsp-mutinynet.albylabs.com",
|
||||
LspType: LSP_TYPE_PMLSP,
|
||||
Pubkey: "02f7029c14f3d805843e065d42e9bdc57f5f414249f335906bbe282ff99b2be17a",
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
||||
func MegalithMutinynetLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "03e30fda71887a916ef5548a4d02b06fe04aaa1a8de9e24134ce7f139cf79d7579",
|
||||
Url: "https://lsp1.mutiny.megalith-node.com/api/lsps1/v1",
|
||||
LspType: LSP_TYPE_LSPS1,
|
||||
Pubkey: "03e30fda71887a916ef5548a4d02b06fe04aaa1a8de9e24134ce7f139cf79d7579",
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
||||
func MegalithLSP() LSP {
|
||||
lsp := LSP{
|
||||
Pubkey: "038a9e56512ec98da2b5789761f7af8f280baf98a09282360cd6ff1381b5e889bf",
|
||||
Url: "https://megalithic.me/api/lsps1/v1",
|
||||
LspType: LSP_TYPE_LSPS1,
|
||||
Pubkey: "038a9e56512ec98da2b5789761f7af8f280baf98a09282360cd6ff1381b5e889bf",
|
||||
}
|
||||
return lsp
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue