From a746dfd6647f6d85f34457a13198ca4ccf7d2010 Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Fri, 12 Nov 2021 17:35:05 +0100 Subject: [PATCH] get available local balance --- .../controller/LegacyControllerIT.java | 12 ++++ .../controller/LegacyController.java | 11 +++- .../lndmanagej/service/BalanceService.java | 34 ++++++++++ .../controller/LegacyControllerTest.java | 17 ++++- .../service/BalanceServiceTest.java | 62 +++++++++++++++++++ .../service/ChannelServiceTest.java | 5 +- .../cotto/lndmanagej/grpc/GrpcChannels.java | 14 ++++- .../lndmanagej/grpc/GrpcChannelsTest.java | 23 +++++-- .../cotto/lndmanagej/model/LocalChannel.java | 14 ++++- .../lndmanagej/model/LocalChannelTest.java | 15 ++++- .../model/LocalChannelFixtures.java | 15 +++-- 11 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 application/src/main/java/de/cotto/lndmanagej/service/BalanceService.java create mode 100644 application/src/test/java/de/cotto/lndmanagej/service/BalanceServiceTest.java diff --git a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java index 37eb93cb..cc42a047 100644 --- a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java +++ b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java @@ -1,6 +1,7 @@ package de.cotto.lndmanagej.controller; import de.cotto.lndmanagej.model.Coins; +import de.cotto.lndmanagej.service.BalanceService; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.FeeService; import de.cotto.lndmanagej.service.NodeService; @@ -51,6 +52,9 @@ class LegacyControllerIT { @MockBean private FeeService feeService; + @MockBean + private BalanceService balanceService; + @Test void getAlias() throws Exception { when(nodeService.getAlias(PUBKEY)).thenReturn(ALIAS); @@ -136,4 +140,12 @@ class LegacyControllerIT { mockMvc.perform(get(CHANNEL_BASE + "/outgoing-base-fee")) .andExpect(content().string(String.valueOf(BASE_FEE.milliSatoshis()))); } + + @Test + void getAvailableLocalBalance() throws Exception { + Coins availableBalance = Coins.ofSatoshis(999); + when(balanceService.getAvailableLocalBalance(CHANNEL_ID)).thenReturn(availableBalance); + mockMvc.perform(get(CHANNEL_BASE + "/available-local-balance")) + .andExpect(content().string(String.valueOf(availableBalance.satoshis()))); + } } \ No newline at end of file diff --git a/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java b/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java index b714ede5..bb101c99 100644 --- a/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java +++ b/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java @@ -4,6 +4,7 @@ import de.cotto.lndmanagej.model.Channel; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.LocalChannel; import de.cotto.lndmanagej.model.Pubkey; +import de.cotto.lndmanagej.service.BalanceService; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.FeeService; import de.cotto.lndmanagej.service.NodeService; @@ -25,17 +26,20 @@ public class LegacyController { private final ChannelService channelService; private final OwnNodeService ownNodeService; private final FeeService feeService; + private final BalanceService balanceService; public LegacyController( NodeService nodeService, ChannelService channelService, OwnNodeService ownNodeService, - FeeService feeService + FeeService feeService, + BalanceService balanceService ) { this.nodeService = nodeService; this.channelService = channelService; this.ownNodeService = ownNodeService; this.feeService = feeService; + this.balanceService = balanceService; } @GetMapping("/node/{pubkey}/alias") @@ -115,6 +119,11 @@ public class LegacyController { return feeService.getOutgoingBaseFee(channelId).milliSatoshis(); } + @GetMapping("/channel/{channelId}/available-local-balance") + public long getAvailableLocalBalance(ChannelId channelId) { + return balanceService.getAvailableLocalBalance(channelId).satoshis(); + } + private Stream getOpenChannelIdsSorted() { return channelService.getOpenChannels().stream() .map(Channel::getId) diff --git a/application/src/main/java/de/cotto/lndmanagej/service/BalanceService.java b/application/src/main/java/de/cotto/lndmanagej/service/BalanceService.java new file mode 100644 index 00000000..5f48cff9 --- /dev/null +++ b/application/src/main/java/de/cotto/lndmanagej/service/BalanceService.java @@ -0,0 +1,34 @@ +package de.cotto.lndmanagej.service; + +import de.cotto.lndmanagej.grpc.GrpcChannels; +import de.cotto.lndmanagej.model.ChannelId; +import de.cotto.lndmanagej.model.Coins; +import de.cotto.lndmanagej.model.LocalChannel; +import org.springframework.stereotype.Component; + +@Component +public class BalanceService { + private final GrpcChannels grpcChannels; + + public BalanceService(GrpcChannels grpcChannels) { + this.grpcChannels = grpcChannels; + } + + public Coins getLocalBalance(ChannelId channelId) { + return grpcChannels.getChannel(channelId).map(LocalChannel::getLocalBalance).orElse(Coins.NONE); + } + + public Coins getLocalReserve(ChannelId channelId) { + return grpcChannels.getChannel(channelId).map(LocalChannel::getLocalReserve).orElse(Coins.NONE); + } + + public Coins getAvailableLocalBalance(ChannelId channelId) { + Coins available = grpcChannels.getChannel(channelId) + .map(c -> c.getLocalBalance().subtract(c.getLocalReserve())) + .orElse(Coins.NONE); + if (available.isNegative()) { + return Coins.NONE; + } + return available; + } +} diff --git a/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java b/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java index 93f7484d..1ed54429 100644 --- a/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java @@ -1,8 +1,10 @@ package de.cotto.lndmanagej.controller; +import de.cotto.lndmanagej.model.Channel; import de.cotto.lndmanagej.model.ChannelFixtures; import de.cotto.lndmanagej.model.Coins; import de.cotto.lndmanagej.model.LocalChannel; +import de.cotto.lndmanagej.service.BalanceService; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.FeeService; import de.cotto.lndmanagej.service.NodeService; @@ -53,6 +55,9 @@ class LegacyControllerTest { @Mock private FeeService feeService; + @Mock + private BalanceService balanceService; + @Test void getAlias() { when(nodeService.getAlias(PUBKEY)).thenReturn(ALIAS); @@ -131,14 +136,16 @@ class LegacyControllerTest { @Test void getPeerPubkeys() { - LocalChannel channel2 = new LocalChannel(ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2), PUBKEY); + Channel channel = ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2); + LocalChannel channel2 = new LocalChannel(channel, PUBKEY, Coins.NONE, Coins.NONE); when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_CHANNEL, channel2)); assertThat(legacyController.getPeerPubkeys()).isEqualTo(PUBKEY_2 + "\n" + PUBKEY_3); } @Test void getPeerPubkeys_sorted() { - LocalChannel channel2 = new LocalChannel(ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2), PUBKEY); + Channel channel = ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2); + LocalChannel channel2 = new LocalChannel(channel, PUBKEY, Coins.NONE, Coins.NONE); when(channelService.getOpenChannels()).thenReturn(Set.of(channel2, LOCAL_CHANNEL)); assertThat(legacyController.getPeerPubkeys()).isEqualTo(PUBKEY_2 + "\n" + PUBKEY_3); } @@ -172,4 +179,10 @@ class LegacyControllerTest { when(feeService.getOutgoingBaseFee(CHANNEL_ID)).thenReturn(Coins.ofMilliSatoshis(10L)); assertThat(legacyController.getOutgoingBaseFee(CHANNEL_ID)).isEqualTo(10); } + + @Test + void getAvailableLocalBalance() { + when(balanceService.getAvailableLocalBalance(CHANNEL_ID)).thenReturn(Coins.ofSatoshis(123L)); + assertThat(legacyController.getAvailableLocalBalance(CHANNEL_ID)).isEqualTo(123); + } } \ No newline at end of file diff --git a/application/src/test/java/de/cotto/lndmanagej/service/BalanceServiceTest.java b/application/src/test/java/de/cotto/lndmanagej/service/BalanceServiceTest.java new file mode 100644 index 00000000..b5c237d2 --- /dev/null +++ b/application/src/test/java/de/cotto/lndmanagej/service/BalanceServiceTest.java @@ -0,0 +1,62 @@ +package de.cotto.lndmanagej.service; + +import de.cotto.lndmanagej.grpc.GrpcChannels; +import de.cotto.lndmanagej.model.Coins; +import de.cotto.lndmanagej.model.LocalChannel; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Optional; + +import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; +import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_BALANCE; +import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL; +import static de.cotto.lndmanagej.model.LocalChannelFixtures.RESERVE_LOCAL; +import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class BalanceServiceTest { + @InjectMocks + private BalanceService balanceService; + + @Mock + private GrpcChannels grpcChannels; + + @Test + void getLocalBalance() { + when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_CHANNEL)); + assertThat(balanceService.getLocalBalance(CHANNEL_ID)).isEqualTo(LOCAL_BALANCE); + } + + @Test + void getLocalBalance_no_channel() { + when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.empty()); + assertThat(balanceService.getLocalBalance(CHANNEL_ID)).isEqualTo(Coins.NONE); + } + + @Test + void getLocalReserve() { + when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_CHANNEL)); + assertThat(balanceService.getLocalReserve(CHANNEL_ID)).isEqualTo(RESERVE_LOCAL); + } + + @Test + void getAvailableLocalBalance() { + when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_CHANNEL)); + assertThat(balanceService.getAvailableLocalBalance(CHANNEL_ID)) + .isEqualTo(LOCAL_BALANCE.subtract(RESERVE_LOCAL)); + } + + @Test + void getAvailableLocalBalance_negative() { + LocalChannel localChannel = new LocalChannel(CHANNEL, PUBKEY, Coins.ofSatoshis(99), Coins.ofSatoshis(100)); + when(grpcChannels.getChannel(CHANNEL_ID)).thenReturn(Optional.of(localChannel)); + assertThat(balanceService.getAvailableLocalBalance(CHANNEL_ID)).isEqualTo(Coins.NONE); + } +} \ No newline at end of file diff --git a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java index ac4d405d..5493239f 100644 --- a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java @@ -1,7 +1,9 @@ package de.cotto.lndmanagej.service; import de.cotto.lndmanagej.grpc.GrpcChannels; +import de.cotto.lndmanagej.model.Channel; import de.cotto.lndmanagej.model.ChannelFixtures; +import de.cotto.lndmanagej.model.Coins; import de.cotto.lndmanagej.model.LocalChannel; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -37,7 +39,8 @@ class ChannelServiceTest { @Test void getOpenChannelsWith_ignores_channel_to_other_node() { - LocalChannel localChannel2 = new LocalChannel(ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2), PUBKEY); + Channel channel = ChannelFixtures.create(PUBKEY, PUBKEY_3, CHANNEL_ID_2); + LocalChannel localChannel2 = new LocalChannel(channel, PUBKEY, Coins.NONE, Coins.NONE); when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_CHANNEL, localChannel2, LOCAL_CHANNEL_3)); assertThat(channelService.getOpenChannelsWith(PUBKEY_2)) .containsExactlyInAnyOrder(LOCAL_CHANNEL, LOCAL_CHANNEL_3); diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java index d813b3c4..6fbfcc4d 100644 --- a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcChannels.java @@ -7,6 +7,7 @@ import de.cotto.lndmanagej.model.LocalChannel; import de.cotto.lndmanagej.model.Pubkey; import org.springframework.stereotype.Component; +import java.util.Optional; import java.util.Set; import static java.util.stream.Collectors.toSet; @@ -31,6 +32,15 @@ public class GrpcChannels { .collect(toSet()); } + public Optional getChannel(ChannelId channelId) { + Pubkey ownPubkey = grpcGetInfo.getPubkey(); + long expectedChannelId = channelId.shortChannelId(); + return grpcService.getChannels().stream() + .filter(c -> c.getChanId() == expectedChannelId) + .map(lndChannel -> toChannel(lndChannel, ownPubkey)) + .findFirst(); + } + private LocalChannel toChannel(lnrpc.Channel lndChannel, Pubkey ownPubkey) { Channel channel = Channel.builder() .withChannelId(ChannelId.fromShortChannelId(lndChannel.getChanId())) @@ -38,7 +48,9 @@ public class GrpcChannels { .withNode1(ownPubkey) .withNode2(Pubkey.create(lndChannel.getRemotePubkey())) .build(); - return new LocalChannel(channel, ownPubkey); + Coins localBalance = Coins.ofSatoshis(lndChannel.getLocalBalance()); + Coins localReserve = Coins.ofSatoshis(lndChannel.getLocalConstraints().getChanReserveSat()); + return new LocalChannel(channel, ownPubkey, localBalance, localReserve); } } diff --git a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java index ff24980a..0064497b 100644 --- a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java +++ b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcChannelsTest.java @@ -1,5 +1,6 @@ package de.cotto.lndmanagej.grpc; +import de.cotto.lndmanagej.model.ChannelId; import lnrpc.Channel; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -12,6 +13,7 @@ import java.util.List; import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_2; import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL; import static de.cotto.lndmanagej.model.NodeFixtures.NODE_2; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; @@ -35,19 +37,30 @@ class GrpcChannelsTest { } @Test - void no_channels() { + void getChannels_no_channels() { assertThat(grpcChannels.getChannels()).isEmpty(); } @Test - void one_channel() { - when(grpcService.getChannels()).thenReturn(List.of(channel())); + void getChannels_one_channel() { + when(grpcService.getChannels()).thenReturn(List.of(channel(CHANNEL_ID))); assertThat(grpcChannels.getChannels()).containsExactly(LOCAL_CHANNEL); } - private Channel channel() { + @Test + void getChannel() { + when(grpcService.getChannels()).thenReturn(List.of(channel(CHANNEL_ID_2), channel(CHANNEL_ID))); + assertThat(grpcChannels.getChannel(CHANNEL_ID)).contains(LOCAL_CHANNEL); + } + + @Test + void getChannel_empty() { + assertThat(grpcChannels.getChannel(CHANNEL_ID)).isEmpty(); + } + + private Channel channel(ChannelId channelId) { return Channel.newBuilder() - .setChanId(CHANNEL_ID.shortChannelId()) + .setChanId(channelId.shortChannelId()) .setCapacity(CAPACITY.satoshis()) .setRemotePubkey(NODE_2.pubkey().toString()) .build(); diff --git a/model/src/main/java/de/cotto/lndmanagej/model/LocalChannel.java b/model/src/main/java/de/cotto/lndmanagej/model/LocalChannel.java index a10f2b18..18d7e0e4 100644 --- a/model/src/main/java/de/cotto/lndmanagej/model/LocalChannel.java +++ b/model/src/main/java/de/cotto/lndmanagej/model/LocalChannel.java @@ -4,9 +4,13 @@ import java.util.Set; public class LocalChannel extends Channel { private final Pubkey remotePubkey; + private final Coins localBalance; + private final Coins localReserve; - public LocalChannel(Channel channel, Pubkey ownPubkey) { + public LocalChannel(Channel channel, Pubkey ownPubkey, Coins localBalance, Coins localReserve) { super(channel.getId(), channel.getCapacity(), channel.getPubkeys()); + this.localBalance = localBalance; + this.localReserve = localReserve; Set pubkeys = channel.getPubkeys(); remotePubkey = pubkeys.stream() .filter(pubkey -> !ownPubkey.equals(pubkey)) @@ -20,4 +24,12 @@ public class LocalChannel extends Channel { public Pubkey getRemotePubkey() { return remotePubkey; } + + public Coins getLocalBalance() { + return localBalance; + } + + public Coins getLocalReserve() { + return localReserve; + } } diff --git a/model/src/test/java/de/cotto/lndmanagej/model/LocalChannelTest.java b/model/src/test/java/de/cotto/lndmanagej/model/LocalChannelTest.java index 20327152..f1b2fc42 100644 --- a/model/src/test/java/de/cotto/lndmanagej/model/LocalChannelTest.java +++ b/model/src/test/java/de/cotto/lndmanagej/model/LocalChannelTest.java @@ -4,6 +4,8 @@ import org.junit.jupiter.api.Test; import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_2; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; +import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_BALANCE; +import static de.cotto.lndmanagej.model.LocalChannelFixtures.LOCAL_CHANNEL; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_3; @@ -13,20 +15,27 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class LocalChannelTest { @Test void getRemotePubkey() { - LocalChannel localChannel = new LocalChannel(ChannelFixtures.create(PUBKEY_2, PUBKEY, CHANNEL_ID), PUBKEY); + Channel channel = ChannelFixtures.create(PUBKEY_2, PUBKEY, CHANNEL_ID); + LocalChannel localChannel = new LocalChannel(channel, PUBKEY, Coins.NONE, Coins.NONE); assertThat(localChannel.getRemotePubkey()).isEqualTo(PUBKEY_2); } @Test void getRemotePubkey_swapped() { - LocalChannel localChannel = new LocalChannel(ChannelFixtures.create(PUBKEY_3, PUBKEY_2, CHANNEL_ID), PUBKEY_3); + Channel channel = ChannelFixtures.create(PUBKEY_3, PUBKEY_2, CHANNEL_ID); + LocalChannel localChannel = new LocalChannel(channel, PUBKEY_3, Coins.NONE, Coins.NONE); assertThat(localChannel.getRemotePubkey()).isEqualTo(PUBKEY_2); } @Test void ownPubkey_not_in_pubkey_set() { assertThatIllegalArgumentException() - .isThrownBy(() -> new LocalChannel(CHANNEL_2, PUBKEY_3)) + .isThrownBy(() -> new LocalChannel(CHANNEL_2, PUBKEY_3, Coins.NONE, Coins.NONE)) .withMessage("Channel must have given pubkey as peer"); } + + @Test + void getLocalBalance() { + assertThat(LOCAL_CHANNEL.getLocalBalance()).isEqualTo(LOCAL_BALANCE); + } } \ No newline at end of file diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/LocalChannelFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/LocalChannelFixtures.java index 9e907d54..b47f41ce 100644 --- a/model/src/testFixtures/java/de/cotto/lndmanagej/model/LocalChannelFixtures.java +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/LocalChannelFixtures.java @@ -7,8 +7,15 @@ import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_TO_NODE_3; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; public class LocalChannelFixtures { - public static final LocalChannel LOCAL_CHANNEL = new LocalChannel(CHANNEL, PUBKEY); - public static final LocalChannel LOCAL_CHANNEL_2 = new LocalChannel(CHANNEL_2, PUBKEY); - public static final LocalChannel LOCAL_CHANNEL_3 = new LocalChannel(CHANNEL_3, PUBKEY); - public static final LocalChannel LOCAL_CHANNEL_TO_NODE_3 = new LocalChannel(CHANNEL_TO_NODE_3, PUBKEY); + public static final Coins LOCAL_BALANCE = Coins.ofSatoshis(1_000); + public static final Coins RESERVE_LOCAL = Coins.ofSatoshis(100); + + public static final LocalChannel LOCAL_CHANNEL = + new LocalChannel(CHANNEL, PUBKEY, LOCAL_BALANCE, RESERVE_LOCAL); + public static final LocalChannel LOCAL_CHANNEL_2 = + new LocalChannel(CHANNEL_2, PUBKEY, LOCAL_BALANCE, RESERVE_LOCAL); + public static final LocalChannel LOCAL_CHANNEL_3 = + new LocalChannel(CHANNEL_3, PUBKEY, LOCAL_BALANCE, RESERVE_LOCAL); + public static final LocalChannel LOCAL_CHANNEL_TO_NODE_3 = + new LocalChannel(CHANNEL_TO_NODE_3, PUBKEY, LOCAL_BALANCE, RESERVE_LOCAL); }