From 2bcf675da40fe1e9225cb949a1d2bb966ca3bccd Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 13 Nov 2023 23:53:31 +0100 Subject: [PATCH] feat: add logic to handle both address and wallet reverse swaps --- cache/cache_test.go | 6 +++-- liquidator.go | 32 +++++++++++++++++---------- liquidator_test.go | 53 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 64 insertions(+), 27 deletions(-) diff --git a/cache/cache_test.go b/cache/cache_test.go index 4cf54b2..5d8f77f 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -49,7 +49,8 @@ func TestBigCache_SetGetLiquidityRules(t *testing.T) { x := nodeguard.LiquidityRule{ ChannelId: 1, NodePubkey: "", - WalletId: 0, + SwapWalletId: 0, + ReverseSwapWalletId: nil, MinimumLocalBalance: 0, MinimumRemoteBalance: 0, } @@ -57,7 +58,8 @@ func TestBigCache_SetGetLiquidityRules(t *testing.T) { y := nodeguard.LiquidityRule{ ChannelId: 2, NodePubkey: "", - WalletId: 0, + SwapWalletId: 0, + ReverseSwapWalletId: nil, MinimumLocalBalance: 0, MinimumRemoteBalance: 0, } diff --git a/liquidator.go b/liquidator.go index 26aac74..1693ea9 100644 --- a/liquidator.go +++ b/liquidator.go @@ -567,7 +567,7 @@ func performSwap(info ManageChannelLiquidityInfo, channel *lnrpc.Channel, swapAm //Request nodeguard to send the swap amount to the invoice address withdrawalRequest := nodeguard.RequestWithdrawalRequest{ - WalletId: rule.WalletId, + WalletId: rule.SwapWalletId, Address: resp.InvoiceBTCAddress, Amount: swapAmount, Description: fmt.Sprintf("Swap %v", resp.SwapId), @@ -584,9 +584,9 @@ func performSwap(info ManageChannelLiquidityInfo, channel *lnrpc.Channel, swapAm //Log the swap request if withdrawalResponse.IsHotWallet { - log.WithField("span", span).Infof("Swap request sent to nodeguard hot wallet with id: %d for swap id: %v for node: %v", rule.GetWalletId(), resp.SwapId, info.nodeInfo.GetIdentityPubkey()) + log.WithField("span", span).Infof("Swap request sent to nodeguard hot wallet with id: %d for swap id: %v for node: %v", rule.GetSwapWalletId(), resp.SwapId, info.nodeInfo.GetIdentityPubkey()) } else { - log.WithField("span", span).Infof("Swap request sent to nodeguard cold wallet with id: %d for swap id: %v for node: %v ", rule.GetWalletId(), resp.SwapId, info.nodeInfo.GetIdentityPubkey()) + log.WithField("span", span).Infof("Swap request sent to nodeguard cold wallet with id: %d for swap id: %v for node: %v ", rule.GetSwapWalletId(), resp.SwapId, info.nodeInfo.GetIdentityPubkey()) } //Monitor the swap @@ -635,22 +635,30 @@ func performSwap(info ManageChannelLiquidityInfo, channel *lnrpc.Channel, swapAm } func performReverseSwap(info ManageChannelLiquidityInfo, channel *lnrpc.Channel, swapAmount int64, rule nodeguard.LiquidityRule, span trace.Span, loopdCtx context.Context, retryCounter int, swapAmountTarget int64) error { - //Request nodeguard a new destination address for the reverse swap - walletRequest := &nodeguard.GetNewWalletAddressRequest{ - WalletId: rule.WalletId, - } + // Check if it is a reverse swap to a wallet or to an address + var address string + if rule.IsReverseSwapWalletRule { + //Request nodeguard a new destination address for the reverse swap + walletRequest := &nodeguard.GetNewWalletAddressRequest{ + WalletId: *rule.ReverseSwapWalletId, + } - addrResponse, err := info.nodeguardClient.GetNewWalletAddress(info.ctx, walletRequest) - if err != nil || addrResponse.GetAddress() == "" { - log.WithField("span", span).Errorf("error requesting nodeguard a new wallet address: %v on node: %v", err, info.nodeInfo.GetIdentityPubkey()) - return err + addrResponse, err := info.nodeguardClient.GetNewWalletAddress(info.ctx, walletRequest) + if err != nil || addrResponse.GetAddress() == "" { + log.WithField("span", span).Errorf("error requesting nodeguard a new wallet address: %v on node: %v", err, info.nodeInfo.GetIdentityPubkey()) + return err + } + + address = addrResponse.Address + } else { + address = *rule.ReverseSwapAddress } //Perform the swap swapRequest := provider.ReverseSubmarineSwapRequest{ SatsAmount: swapAmount, ChannelSet: []uint64{channel.GetChanId()}, - ReceiverBTCAddress: addrResponse.Address, + ReceiverBTCAddress: address, } log.WithField("span", span).Infof("requesting reverse submarine swap with amount: %d sats to BTC Address %s", swapRequest.SatsAmount, swapRequest.ReceiverBTCAddress) diff --git a/liquidator_test.go b/liquidator_test.go index 4a97444..2cd3a0a 100644 --- a/liquidator_test.go +++ b/liquidator_test.go @@ -109,6 +109,12 @@ func Test_manageChannelLiquidity(t *testing.T) { //Mock provider invalid reverse swap loop error mockProviderInvalidLoopError := createMockProviderInvalidSwapLoopError(mockCtrl) + // Wallet and address for reverse swaps + var walletId *int32 = new(int32) + *walletId = 1 + var address *string = new(string) + *address = "bcrt1q6zszlnxhlq0lsmfc42nkwgqedy9kvmvmxhkvme" + //Active channel channelActive := &lnrpc.Channel{ Active: true, @@ -136,12 +142,27 @@ func Test_manageChannelLiquidity(t *testing.T) { args ManageChannelLiquidityInfo wantErr bool }{ + + { + name: "Manage channel liquidity test valid reverse swap", + args: ManageChannelLiquidityInfo{ + channel: channelActive, + channelBalanceRatio: 0.1, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", IsReverseSwapWalletRule: true, ReverseSwapWalletId: walletId, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, + nodeguardClient: mockNodeGuardClient, + loopProvider: mockProvider, + loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", + nodeInfo: nodeInfo, + ctx: context.TODO(), + }, + wantErr: false, + }, { name: "Manage channel liquidity test valid reverse swap", args: ManageChannelLiquidityInfo{ channel: channelActive, channelBalanceRatio: 0.1, - channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", WalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", IsReverseSwapWalletRule: false, ReverseSwapAddress: address, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, nodeguardClient: mockNodeGuardClient, loopProvider: mockProvider, loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", @@ -155,7 +176,7 @@ func Test_manageChannelLiquidity(t *testing.T) { args: ManageChannelLiquidityInfo{ channel: channelActive, channelBalanceRatio: 0.1, - channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", WalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 40}}, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", IsReverseSwapWalletRule: true, ReverseSwapWalletId: walletId, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 40}}, nodeguardClient: mockNodeGuardClient, loopProvider: mockProvider, loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", @@ -169,7 +190,7 @@ func Test_manageChannelLiquidity(t *testing.T) { args: ManageChannelLiquidityInfo{ channel: channelActive, channelBalanceRatio: 0.1, - channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", WalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 40}}, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", IsReverseSwapWalletRule: true, ReverseSwapWalletId: walletId, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 40}}, nodeguardClient: mockNodeGuardClient, loopProvider: mockProvider, loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", @@ -187,7 +208,7 @@ func Test_manageChannelLiquidity(t *testing.T) { { ChannelId: 123, NodePubkey: "03485d8dcdd149c87553eeb80586eb2bece874d412e9f117304446ce189955d375", - WalletId: 1, + SwapWalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60, @@ -206,7 +227,7 @@ func Test_manageChannelLiquidity(t *testing.T) { args: ManageChannelLiquidityInfo{ channel: channelActive, channelBalanceRatio: 0.1, - channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", WalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", IsReverseSwapWalletRule: true, ReverseSwapWalletId: walletId, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, nodeguardClient: mockNodeGuardClient, loopProvider: mockProviderInvalid, loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", @@ -220,7 +241,7 @@ func Test_manageChannelLiquidity(t *testing.T) { args: ManageChannelLiquidityInfo{ channel: channelActive, channelBalanceRatio: 0.9, - channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", WalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", SwapWalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, nodeguardClient: mockNodeGuardClient, loopProvider: mockProviderInvalid, loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", @@ -234,7 +255,7 @@ func Test_manageChannelLiquidity(t *testing.T) { args: ManageChannelLiquidityInfo{ channel: channelActive, channelBalanceRatio: 0.1, - channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", WalletId: 1, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, + channelRules: &[]nodeguard.LiquidityRule{{ChannelId: 123, NodePubkey: "", IsReverseSwapWalletRule: true, ReverseSwapWalletId: walletId, MinimumLocalBalance: 20, MinimumRemoteBalance: 80, RebalanceTarget: 60}}, nodeguardClient: mockNodeGuardClient, loopProvider: mockProviderInvalidLoopError, loopdMacaroon: "0201036c6e6402f801030a10dc64226b045d25f090b114baebcbf04c1201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a21b8cc8c071aa5104b706b751aede972f642537c05da31450fb4b02c6da776e", @@ -384,16 +405,22 @@ func Test_monitorChannel(t *testing.T) { }, }, nil).AnyTimes() + // Wallet id for reverse swaps + var walletId *int32 = new(int32) + *walletId = 1 + // Liquidity rules for the channel liquidityRules := map[uint64][]nodeguard.LiquidityRule{ channel.ChanId: { { - ChannelId: channel.ChanId, - NodePubkey: "", - WalletId: 1, - MinimumLocalBalance: 20, - MinimumRemoteBalance: 80, - RebalanceTarget: 50, + ChannelId: channel.ChanId, + NodePubkey: "", + SwapWalletId: 1, + IsReverseSwapWalletRule: true, + ReverseSwapWalletId: walletId, + MinimumLocalBalance: 20, + MinimumRemoteBalance: 80, + RebalanceTarget: 50, }, }, }