Skip to content

Commit

Permalink
Merge pull request #71 from Impa10r/v1.5.9
Browse files Browse the repository at this point in the history
v1.5.9
  • Loading branch information
Impa10r authored Jul 3, 2024
2 parents 33faf8f + f088e6c commit 8a31ad2
Show file tree
Hide file tree
Showing 12 changed files with 391 additions and 243 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Versions

## 1.5.9

- Add get BTC receiving address and send BTC with coin selection
- AutoFee: add column with days from the last outbound flow
- AutoFee: fix live outbound payments not registering for LND

## 1.5.8

- Ignore forwards < 1000 sats in statistics and autofees
Expand Down
2 changes: 2 additions & 0 deletions cmd/psweb/config/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ func Load(dataDir string) {
func Save() error {
jsonData, err := json.MarshalIndent(Config, "", " ")
if err != nil {
log.Println("Error saving config file:", err)
return err
}
filename := filepath.Join(Config.DataDir, "pswebconfig.json")
err = os.WriteFile(filename, jsonData, 0644)
if err != nil {
log.Println("Error saving config file:", err)
return err
}
return nil
Expand Down
146 changes: 97 additions & 49 deletions cmd/psweb/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"peerswap-web/cmd/psweb/bitcoin"
"peerswap-web/cmd/psweb/config"
"peerswap-web/cmd/psweb/db"
"peerswap-web/cmd/psweb/internet"
"peerswap-web/cmd/psweb/liquid"
"peerswap-web/cmd/psweb/ln"
"peerswap-web/cmd/psweb/ps"
Expand Down Expand Up @@ -486,6 +485,13 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
popupMessage = keys[0]
}

// newly genetated address
addr := ""
keys, ok = r.URL.Query()["addr"]
if ok && len(keys[0]) > 0 {
addr = keys[0]
}

var utxos []ln.UTXO
cl, clean, er := ln.GetClient()
if er != nil {
Expand All @@ -502,6 +508,7 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
BitcoinBalance uint64
Outputs *[]ln.UTXO
PeginTxId string
IsPegin bool // false for ordinary BTC withdrawal
PeginAmount uint64
BitcoinApi string
Confirmations int32
Expand All @@ -515,6 +522,7 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
CanBump bool
CanRBF bool
IsCLN bool
BitcoinAddress string
}

btcBalance := ln.ConfirmedWalletBalance(cl)
Expand All @@ -536,8 +544,8 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
fee = fee + fee/2
}
}
if fee < config.Config.PeginFeeRate+1 {
fee = config.Config.PeginFeeRate + 1 // min increment
if fee < config.Config.PeginFeeRate+2 {
fee = config.Config.PeginFeeRate + 2 // min increment
}
}
}
Expand All @@ -554,6 +562,7 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
BitcoinBalance: uint64(btcBalance),
Outputs: &utxos,
PeginTxId: config.Config.PeginTxId,
IsPegin: config.Config.PeginClaimScript != "",
PeginAmount: uint64(config.Config.PeginAmount),
BitcoinApi: config.Config.BitcoinApi,
Confirmations: confs,
Expand All @@ -563,16 +572,18 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
MempoolFeeRate: mempoolFeeRate,
LiquidFeeRate: liquid.EstimateFee(),
SuggestedFeeRate: fee,
MinBumpFeeRate: config.Config.PeginFeeRate + 1,
MinBumpFeeRate: config.Config.PeginFeeRate + 2,
CanBump: canBump,
CanRBF: ln.CanRBF(),
IsCLN: ln.Implementation == "CLN",
BitcoinAddress: addr,
}

// executing template named "bitcoin"
executeTemplate(w, "bitcoin", data)
}

