Skip to content

Commit

Permalink
Add feature to do swaps to an address instead of a wallet (#57)
Browse files Browse the repository at this point in the history
* feat: new nodeguard proto and compilation

* feat: add logic to handle both address and wallet reverse swaps

* fix(liquidator_test.go): change walletId and address variables from pointers to values to improve code readability and semantics
  • Loading branch information
markettes authored Nov 20, 2023
1 parent eb2bea2 commit 363528a
Show file tree
Hide file tree
Showing 7 changed files with 4,123 additions and 161 deletions.
6 changes: 4 additions & 2 deletions cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ func TestBigCache_SetGetLiquidityRules(t *testing.T) {
x := nodeguard.LiquidityRule{
ChannelId: 1,
NodePubkey: "",
WalletId: 0,
SwapWalletId: 0,
ReverseSwapWalletId: nil,
MinimumLocalBalance: 0,
MinimumRemoteBalance: 0,
}

y := nodeguard.LiquidityRule{
ChannelId: 2,
NodePubkey: "",
WalletId: 0,
SwapWalletId: 0,
ReverseSwapWalletId: nil,
MinimumLocalBalance: 0,
MinimumRemoteBalance: 0,
}
Expand Down
32 changes: 20 additions & 12 deletions liquidator.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,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),
Expand All @@ -585,9 +585,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
Expand Down Expand Up @@ -636,22 +636,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)
Expand Down
51 changes: 38 additions & 13 deletions liquidator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ 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 = 1
var address string = "bcrt1q6zszlnxhlq0lsmfc42nkwgqedy9kvmvmxhkvme"

//Active channel
channelActive := &lnrpc.Channel{
Active: true,
Expand Down Expand Up @@ -136,12 +140,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",
Expand All @@ -155,7 +174,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",
Expand All @@ -169,7 +188,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",
Expand All @@ -187,7 +206,7 @@ func Test_manageChannelLiquidity(t *testing.T) {
{
ChannelId: 123,
NodePubkey: "03485d8dcdd149c87553eeb80586eb2bece874d412e9f117304446ce189955d375",
WalletId: 1,
SwapWalletId: 1,
MinimumLocalBalance: 20,
MinimumRemoteBalance: 80,
RebalanceTarget: 60,
Expand All @@ -206,7 +225,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",
Expand All @@ -220,7 +239,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",
Expand All @@ -234,7 +253,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",
Expand Down Expand Up @@ -384,16 +403,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,
},
},
}
Expand Down
Loading

0 comments on commit 363528a

Please sign in to comment.