feat: encrypt xpub for auto swap outs (#1973)

* feat: encrypt xpub for auto swap out

* fix: include encryptionKey in the cache key (sha256)

* fix: make cache 2 level nested map

* chore: comment

* fix: missing import

* fix: use ValidateXpub

* fix: cleanup

* fix: cleanup

* fix: better name

* fix: cleanup

* fix: cleanup

* fix: cleanup

* fix: open dialog to ask password on autoswap xpub

* fix: reject extended private keys

* fix: fix amount comp

* chore: improve autoswap destination handling and form submission flow

* fix: clear cached xpub when enabling autoswaps

* fix: autoswap destination validation and xpub handling

* chore: add mutex for auto swap xpub

* chore: add copy icon for destination in auto swap info

---------

Co-authored-by: fmar <fmar@fmar.dev>
Co-authored-by: anon <anon@anon.com>
Co-authored-by: im-adithya <imadithyavardhan@gmail.com>
This commit is contained in:
frnandu 2026-03-25 16:58:16 +00:00 committed by GitHub
parent 06b21139bc
commit 354099cbff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 408 additions and 244 deletions

View file

@ -810,10 +810,18 @@ func (api *api) RefundSwap(refundSwapRequest *RefundSwapRequest) error {
}
func (api *api) GetAutoSwapConfig() (*GetAutoSwapConfigResponse, error) {
if api.svc.GetSwapsService() == nil {
return nil, errors.New("SwapsService not started")
}
swapOutBalanceThresholdStr, _ := api.cfg.Get(config.AutoSwapBalanceThresholdKey, "")
swapOutAmountStr, _ := api.cfg.Get(config.AutoSwapAmountKey, "")
swapOutDestination, _ := api.cfg.Get(config.AutoSwapDestinationKey, "")
if xpub := api.svc.GetSwapsService().GetDecryptedAutoSwapXpub(); xpub != "" {
swapOutDestination = xpub
}
swapOutEnabled := swapOutBalanceThresholdStr != "" && swapOutAmountStr != ""
var swapOutBalanceThreshold, swapOutAmount uint64
if swapOutEnabled {
@ -984,6 +992,30 @@ func (api *api) InitiateSwapIn(ctx context.Context, initiateSwapInRequest *Initi
}
func (api *api) EnableAutoSwapOut(ctx context.Context, enableAutoSwapsRequest *EnableAutoSwapRequest) error {
if api.svc.GetSwapsService() == nil {
return errors.New("SwapsService not started")
}
encryptionKey := ""
if enableAutoSwapsRequest.Destination != "" {
switch enableAutoSwapsRequest.DestinationType {
case "address":
if err := api.svc.GetSwapsService().ValidateAddress(enableAutoSwapsRequest.Destination); err != nil {
return err
}
case "xpub":
if !api.cfg.CheckUnlockPassword(enableAutoSwapsRequest.UnlockPassword) {
return errors.New("invalid unlock password")
}
if err := api.svc.GetSwapsService().ValidateXpub(enableAutoSwapsRequest.Destination); err != nil {
return err
}
encryptionKey = enableAutoSwapsRequest.UnlockPassword
default:
return errors.New("destination type must be address or xpub")
}
}
err := api.cfg.SetUpdate(config.AutoSwapBalanceThresholdKey, strconv.FormatUint(enableAutoSwapsRequest.BalanceThreshold, 10), "")
if err != nil {
logger.Logger.WithError(err).Error("Failed to save autoswap balance threshold to config")
@ -996,16 +1028,13 @@ func (api *api) EnableAutoSwapOut(ctx context.Context, enableAutoSwapsRequest *E
return err
}
err = api.cfg.SetUpdate(config.AutoSwapDestinationKey, enableAutoSwapsRequest.Destination, "")
err = api.cfg.SetUpdate(config.AutoSwapDestinationKey, enableAutoSwapsRequest.Destination, encryptionKey)
if err != nil {
logger.Logger.WithError(err).Error("Failed to save autoswap destination to config")
return err
}
if api.svc.GetSwapsService() == nil {
return errors.New("SwapsService not started")
}
return api.svc.GetSwapsService().EnableAutoSwapOut()
return api.svc.GetSwapsService().EnableAutoSwapOut(enableAutoSwapsRequest.UnlockPassword)
}
func (api *api) DisableAutoSwap() error {

View file

@ -168,6 +168,8 @@ type EnableAutoSwapRequest struct {
BalanceThreshold uint64 `json:"balanceThreshold"`
SwapAmount uint64 `json:"swapAmount"`
Destination string `json:"destination"`
DestinationType string `json:"destinationType"`
UnlockPassword string `json:"unlockPassword"`
}
type GetAutoSwapConfigResponse struct {