Skip to content

Commit 8a31ad2

Browse files
authored
Merge pull request #71 from Impa10r/v1.5.9
v1.5.9
2 parents 33faf8f + f088e6c commit 8a31ad2

File tree

12 files changed

+391
-243
lines changed

12 files changed

+391
-243
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Versions
22

3+
## 1.5.9
4+
5+
- Add get BTC receiving address and send BTC with coin selection
6+
- AutoFee: add column with days from the last outbound flow
7+
- AutoFee: fix live outbound payments not registering for LND
8+
39
## 1.5.8
410

511
- Ignore forwards < 1000 sats in statistics and autofees

cmd/psweb/config/common.go

+2
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,13 @@ func Load(dataDir string) {
143143
func Save() error {
144144
jsonData, err := json.MarshalIndent(Config, "", " ")
145145
if err != nil {
146+
log.Println("Error saving config file:", err)
146147
return err
147148
}
148149
filename := filepath.Join(Config.DataDir, "pswebconfig.json")
149150
err = os.WriteFile(filename, jsonData, 0644)
150151
if err != nil {
152+
log.Println("Error saving config file:", err)
151153
return err
152154
}
153155
return nil

cmd/psweb/handlers.go

+97-49
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"peerswap-web/cmd/psweb/bitcoin"
2020
"peerswap-web/cmd/psweb/config"
2121
"peerswap-web/cmd/psweb/db"
22-
"peerswap-web/cmd/psweb/internet"
2322
"peerswap-web/cmd/psweb/liquid"
2423
"peerswap-web/cmd/psweb/ln"
2524
"peerswap-web/cmd/psweb/ps"
@@ -486,6 +485,13 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
486485
popupMessage = keys[0]
487486
}
488487

488+
// newly genetated address
489+
addr := ""
490+
keys, ok = r.URL.Query()["addr"]
491+
if ok && len(keys[0]) > 0 {
492+
addr = keys[0]
493+
}
494+
489495
var utxos []ln.UTXO
490496
cl, clean, er := ln.GetClient()
491497
if er != nil {
@@ -502,6 +508,7 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
502508
BitcoinBalance uint64
503509
Outputs *[]ln.UTXO
504510
PeginTxId string
511+
IsPegin bool // false for ordinary BTC withdrawal
505512
PeginAmount uint64
506513
BitcoinApi string
507514
Confirmations int32
@@ -515,6 +522,7 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
515522
CanBump bool
516523
CanRBF bool
517524
IsCLN bool
525+
BitcoinAddress string
518526
}
519527

520528
btcBalance := ln.ConfirmedWalletBalance(cl)
@@ -536,8 +544,8 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
536544
fee = fee + fee/2
537545
}
538546
}
539-
if fee < config.Config.PeginFeeRate+1 {
540-
fee = config.Config.PeginFeeRate + 1 // min increment
547+
if fee < config.Config.PeginFeeRate+2 {
548+
fee = config.Config.PeginFeeRate + 2 // min increment
541549
}
542550
}
543551
}
@@ -554,6 +562,7 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
554562
BitcoinBalance: uint64(btcBalance),
555563
Outputs: &utxos,
556564
PeginTxId: config.Config.PeginTxId,
565+
IsPegin: config.Config.PeginClaimScript != "",
557566
PeginAmount: uint64(config.Config.PeginAmount),
558567
BitcoinApi: config.Config.BitcoinApi,
559568
Confirmations: confs,
@@ -563,16 +572,18 @@ func bitcoinHandler(w http.ResponseWriter, r *http.Request) {
563572
MempoolFeeRate: mempoolFeeRate,
564573
LiquidFeeRate: liquid.EstimateFee(),
565574
SuggestedFeeRate: fee,
566-
MinBumpFeeRate: config.Config.PeginFeeRate + 1,
575+
MinBumpFeeRate: config.Config.PeginFeeRate + 2,
567576
CanBump: canBump,
568577
CanRBF: ln.CanRBF(),
569578
IsCLN: ln.Implementation == "CLN",
579+
BitcoinAddress: addr,
570580
}
571581

572582
// executing template named "bitcoin"
573583
executeTemplate(w, "bitcoin", data)
574584
}
575585

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

596607
selectedOutputs := r.Form["selected_outputs[]"]
597608
subtractFeeFromAmount := r.FormValue("subtractfee") == "on"
609+
isPegin := r.FormValue("isPegin") == "true"
598610

599611
totalAmount := int64(0)
600612

@@ -638,69 +650,79 @@ func peginHandler(w http.ResponseWriter, r *http.Request) {
638650
return
639651
}
640652

