From ca933f843c8801674988a87d00b748add725d9a0 Mon Sep 17 00:00:00 2001 From: Slyghtning Date: Tue, 4 Jul 2023 18:47:44 +0200 Subject: [PATCH] loopd: xpub support for loop out --- loopd/swapclient_server.go | 95 ++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 15 deletions(-) diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index 2a5baef..dd826cc 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -83,10 +83,10 @@ type swapClientServer struct { mainCtx context.Context } -// LoopOut initiates an loop out swap with the given parameters. The call -// returns after the swap has been set up with the swap server. From that point -// onwards, progress can be tracked via the LoopOutStatus stream that is -// returned from Monitor(). +// LoopOut initiates a loop out swap with the given parameters. The call returns +// after the swap has been set up with the swap server. From that point onwards, +// progress can be tracked via the LoopOutStatus stream that is returned from +// Monitor(). func (s *swapClientServer) LoopOut(ctx context.Context, in *clientrpc.LoopOutRequest) ( *clientrpc.SwapResponse, error) { @@ -94,9 +94,49 @@ func (s *swapClientServer) LoopOut(ctx context.Context, log.Infof("Loop out request received") var sweepAddr btcutil.Address - if in.Dest == "" { + var err error + //nolint:lll + switch { + case in.Dest != "" && in.Account != "": + return nil, fmt.Errorf("destination address and external " + + "account address cannot be set at the same time") + + case in.Dest != "": + // Decode the client provided destination address for the loop + // out sweep. + sweepAddr, err = btcutil.DecodeAddress( + in.Dest, s.lnd.ChainParams, + ) + if err != nil { + return nil, fmt.Errorf("decode address: %v", err) + } + + case in.Account != "" && in.AccountAddrType == clientrpc.AddressType_ADDRESS_TYPE_UNKNOWN: + return nil, liquidity.ErrAccountAndAddrType + + case in.Account != "": + // Derive a new receiving address from the stated account. + addrType, err := toWalletAddrType(in.AccountAddrType) + if err != nil { + return nil, err + } + + // Check if account with address type exists. + if !s.accountExists(ctx, in.Account, addrType) { + return nil, fmt.Errorf("the provided account does " + + "not exist") + } + + sweepAddr, err = s.lnd.WalletKit.NextAddr( + ctx, in.Account, addrType, false, + ) + if err != nil { + return nil, fmt.Errorf("NextAddr from account error: "+ + "%v", err) + } + + default: // Generate sweep address if none specified. - var err error sweepAddr, err = s.lnd.WalletKit.NextAddr( context.Background(), "", walletrpc.AddressType_WITNESS_PUBKEY_HASH, false, @@ -104,14 +144,6 @@ func (s *swapClientServer) LoopOut(ctx context.Context, if err != nil { return nil, fmt.Errorf("NextAddr error: %v", err) } - } else { - var err error - sweepAddr, err = btcutil.DecodeAddress( - in.Dest, s.lnd.ChainParams, - ) - if err != nil { - return nil, fmt.Errorf("decode address: %v", err) - } } sweepConfTarget, err := validateLoopOutRequest( @@ -174,6 +206,38 @@ func (s *swapClientServer) LoopOut(ctx context.Context, return resp, nil } +// accountExists returns true if account under the address type exists in the +// backing lnd instance and false otherwise. +func (s *swapClientServer) accountExists(ctx context.Context, account string, + addrType walletrpc.AddressType) bool { + + accounts, err := s.lnd.WalletKit.ListAccounts(ctx, account, addrType) + if err != nil { + return false + } + + for _, a := range accounts { + if a.Name == account { + return true + } + } + + return false +} + +func toWalletAddrType(addrType clientrpc.AddressType) (walletrpc.AddressType, + error) { + + switch addrType { + case clientrpc.AddressType_TAPROOT_PUBKEY: + return walletrpc.AddressType_TAPROOT_PUBKEY, nil + + default: + return walletrpc.AddressType_UNKNOWN, + fmt.Errorf("unknown address type") + } +} + func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) ( *clientrpc.SwapStatus, error) { @@ -1072,7 +1136,8 @@ func validateLoopOutRequest(ctx context.Context, lnd lndclient.LightningClient, // Check that the provided destination address is a supported // address format. switch sweepAddr.(type) { - case *btcutil.AddressWitnessScriptHash, + case *btcutil.AddressTaproot, + *btcutil.AddressWitnessScriptHash, *btcutil.AddressWitnessPubKeyHash, *btcutil.AddressScriptHash, *btcutil.AddressPubKeyHash: