From d1c7e684e2844811e1f51af32911308b4ef3887c Mon Sep 17 00:00:00 2001 From: helloscoopa Date: Wed, 10 Jun 2026 17:51:50 +0530 Subject: [PATCH 1/3] feat: integrate DCA bot with configuration and deposit notification --- config.yaml.example | 5 +++++ internal/config.go | 6 ++++++ internal/dca/dca.go | 34 ++++++++++++++++++++++++++++++ internal/lnbits/webhook/webhook.go | 3 +++ internal/telegram/transaction.go | 2 ++ 5 files changed, 50 insertions(+) create mode 100644 internal/dca/dca.go diff --git a/config.yaml.example b/config.yaml.example index 9258d6a2..ab8c4080 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -43,6 +43,11 @@ nostr: third_party: coinmarketcap_api_key: "your-cmc-api-key-here" # optional — get free key at coinmarketcap.com/api +# DCA bot integration +dca: + wallet_username: "" # when sats are received by this Telegram username, reset DCA retry counts + api_url: "https://bitcoindeepa-dca-be-production.up.railway.app" + # API Configuration api: # Analytics API - HMAC authenticated endpoints for data export diff --git a/internal/config.go b/internal/config.go index 3ead8fd2..36be4668 100644 --- a/internal/config.go +++ b/internal/config.go @@ -19,8 +19,14 @@ var Configuration = struct { Nostr NostrConfiguration `yaml:"nostr"` API APIConfiguration `yaml:"api"` ThirdParty ThirdPartyConfiguration `yaml:"third_party"` + DCA DCAConfiguration `yaml:"dca"` }{} +type DCAConfiguration struct { + WalletUsername string `yaml:"wallet_username"` + ApiUrl string `yaml:"api_url"` +} + type NostrConfiguration struct { PrivateKey string `yaml:"private_key"` } diff --git a/internal/dca/dca.go b/internal/dca/dca.go new file mode 100644 index 00000000..2b53b7bf --- /dev/null +++ b/internal/dca/dca.go @@ -0,0 +1,34 @@ +package dca + +import ( + "net/http" + "time" + + "github.com/LightningTipBot/LightningTipBot/internal" + log "github.com/sirupsen/logrus" +) + +// NotifyDeposit checks whether the given recipient username matches the configured +// DCA wallet username and, if so, asks the DCA backend to reset its retry counts. +func NotifyDeposit(toUsername string) { + if internal.Configuration.DCA.WalletUsername == "" || toUsername != internal.Configuration.DCA.WalletUsername { + return + } + + url := internal.Configuration.DCA.ApiUrl + "/transaction/reset-retry-counts" + req, err := http.NewRequest(http.MethodPost, url, nil) + if err != nil { + log.Errorf("[DCA] Error creating reset-retry-counts request: %s", err.Error()) + return + } + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Do(req) + if err != nil { + log.Errorf("[DCA] Error calling reset-retry-counts: %s", err.Error()) + return + } + defer resp.Body.Close() + log.Infof("[DCA] reset-retry-counts called for %s, status: %s", toUsername, resp.Status) +} diff --git a/internal/lnbits/webhook/webhook.go b/internal/lnbits/webhook/webhook.go index 53e81240..4b457ad3 100644 --- a/internal/lnbits/webhook/webhook.go +++ b/internal/lnbits/webhook/webhook.go @@ -6,6 +6,7 @@ import ( "time" "github.com/LightningTipBot/LightningTipBot/internal" + "github.com/LightningTipBot/LightningTipBot/internal/dca" "github.com/LightningTipBot/LightningTipBot/internal/lnbits" "github.com/LightningTipBot/LightningTipBot/internal/telegram" "github.com/LightningTipBot/LightningTipBot/internal/utils" @@ -100,6 +101,8 @@ func (w *Server) receive(writer http.ResponseWriter, request *http.Request) { } log.Infoln(fmt.Sprintf("[⚡️ WebHook] User %s (%d) received invoice of %d sat.", telegram.GetUserStr(user.Telegram), user.Telegram.ID, webhookEvent.Amount/1000)) + go dca.NotifyDeposit(telegram.GetUserStr(user.Telegram)) + writer.WriteHeader(200) // trigger invoice events diff --git a/internal/telegram/transaction.go b/internal/telegram/transaction.go index a5a1af1e..022a0548 100644 --- a/internal/telegram/transaction.go +++ b/internal/telegram/transaction.go @@ -6,6 +6,7 @@ import ( log "github.com/sirupsen/logrus" + "github.com/LightningTipBot/LightningTipBot/internal/dca" "github.com/LightningTipBot/LightningTipBot/internal/lnbits" tb "gopkg.in/lightningtipbot/telebot.v3" ) @@ -73,6 +74,7 @@ func (t *Transaction) Send() (success bool, err error) { success, err = t.SendTransaction(t.Bot, t.From, t.To, t.Amount, t.Memo) if success { t.Success = success + go dca.NotifyDeposit(t.ToUser) } // save transaction to db From d5ea345b950b6124dc298d1b04c1b38cbcdd5103 Mon Sep 17 00:00:00 2001 From: helloscoopa Date: Fri, 12 Jun 2026 20:12:23 +0530 Subject: [PATCH 2/3] fix: trim prefix from wallet username in NotifyDeposit function --- internal/dca/dca.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/dca/dca.go b/internal/dca/dca.go index 2b53b7bf..9b13d4e3 100644 --- a/internal/dca/dca.go +++ b/internal/dca/dca.go @@ -2,6 +2,7 @@ package dca import ( "net/http" + "strings" "time" "github.com/LightningTipBot/LightningTipBot/internal" @@ -11,7 +12,8 @@ import ( // NotifyDeposit checks whether the given recipient username matches the configured // DCA wallet username and, if so, asks the DCA backend to reset its retry counts. func NotifyDeposit(toUsername string) { - if internal.Configuration.DCA.WalletUsername == "" || toUsername != internal.Configuration.DCA.WalletUsername { + wallet := strings.TrimPrefix(internal.Configuration.DCA.WalletUsername, "@") + if wallet == "" || strings.TrimPrefix(toUsername, "@") != wallet { return } From f3abfd6d44dedc4854f3687d5739c22e6654d6a1 Mon Sep 17 00:00:00 2001 From: helloscoopa Date: Fri, 12 Jun 2026 20:13:52 +0530 Subject: [PATCH 3/3] fix: ensure API URL is configured before calling reset-retry-counts --- internal/dca/dca.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/dca/dca.go b/internal/dca/dca.go index 9b13d4e3..88e8e840 100644 --- a/internal/dca/dca.go +++ b/internal/dca/dca.go @@ -17,7 +17,13 @@ func NotifyDeposit(toUsername string) { return } - url := internal.Configuration.DCA.ApiUrl + "/transaction/reset-retry-counts" + apiUrl := strings.TrimSuffix(internal.Configuration.DCA.ApiUrl, "/") + if apiUrl == "" { + log.Errorln("[DCA] dca.api_url is not configured, skipping reset-retry-counts call") + return + } + + url := apiUrl + "/transaction/reset-retry-counts" req, err := http.NewRequest(http.MethodPost, url, nil) if err != nil { log.Errorf("[DCA] Error creating reset-retry-counts request: %s", err.Error())