641-
// test on pre-existing tx that bitcon core can complete the peg
642-
tx := "b61ec844027ce18fd3eb91fa7bed8abaa6809c4d3f6cf4952b8ebaa7cd46583a"
643-
if config.Config.Chain == "testnet" {
644-
tx = "2c7ec5043fe8ee3cb4ce623212c0e52087d3151c9e882a04073cce1688d6fc1e"
645-
}
653+
address := ""
654+
claimScript := ""
655+
656+
if isPegin {
657+
// test on pre-existing tx that bitcon core can complete the peg
658+
tx := "b61ec844027ce18fd3eb91fa7bed8abaa6809c4d3f6cf4952b8ebaa7cd46583a"
659+
if config.Config.Chain == "testnet" {
660+
tx = "2c7ec5043fe8ee3cb4ce623212c0e52087d3151c9e882a04073cce1688d6fc1e"
661+
}
646662

647-
_, err = bitcoin.GetTxOutProof(tx)
648-
if err != nil {
649-
// automatic fallback to getblock.io
650-
config.Config.BitcoinHost = config.GetBlockIoHost()
651-
config.Config.BitcoinUser = ""
652-
config.Config.BitcoinPass = ""
653663
_, err = bitcoin.GetTxOutProof(tx)
654664
if err != nil {
655-
redirectWithError(w, r, "/bitcoin?", errors.New("GetTxOutProof failed, check BitcoinHost in Config"))
656-
return
657-
} else {
658-
// use getblock.io endpoint going forward
659-
log.Println("Switching to getblock.io bitcoin host endpoint")
660-
if err := config.Save(); err != nil {
661-
log.Println("Error saving config file:", err)
662-
redirectWithError(w, r, "/bitcoin?", err)
665+
// automatic fallback to getblock.io
666+
config.Config.BitcoinHost = config.GetBlockIoHost()
667+
config.Config.BitcoinUser = ""
668+
config.Config.BitcoinPass = ""
669+
_, err = bitcoin.GetTxOutProof(tx)
670+
if err != nil {
671+
redirectWithError(w, r, "/bitcoin?", errors.New("GetTxOutProof failed, check BitcoinHost in Config"))
663672
return
673+
} else {
674+
// use getblock.io endpoint going forward
675+
log.Println("Switching to getblock.io bitcoin host endpoint")
676+
if err := config.Save(); err != nil {
677+
redirectWithError(w, r, "/bitcoin?", err)
678+
return
679+
}
664680
}
665681
}
666-
}
667682

668-
var addr liquid.PeginAddress
683+
var addr liquid.PeginAddress
669684

670-
err = liquid.GetPeginAddress(&addr)
671-
if err != nil {
672-
redirectWithError(w, r, "/bitcoin?", err)
673-
return
685+
err = liquid.GetPeginAddress(&addr)
686+
if err != nil {
687+
redirectWithError(w, r, "/bitcoin?", err)
688+
return
689+
}
690+
691+
address = addr.MainChainAddress
692+
claimScript = addr.ClaimScript
693+
} else {
694+
address = r.FormValue("sendAddress")
695+
claimScript = ""
674696
}
675697

676-
res, err := ln.SendCoinsWithUtxos(&selectedOutputs, addr.MainChainAddress, amount, fee, subtractFeeFromAmount)
698+
res, err := ln.SendCoinsWithUtxos(&selectedOutputs, address, amount, fee, subtractFeeFromAmount)
677699
if err != nil {
678700
redirectWithError(w, r, "/bitcoin?", err)
679701
return
680702
}
681703

682-
// to speed things up, also broadcast it to mempool.space
683-
internet.SendRawTransaction(res.RawHex)
684-
685-
log.Println("Peg-in TxId:", res.TxId, "RawHex:", res.RawHex, "Claim script:", addr.ClaimScript)
686-
duration := time.Duration(1020) * time.Minute
687-
formattedDuration := time.Time{}.Add(duration).Format("15h 04m")
704+
if isPegin {
705+
log.Println("Peg-in TxId:", res.TxId, "RawHex:", res.RawHex, "Claim script:", claimScript)
706+
duration := time.Duration(1020) * time.Minute
707+
formattedDuration := time.Time{}.Add(duration).Format("15h 04m")
708+
telegramSendMessage("⏰ Started peg-in " + formatWithThousandSeparators(uint64(res.AmountSat)) + " sats. Time left: " + formattedDuration)
709+
} else {
710+
log.Println("BTC withdrawal TxId:", res.TxId, "RawHex:", res.RawHex)
711+
telegramSendMessage("BTC withdrawal pending: " + formatWithThousandSeparators(uint64(res.AmountSat)) + " sats.")
712+
}
688713

689-
config.Config.PeginClaimScript = addr.ClaimScript
690-
config.Config.PeginAddress = addr.MainChainAddress
714+
config.Config.PeginClaimScript = claimScript
715+
config.Config.PeginAddress = address
691716
config.Config.PeginAmount = res.AmountSat
692717
config.Config.PeginTxId = res.TxId
693718
config.Config.PeginReplacedTxId = ""
694719
config.Config.PeginFeeRate = uint32(fee)
695720

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

702-
telegramSendMessage("⏰ Started peg-in " + formatWithThousandSeparators(uint64(res.AmountSat)) + " sats. Time left: " + formattedDuration)
703-
704726
// Redirect to bitcoin page to follow the pegin progress
705727
http.Redirect(w, r, "/bitcoin", http.StatusSeeOther)
706728
} else {
@@ -748,9 +770,6 @@ func bumpfeeHandler(w http.ResponseWriter, r *http.Request) {
748770
}
749771

750772
if ln.CanRBF() {
751-
// to speed things up, also broadcast it to mempool.space
752-
internet.SendRawTransaction(res.RawHex)
753-
754773
log.Println("RBF TxId:", res.TxId)
755774
config.Config.PeginReplacedTxId = config.Config.PeginTxId
756775
config.Config.PeginAmount = res.AmountSat
@@ -764,7 +783,6 @@ func bumpfeeHandler(w http.ResponseWriter, r *http.Request) {
764783
config.Config.PeginFeeRate = uint32(fee)
765784

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

837856
for _, peer := range res.GetPeers() {
838857
alias := getNodeAlias(peer.NodeId)
839858
for _, ch := range peer.Channels {
840859
rule, custom := ln.AutoFeeRatesSummary(ch.ChannelId)
841860
af, _ := ln.AutoFeeRule(ch.ChannelId)
842861
peerNodeId[ch.ChannelId] = peer.NodeId
862+
daysNoFlow := 999
863+
ts, ok := ln.LastForwardTS[ch.ChannelId]
864+
if ok {
865+
daysNoFlow = int(currentTime.Sub(time.Unix(ts, 0)).Hours() / 24)
866+
}
843867

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

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

14461471
switch action {
1472+
case "deleteTxId":
1473+
// acknowledges BTC withdrawal
1474+
config.Config.PeginTxId = ""
1475+
if err := config.Save(); err != nil {
1476+
redirectWithError(w, r, "/bitcoin?", err)
1477+
return
1478+
}
1479+
1480+
// all done
1481+
http.Redirect(w, r, "/", http.StatusSeeOther)
1482+
return
14471483
case "saveAutoFee":
14481484
channelId, err := strconv.ParseUint(r.FormValue("channelId"), 10, 64)
14491485
if err != nil {
@@ -1845,7 +1881,6 @@ func submitHandler(w http.ResponseWriter, r *http.Request) {
18451881

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

1892+
case "newBitcoinAddress":
1893+
addr, err := ln.NewAddress()
1894+
if err != nil {
1895+
log.Printf("unable to connect to RPC server: %v", err)
1896+
redirectWithError(w, r, "/bitcoin?", err)
1897+
return
1898+
}
1899+
1900+
// Redirect to bitcoin page with new address
1901+
http.Redirect(w, r, "/bitcoin?addr="+addr, http.StatusSeeOther)
1902+
return
1903+
18571904
case "newAddress":
18581905
res, err := ps.LiquidGetAddress(client)
18591906
if err != nil {
@@ -2012,7 +2059,10 @@ func saveConfigHandler(w http.ResponseWriter, r *http.Request) {
20122059
// display CA certificate installation instructions
20132060
if secureConnection && !config.Config.SecureConnection {
20142061
config.Config.ServerIPs = r.FormValue("serverIPs")
2015-
config.Save()
2062+
if err := config.Save(); err != nil {
2063+
redirectWithError(w, r, "/config?", err)
2064+
return
2065+
}
20162066
http.Redirect(w, r, "/ca", http.StatusSeeOther)
20172067
return
20182068
}
@@ -2105,15 +2155,13 @@ func saveConfigHandler(w http.ResponseWriter, r *http.Request) {
21052155
}
21062156

21072157
if err := config.Save(); err != nil {
2108-
log.Println("Error saving config file:", err)
21092158
redirectWithError(w, r, "/config?", err)
21102159
return
21112160
}
21122161

21132162
if mustRestart {
21142163
// show progress bar and log
21152164
go http.Redirect(w, r, "/loading", http.StatusSeeOther)
2116-
config.SavePS()
21172165
ps.Stop()
21182166
} else if clientIsDown { // configs did not work, try again
21192167
redirectWithError(w, r, "/config?", err)

cmd/psweb/ln/cln.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ func CacheForwards() {
421421
forwardsIn[chIn] = append(forwardsIn[chIn], f)
422422
forwardsOut[chOut] = append(forwardsOut[chOut], f)
423423
// save for autofees
424-
lastForwardTS[chOut] = int64(f.ResolvedTime)
424+
LastForwardTS[chOut] = int64(f.ResolvedTime)
425425
} else {
426426
// catch not enough balance error
427427
if f.FailCode == 4103 {

cmd/psweb/ln/common.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type AutoFeeStatus struct {
8585
Custom bool
8686
FeeRate int64
8787
InboundRate int64
88+
DaysNoFlow int
8889
}
8990

9091
type AutoFeeParams struct {
@@ -161,7 +162,7 @@ var (
161162
}
162163

163164
// track timestamp of the last outbound forward per channel
164-
lastForwardTS = make(map[uint64]int64)
165+
LastForwardTS = make(map[uint64]int64)
165166

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

245246
func LoadDB() {
246247
// load rebates from db
247-
db.Load("Swaps", "SwapRebates", SwapRebates)
248+
db.Load("Swaps", "SwapRebates", &SwapRebates)
248249

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

0 commit comments

Comments
 (0)