// handles Liquid pegin and Bitcoin send form
func peginHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
// Parse the form data
Expand All @@ -595,6 +606,7 @@ func peginHandler(w http.ResponseWriter, r *http.Request) {

selectedOutputs := r.Form["selected_outputs[]"]
subtractFeeFromAmount := r.FormValue("subtractfee") == "on"
isPegin := r.FormValue("isPegin") == "true"

totalAmount := int64(0)

Expand Down Expand Up @@ -638,69 +650,79 @@ func peginHandler(w http.ResponseWriter, r *http.Request) {
return
}

// test on pre-existing tx that bitcon core can complete the peg
tx := "b61ec844027ce18fd3eb91fa7bed8abaa6809c4d3f6cf4952b8ebaa7cd46583a"
if config.Config.Chain == "testnet" {
tx = "2c7ec5043fe8ee3cb4ce623212c0e52087d3151c9e882a04073cce1688d6fc1e"
}
address := ""
claimScript := ""

if isPegin {
// test on pre-existing tx that bitcon core can complete the peg
tx := "b61ec844027ce18fd3eb91fa7bed8abaa6809c4d3f6cf4952b8ebaa7cd46583a"
if config.Config.Chain == "testnet" {
tx = "2c7ec5043fe8ee3cb4ce623212c0e52087d3151c9e882a04073cce1688d6fc1e"
}

_, err = bitcoin.GetTxOutProof(tx)
if err != nil {
// automatic fallback to getblock.io
config.Config.BitcoinHost = config.GetBlockIoHost()
config.Config.BitcoinUser = ""
config.Config.BitcoinPass = ""
_, err = bitcoin.GetTxOutProof(tx)
if err != nil {
redirectWithError(w, r, "/bitcoin?", errors.New("GetTxOutProof failed, check BitcoinHost in Config"))
return
} else {
// use getblock.io endpoint going forward
log.Println("Switching to getblock.io bitcoin host endpoint")
if err := config.Save(); err != nil {
log.Println("Error saving config file:", err)
redirectWithError(w, r, "/bitcoin?", err)
// automatic fallback to getblock.io
config.Config.BitcoinHost = config.GetBlockIoHost()
config.Config.BitcoinUser = ""
config.Config.BitcoinPass = ""
_, err = bitcoin.GetTxOutProof(tx)
if err != nil {
redirectWithError(w, r, "/bitcoin?", errors.New("GetTxOutProof failed, check BitcoinHost in Config"))
return
} else {
// use getblock.io endpoint going forward
log.Println("Switching to getblock.io bitcoin host endpoint")
if err := config.Save(); err != nil {
redirectWithError(w, r, "/bitcoin?", err)
return
}
}
}
}

var addr liquid.PeginAddress
var addr liquid.PeginAddress

err = liquid.GetPeginAddress(&addr)
if err != nil {
redirectWithError(w, r, "/bitcoin?", err)
return
err = liquid.GetPeginAddress(&addr)
if err != nil {
redirectWithError(w, r, "/bitcoin?", err)
return
}

address = addr.MainChainAddress
claimScript = addr.ClaimScript
} else {
address = r.FormValue("sendAddress")
claimScript = ""
}

res, err := ln.SendCoinsWithUtxos(&selectedOutputs, addr.MainChainAddress, amount, fee, subtractFeeFromAmount)
res, err := ln.SendCoinsWithUtxos(&selectedOutputs, address, amount, fee, subtractFeeFromAmount)
if err != nil {
redirectWithError(w, r, "/bitcoin?", err)
return
}

// to speed things up, also broadcast it to mempool.space
internet.SendRawTransaction(res.RawHex)

log.Println("Peg-in TxId:", res.TxId, "RawHex:", res.RawHex, "Claim script:", addr.ClaimScript)
duration := time.Duration(1020) * time.Minute
formattedDuration := time.Time{}.Add(duration).Format("15h 04m")
if isPegin {
log.Println("Peg-in TxId:", res.TxId, "RawHex:", res.RawHex, "Claim script:", claimScript)
duration := time.Duration(1020) * time.Minute
formattedDuration := time.Time{}.Add(duration).Format("15h 04m")
telegramSendMessage("⏰ Started peg-in " + formatWithThousandSeparators(uint64(res.AmountSat)) + " sats. Time left: " + formattedDuration)
} else {
log.Println("BTC withdrawal TxId:", res.TxId, "RawHex:", res.RawHex)
telegramSendMessage("BTC withdrawal pending: " + formatWithThousandSeparators(uint64(res.AmountSat)) + " sats.")
}

config.Config.PeginClaimScript = addr.ClaimScript
config.Config.PeginAddress = addr.MainChainAddress
config.Config.PeginClaimScript = claimScript
config.Config.PeginAddress = address
config.Config.PeginAmount = res.AmountSat
config.Config.PeginTxId = res.TxId
config.Config.PeginReplacedTxId = ""
config.Config.PeginFeeRate = uint32(fee)

if err := config.Save(); err != nil {
log.Println("Error saving config file:", err)
redirectWithError(w, r, "/bitcoin?", err)
return
}

telegramSendMessage("⏰ Started peg-in " + formatWithThousandSeparators(uint64(res.AmountSat)) + " sats. Time left: " + formattedDuration)

// Redirect to bitcoin page to follow the pegin progress
http.Redirect(w, r, "/bitcoin", http.StatusSeeOther)
} else {
Expand Down Expand Up @@ -748,9 +770,6 @@ func bumpfeeHandler(w http.ResponseWriter, r *http.Request) {
}

if ln.CanRBF() {
// to speed things up, also broadcast it to mempool.space
internet.SendRawTransaction(res.RawHex)

log.Println("RBF TxId:", res.TxId)
config.Config.PeginReplacedTxId = config.Config.PeginTxId
config.Config.PeginAmount = res.AmountSat
Expand All @@ -764,7 +783,6 @@ func bumpfeeHandler(w http.ResponseWriter, r *http.Request) {
config.Config.PeginFeeRate = uint32(fee)

if err := config.Save(); err != nil {
log.Println("Error saving config file:", err)
redirectWithError(w, r, "/bitcoin?", err)
return
}
Expand Down Expand Up @@ -833,13 +851,19 @@ func afHandler(w http.ResponseWriter, r *http.Request) {
localPct := uint64(0)
feeRate := outboundFeeRates[channelId]
inboundRate := inboundFeeRates[channelId]
currentTime := time.Now()

for _, peer := range res.GetPeers() {
alias := getNodeAlias(peer.NodeId)
for _, ch := range peer.Channels {
rule, custom := ln.AutoFeeRatesSummary(ch.ChannelId)
af, _ := ln.AutoFeeRule(ch.ChannelId)
peerNodeId[ch.ChannelId] = peer.NodeId
daysNoFlow := 999
ts, ok := ln.LastForwardTS[ch.ChannelId]
if ok {
daysNoFlow = int(currentTime.Sub(time.Unix(ts, 0)).Hours() / 24)
}

channelList = append(channelList, &ln.AutoFeeStatus{
Enabled: ln.AutoFeeEnabled[ch.ChannelId],
Expand All @@ -852,6 +876,7 @@ func afHandler(w http.ResponseWriter, r *http.Request) {
FeeRate: outboundFeeRates[ch.ChannelId],
InboundRate: inboundFeeRates[ch.ChannelId],
ChannelId: ch.ChannelId,
DaysNoFlow: daysNoFlow,
})

if ch.ChannelId == channelId {
Expand Down Expand Up @@ -1444,6 +1469,17 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {
defer cleanup()

switch action {
case "deleteTxId":
// acknowledges BTC withdrawal
config.Config.PeginTxId = ""
if err := config.Save(); err != nil {
redirectWithError(w, r, "/bitcoin?", err)
return
}

// all done
http.Redirect(w, r, "/", http.StatusSeeOther)
return
case "saveAutoFee":
channelId, err := strconv.ParseUint(r.FormValue("channelId"), 10, 64)
if err != nil {
Expand Down Expand Up @@ -1845,7 +1881,6 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {

// Save config
if err := config.Save(); err != nil {
log.Println("Error saving config file:", err)
redirectWithError(w, r, "/liquid?", err)
return
}
Expand All @@ -1854,6 +1889,18 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/liquid?msg="+msg, http.StatusSeeOther)
return

case "newBitcoinAddress":
addr, err := ln.NewAddress()
if err != nil {
log.Printf("unable to connect to RPC server: %v", err)
redirectWithError(w, r, "/bitcoin?", err)
return
}

// Redirect to bitcoin page with new address
http.Redirect(w, r, "/bitcoin?addr="+addr, http.StatusSeeOther)
return

case "newAddress":
res, err := ps.LiquidGetAddress(client)
if err != nil {
Expand Down Expand Up @@ -2012,7 +2059,10 @@ func saveConfigHandler(w http.ResponseWriter, r *http.Request) {
// display CA certificate installation instructions
if secureConnection && !config.Config.SecureConnection {
config.Config.ServerIPs = r.FormValue("serverIPs")
config.Save()
if err := config.Save(); err != nil {
redirectWithError(w, r, "/config?", err)
return
}
http.Redirect(w, r, "/ca", http.StatusSeeOther)
return
}
Expand Down Expand Up @@ -2105,15 +2155,13 @@ func saveConfigHandler(w http.ResponseWriter, r *http.Request) {
}

if err := config.Save(); err != nil {
log.Println("Error saving config file:", err)
redirectWithError(w, r, "/config?", err)
return
}

if mustRestart {
// show progress bar and log
go http.Redirect(w, r, "/loading", http.StatusSeeOther)
config.SavePS()
ps.Stop()
} else if clientIsDown { // configs did not work, try again
redirectWithError(w, r, "/config?", err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/psweb/ln/cln.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ func CacheForwards() {
forwardsIn[chIn] = append(forwardsIn[chIn], f)
forwardsOut[chOut] = append(forwardsOut[chOut], f)
// save for autofees
lastForwardTS[chOut] = int64(f.ResolvedTime)
LastForwardTS[chOut] = int64(f.ResolvedTime)
} else {
// catch not enough balance error
if f.FailCode == 4103 {
Expand Down
7 changes: 4 additions & 3 deletions cmd/psweb/ln/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type AutoFeeStatus struct {
Custom bool
FeeRate int64
InboundRate int64
DaysNoFlow int
}

type AutoFeeParams struct {
Expand Down Expand Up @@ -161,7 +162,7 @@ var (
}

// track timestamp of the last outbound forward per channel
lastForwardTS = make(map[uint64]int64)
LastForwardTS = make(map[uint64]int64)

// prevents starting another fee update while the first still running
autoFeeIsRunning = false
Expand Down Expand Up @@ -244,7 +245,7 @@ func AutoFeeRatesSummary(channelId uint64) (string, bool) {

func LoadDB() {
// load rebates from db
db.Load("Swaps", "SwapRebates", SwapRebates)
db.Load("Swaps", "SwapRebates", &SwapRebates)

// load auto fees from db
db.Load("AutoFees", "AutoFeeEnabledAll", &AutoFeeEnabledAll)
Expand Down Expand Up @@ -283,7 +284,7 @@ func calculateAutoFee(channelId uint64, params *AutoFeeParams, liqPct int, oldFe
// see if cool-off period has passed
if lastUpdate < time.Now().Add(-time.Duration(params.CoolOffHours)*time.Hour).Unix() {
// check the inactivity period
if lastForwardTS[channelId] < time.Now().AddDate(0, 0, -params.InactivityDays).Unix() {
if LastForwardTS[channelId] < time.Now().AddDate(0, 0, -params.InactivityDays).Unix() {
// decrease the fee
newFee -= params.InactivityDropPPM
newFee = newFee * (100 - params.InactivityDropPct) / 100
Expand Down
Loading

0 comments on commit 8a31ad2

Please sign in to comment.