Skip to content

Commit

Permalink
Merge pull request #85 from Impa10r/v1.6.7
Browse files Browse the repository at this point in the history
v1.6.7
  • Loading branch information
Impa10r authored Jul 24, 2024
2 parents bcde489 + 46a6869 commit ea8532d
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 69 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Versions

## 1.6.7

- Fix AutoFees stop working bug
- Fix AutoFees applied on startup before forwards history has been downloaded
- LND 0.18: Fix AutoFees reacting to temporary balance increase due to pendinng HTLCs
- Highlight outputs to be used for peg-in or BTC withdrawal
- Warn when BTC swap-in amount is unlikely to cover chain fee
- Limit L-BTC swap-in amount to avoid excessive fee rate

## 1.6.6

- Allow advertising BTC balance to peers
Expand Down
113 changes: 98 additions & 15 deletions cmd/psweb/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ func peerHandler(w http.ResponseWriter, r *http.Request) {
bitcoinFeeRate := max(ln.EstimateFee(), mempoolFeeRate)

// arbitrary haircut to avoid 'no matching outgoing channel available'
maxLiquidSwapIn := min(int64(satAmount)-2000, int64(maxRemoteBalance)-10000)
maxLiquidSwapIn := min(int64(satAmount)-int64(ln.SwapFeeReserveLBTC), int64(maxRemoteBalance)-10000)
if maxLiquidSwapIn < 100_000 {
maxLiquidSwapIn = 0
}
Expand All @@ -427,10 +427,7 @@ func peerHandler(w http.ResponseWriter, r *http.Request) {
selectedChannel := peer.Channels[maxRemoteBalanceIndex].ChannelId
if ptr := ln.LiquidBalances[peer.NodeId]; ptr != nil {
peerLiquidBalance = int64(ptr.Amount)
// reserves are hardcoded here:
// https://github.com/ElementsProject/peerswap/blob/c77a82913d7898d0d3b7c83e4a990abf54bd97e5/swap/actions.go#L388
// https://github.com/ElementsProject/peerswap/blob/c77a82913d7898d0d3b7c83e4a990abf54bd97e5/peerswaprpc/server.go#L105
maxLiquidSwapOut = uint64(max(0, min(int64(maxLocalBalance)-5000, peerLiquidBalance-20300)))
maxLiquidSwapOut = uint64(max(0, min(int64(maxLocalBalance)-swapOutChannelReserve, peerLiquidBalance-swapOutChainReserve)))
if maxLiquidSwapOut >= 100_000 {
selectedChannel = peer.Channels[maxLocalBalanceIndex].ChannelId
} else {
Expand All @@ -442,16 +439,16 @@ func peerHandler(w http.ResponseWriter, r *http.Request) {
maxBitcoinSwapOut := uint64(0)
if ptr := ln.BitcoinBalances[peer.NodeId]; ptr != nil {
peerBitcoinBalance = int64(ptr.Amount)
maxBitcoinSwapOut = uint64(max(0, min(int64(maxLocalBalance)-5000, peerBitcoinBalance-20300)))
maxBitcoinSwapOut = uint64(max(0, min(int64(maxLocalBalance)-swapOutChannelReserve, peerBitcoinBalance-swapOutChainReserve)))
if maxBitcoinSwapOut >= 100_000 {
selectedChannel = peer.Channels[maxLocalBalanceIndex].ChannelId
} else {
maxBitcoinSwapOut = 0
}
}

// arbitrary haircut to avoid 'no matching outgoing channel available'
maxBitcoinSwapIn := min(btcBalance-2000, int64(maxRemoteBalance)-10000)
// arbitrary haircuts to avoid 'no matching outgoing channel available'
maxBitcoinSwapIn := min(btcBalance-int64(ln.SwapFeeReserveBTC), int64(maxRemoteBalance)-10000)
if maxBitcoinSwapIn < 100_000 {
maxBitcoinSwapIn = 0
}
Expand All @@ -460,20 +457,52 @@ func peerHandler(w http.ResponseWriter, r *http.Request) {
directionIn := false

// assume return to 50/50 channel
recommendLiquidSwapOut := maxLiquidSwapOut
recommendBitcoinSwapOut := maxBitcoinSwapOut
recommendLiquidSwapOut := uint64(0)
recommendBitcoinSwapOut := uint64(0)
if maxLocalBalance > channelCapacity/2 {
recommendLiquidSwapOut = min(maxLiquidSwapOut, maxLocalBalance-channelCapacity/2)
recommendBitcoinSwapOut = min(recommendBitcoinSwapOut, maxLocalBalance-channelCapacity/2)
recommendBitcoinSwapOut = min(maxBitcoinSwapOut, maxLocalBalance-channelCapacity/2)
}

if recommendLiquidSwapOut < 100_000 {
if maxLiquidSwapOut >= 100_000 {
recommendLiquidSwapOut = 100_000
} else {
recommendLiquidSwapOut = 0
}
}

if recommendBitcoinSwapOut < 100_000 {
if maxBitcoinSwapOut >= 100_000 {
recommendBitcoinSwapOut = 100_000
} else {
recommendBitcoinSwapOut = 0
}
}

// assume return to 50/50 channel
recommendLiquidSwapIn := maxLiquidSwapIn
recommendBitcoinSwapIn := maxBitcoinSwapIn
recommendLiquidSwapIn := int64(0)
recommendBitcoinSwapIn := int64(0)
if maxRemoteBalance > channelCapacity/2 {
directionIn = true
recommendLiquidSwapIn = min(recommendLiquidSwapIn, int64(maxRemoteBalance-channelCapacity/2))
recommendBitcoinSwapIn = min(recommendBitcoinSwapIn, int64(maxRemoteBalance-channelCapacity/2))
recommendLiquidSwapIn = min(maxLiquidSwapIn, int64(maxRemoteBalance-channelCapacity/2))
recommendBitcoinSwapIn = min(maxBitcoinSwapIn, int64(maxRemoteBalance-channelCapacity/2))
}

if recommendLiquidSwapIn < 100_000 {
if maxLiquidSwapIn >= 100_000 {
recommendLiquidSwapIn = 100_000
} else {
recommendLiquidSwapIn = 0
}
}

if recommendBitcoinSwapIn < 100_000 {
if maxBitcoinSwapIn >= 100_000 {
recommendBitcoinSwapIn = 100_000
} else {
recommendBitcoinSwapIn = 0
}
}

type Page struct {
Expand Down Expand Up @@ -2241,8 +2270,62 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {

switch direction {
case "in":
// reserve depends on asset and LND/CLN implementation
var reserve uint64
var amountAvailable uint64

if asset == "btc" {
cl, clean, er := ln.GetClient()
if er != nil {
redirectWithError(w, r, "/config?", er)
return
}
defer clean()

amountAvailable = uint64(ln.ConfirmedWalletBalance(cl))
reserve = ln.SwapFeeReserveBTC
} else if asset == "lbtc" {
client, cleanup, err := ps.GetClient(config.Config.RpcHost)
if err != nil {
redirectWithError(w, r, "/config?", err)
return
}
defer cleanup()

res, err := ps.LiquidGetBalance(client)
if err != nil {
log.Printf("unable to connect to RPC server: %v", err)
redirectWithError(w, r, "/config?", err)
return
}

amountAvailable = res.GetSatAmount()
reserve = ln.SwapFeeReserveLBTC
}

if amountAvailable < reserve || swapAmount > amountAvailable-reserve {
redirectWithError(w, r, "/peer?id="+nodeId+"&", errors.New("swap amount exceeds wallet balance less reserve "+formatWithThousandSeparators(reserve)+" sats"))
return
}

id, err = ps.SwapIn(client, swapAmount, channelId, asset, false)
case "out":
peerId := peerNodeId[channelId]
var ptr *ln.BalanceInfo

if asset == "btc" {
ptr = ln.BitcoinBalances[peerId]
} else if asset == "lbtc" {
ptr = ln.LiquidBalances[peerId]
}

if ptr != nil {
if ptr.Amount < swapOutChainReserve || swapAmount > ptr.Amount-swapOutChainReserve {
redirectWithError(w, r, "/peer?id="+nodeId+"&", errors.New("swap amount exceeds peer's wallet balance less reserve "+formatWithThousandSeparators(swapOutChainReserve)+" sats"))
return
}
}

id, err = ps.SwapOut(client, swapAmount, channelId, asset, false)
}

Expand Down
13 changes: 3 additions & 10 deletions cmd/psweb/ln/cln.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import (
const (
Implementation = "CLN"
fileRPC = "lightning-rpc"
// Liquid balance to reserve in auto swap-ins
// https://github.com/ElementsProject/peerswap/blob/master/clightning/clightning_commands.go#L392
SwapFeeReserveLBTC = uint64(0)
// 2000 to avoid high fee
SwapFeeReserveLBTC = uint64(2000)
SwapFeeReserveBTC = uint64(2000)
)

Expand Down Expand Up @@ -1133,25 +1133,21 @@ func HasInboundFees() bool {
}

func ApplyAutoFees() {
if !AutoFeeEnabledAll || autoFeeIsRunning {
if !AutoFeeEnabledAll {
return
}

autoFeeIsRunning = true

CacheForwards()

client, cleanup, err := GetClient()
if err != nil {
autoFeeIsRunning = false
return
}
defer cleanup()

var response map[string]interface{}

if client.Request(&ListPeerChannelsRequest{}, &response) != nil {
autoFeeIsRunning = false
return
}

Expand Down Expand Up @@ -1194,7 +1190,6 @@ func ApplyAutoFees() {
} else {
// move threshold or do nothing
moveLowLiqThreshold(channelId, params.FailedMoveThreshold)
autoFeeIsRunning = false
return
}
}
Expand All @@ -1213,8 +1208,6 @@ func ApplyAutoFees() {
}
}
}

autoFeeIsRunning = false
}

func PlotPPM(channelId uint64) *[]DataPoint {
Expand Down
3 changes: 0 additions & 3 deletions cmd/psweb/ln/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,6 @@ var (
// track timestamp of the last outbound forward per channel
LastForwardTS = make(map[uint64]int64)

// prevents starting another fee update while the first still running
autoFeeIsRunning = false

// received via custom messages, per peer nodeId
LiquidBalances = make(map[string]*BalanceInfo)
BitcoinBalances = make(map[string]*BalanceInfo)
Expand Down
36 changes: 14 additions & 22 deletions cmd/psweb/ln/lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ import (

const (
Implementation = "LND"
// Liquid balance to reserve in auto swap-ins
// https://github.com/ElementsProject/peerswap/blob/master/peerswaprpc/server.go#L234
SwapFeeReserveLBTC = uint64(1000)
// 2000 to avoid high fee
SwapFeeReserveLBTC = uint64(2000)
SwapFeeReserveBTC = uint64(2000)
)

Expand Down Expand Up @@ -1802,12 +1802,10 @@ func SetHtlcSize(peerNodeId string,
// called after individual HTLC settles or fails
func applyAutoFee(client lnrpc.LightningClient, channelId uint64, htlcFail bool) {

if !AutoFeeEnabledAll || !AutoFeeEnabled[channelId] || autoFeeIsRunning {
if !AutoFeeEnabledAll || !AutoFeeEnabled[channelId] {
return
}

autoFeeIsRunning = true

params := &AutoFeeDefaults
if AutoFee[channelId] != nil {
// channel has custom parameters
Expand All @@ -1819,7 +1817,6 @@ func applyAutoFee(client lnrpc.LightningClient, channelId uint64, htlcFail bool)
// get my node id
res, err := client.GetInfo(ctx, &lnrpc.GetInfoRequest{})
if err != nil {
autoFeeIsRunning = false
return
}
myNodeId = res.GetIdentityPubkey()
Expand All @@ -1828,7 +1825,6 @@ func applyAutoFee(client lnrpc.LightningClient, channelId uint64, htlcFail bool)
ChanId: channelId,
})
if err != nil {
autoFeeIsRunning = false
return
}

Expand All @@ -1846,23 +1842,22 @@ func applyAutoFee(client lnrpc.LightningClient, channelId uint64, htlcFail bool)
// get balances
bytePeer, err := hex.DecodeString(peerId)
if err != nil {
autoFeeIsRunning = false
return
}

res, err := client.ListChannels(ctx, &lnrpc.ListChannelsRequest{
Peer: bytePeer,
})
if err != nil {
autoFeeIsRunning = false
return
}

localBalance := int64(0)
unsettledBalance := int64(0)
for _, ch := range res.Channels {
if ch.ChanId == channelId {
localBalance = ch.LocalBalance + ch.UnsettledBalance

unsettledBalance = ch.UnsettledBalance
break
}
}
Expand All @@ -1876,7 +1871,6 @@ func applyAutoFee(client lnrpc.LightningClient, channelId uint64, htlcFail bool)
} else if liqPct > params.LowLiqPct {
// move threshold
moveLowLiqThreshold(channelId, params.FailedMoveThreshold)
autoFeeIsRunning = false
return
}
} else {
Expand All @@ -1885,27 +1879,26 @@ func applyAutoFee(client lnrpc.LightningClient, channelId uint64, htlcFail bool)

// set the new rate
if newFee != oldFee {
if unsettledBalance > 0 && newFee < oldFee {
// do not lower fees for temporary balance spikes due to pending HTLCs
return
}
if old, err := SetFeeRate(peerId, channelId, int64(newFee), false, false); err == nil {
// log the last change
LogFee(channelId, old, newFee, false, false)
}
}

autoFeeIsRunning = false
}

// review all fees on timer
func ApplyAutoFees() {

if !AutoFeeEnabledAll || autoFeeIsRunning {
if !AutoFeeEnabledAll {
return
}

autoFeeIsRunning = true

client, cleanup, err := GetClient()
if err != nil {
autoFeeIsRunning = false
return
}
defer cleanup()
Expand All @@ -1915,7 +1908,6 @@ func ApplyAutoFees() {
// get my node id
res, err := client.GetInfo(ctx, &lnrpc.GetInfoRequest{})
if err != nil {
autoFeeIsRunning = false
return
}
myNodeId = res.GetIdentityPubkey()
Expand All @@ -1925,7 +1917,6 @@ func ApplyAutoFees() {
ActiveOnly: true,
})
if err != nil {
autoFeeIsRunning = false
return
}

Expand All @@ -1944,7 +1935,6 @@ func ApplyAutoFees() {
ChanId: ch.ChanId,
})
if err != nil {
autoFeeIsRunning = false
return
}

Expand All @@ -1964,6 +1954,10 @@ func ApplyAutoFees() {

// set the new rate
if newFee != oldFee {
if ch.UnsettledBalance > 0 && newFee < oldFee {
// do not lower fees for temporary balance spikes due to pending HTLCs
continue
}
_, err := SetFeeRate(peerId, ch.ChanId, int64(newFee), false, false)
if err == nil {
// log the last change
Expand Down Expand Up @@ -1998,8 +1992,6 @@ func ApplyAutoFees() {
}
}
}

autoFeeIsRunning = false
}

func PlotPPM(channelId uint64) *[]DataPoint {
Expand Down
Loading

0 comments on commit ea8532d

Please sign in to comment.