diff --git a/backend/src/main/java/de/cotto/lndmanagej/service/FeeService.java b/backend/src/main/java/de/cotto/lndmanagej/service/FeeService.java index cd3d1185..b7a738da 100644 --- a/backend/src/main/java/de/cotto/lndmanagej/service/FeeService.java +++ b/backend/src/main/java/de/cotto/lndmanagej/service/FeeService.java @@ -19,7 +19,9 @@ public class FeeService { getOutgoingFeeRate(channelId), getOutgoingBaseFee(channelId), getIncomingFeeRate(channelId), - getIncomingBaseFee(channelId) + getIncomingBaseFee(channelId), + isEnabledLocal(channelId), + isEnabledRemote(channelId) ); } @@ -38,4 +40,12 @@ public class FeeService { private Coins getIncomingBaseFee(ChannelId channelId) { return grpcFees.getIncomingBaseFee(channelId).orElseThrow(IllegalStateException::new); } + + private boolean isEnabledLocal(ChannelId channelId) { + return grpcFees.isEnabledLocal(channelId).orElseThrow(IllegalStateException::new); + } + + private boolean isEnabledRemote(ChannelId channelId) { + return grpcFees.isEnabledRemote(channelId).orElseThrow(IllegalStateException::new); + } } diff --git a/backend/src/test/java/de/cotto/lndmanagej/service/FeeServiceTest.java b/backend/src/test/java/de/cotto/lndmanagej/service/FeeServiceTest.java index f1a31f55..63264e65 100644 --- a/backend/src/test/java/de/cotto/lndmanagej/service/FeeServiceTest.java +++ b/backend/src/test/java/de/cotto/lndmanagej/service/FeeServiceTest.java @@ -30,16 +30,40 @@ class FeeServiceTest { 789, Coins.ofMilliSatoshis(111), 123, - Coins.ofMilliSatoshis(456) + Coins.ofMilliSatoshis(456), + true, + false ); when(grpcFees.getOutgoingFeeRate(CHANNEL_ID)).thenReturn(Optional.of(789L)); when(grpcFees.getOutgoingBaseFee(CHANNEL_ID)).thenReturn(Optional.of(Coins.ofMilliSatoshis(111))); when(grpcFees.getIncomingFeeRate(CHANNEL_ID)).thenReturn(Optional.of(123L)); when(grpcFees.getIncomingBaseFee(CHANNEL_ID)).thenReturn(Optional.of(Coins.ofMilliSatoshis(456))); + when(grpcFees.isEnabledLocal(CHANNEL_ID)).thenReturn(Optional.of(true)); + when(grpcFees.isEnabledRemote(CHANNEL_ID)).thenReturn(Optional.of(false)); - assertThat(feeService.getFeeConfiguration(CHANNEL_ID)) - .isEqualTo(expected); + assertThat(feeService.getFeeConfiguration(CHANNEL_ID)).isEqualTo(expected); + } + + @Test + void getFeeConfiguration_swapped() { + FeeConfiguration expected = new FeeConfiguration( + 123, + Coins.ofMilliSatoshis(456), + 789, + Coins.ofMilliSatoshis(111), + false, + true + ); + + when(grpcFees.getOutgoingFeeRate(CHANNEL_ID)).thenReturn(Optional.of(123L)); + when(grpcFees.getOutgoingBaseFee(CHANNEL_ID)).thenReturn(Optional.of(Coins.ofMilliSatoshis(456))); + when(grpcFees.getIncomingFeeRate(CHANNEL_ID)).thenReturn(Optional.of(789L)); + when(grpcFees.getIncomingBaseFee(CHANNEL_ID)).thenReturn(Optional.of(Coins.ofMilliSatoshis(111))); + when(grpcFees.isEnabledLocal(CHANNEL_ID)).thenReturn(Optional.of(false)); + when(grpcFees.isEnabledRemote(CHANNEL_ID)).thenReturn(Optional.of(true)); + + assertThat(feeService.getFeeConfiguration(CHANNEL_ID)).isEqualTo(expected); } @Test diff --git a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcFees.java b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcFees.java index 9870f19c..af511618 100644 --- a/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcFees.java +++ b/grpc-adapter/src/main/java/de/cotto/lndmanagej/grpc/GrpcFees.java @@ -34,4 +34,18 @@ public class GrpcFees { .map(RoutingPolicy::getFeeBaseMsat) .map(Coins::ofMilliSatoshis); } + + @SuppressWarnings("PMD.LinguisticNaming") + public Optional isEnabledLocal(ChannelId channelId) { + return grpcChannelPolicy.getLocalPolicy(channelId) + .map(RoutingPolicy::getDisabled) + .map(b -> !b); + } + + @SuppressWarnings("PMD.LinguisticNaming") + public Optional isEnabledRemote(ChannelId channelId) { + return grpcChannelPolicy.getRemotePolicy(channelId) + .map(RoutingPolicy::getDisabled) + .map(b -> !b); + } } diff --git a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcFeesTest.java b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcFeesTest.java index aa9e3dd1..7cb8b2d2 100644 --- a/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcFeesTest.java +++ b/grpc-adapter/src/test/java/de/cotto/lndmanagej/grpc/GrpcFeesTest.java @@ -69,10 +69,49 @@ class GrpcFeesTest { assertThat(grpcFees.getIncomingBaseFee(CHANNEL_ID)).isEmpty(); } + @Test + void isEnabledLocal_false() { + when(grpcChannelPolicy.getLocalPolicy(CHANNEL_ID)).thenReturn(Optional.of(routingPolicy(true))); + assertThat(grpcFees.isEnabledLocal(CHANNEL_ID)).contains(false); + } + + @Test + void isEnabledLocal_true() { + when(grpcChannelPolicy.getLocalPolicy(CHANNEL_ID)).thenReturn(Optional.of(routingPolicy(false))); + assertThat(grpcFees.isEnabledLocal(CHANNEL_ID)).contains(true); + } + + @Test + void isEnabledLocal_empty() { + assertThat(grpcFees.isEnabledLocal(CHANNEL_ID)).isEmpty(); + } + + @Test + void isEnabledRemote_false() { + when(grpcChannelPolicy.getRemotePolicy(CHANNEL_ID)).thenReturn(Optional.of(routingPolicy(true))); + assertThat(grpcFees.isEnabledRemote(CHANNEL_ID)).contains(false); + } + + @Test + void isEnabledRemote_true() { + when(grpcChannelPolicy.getRemotePolicy(CHANNEL_ID)).thenReturn(Optional.of(routingPolicy(false))); + assertThat(grpcFees.isEnabledRemote(CHANNEL_ID)).contains(true); + } + + @Test + void isEnabledRemote_empty() { + assertThat(grpcFees.isEnabledRemote(CHANNEL_ID)).isEmpty(); + } + private RoutingPolicy routingPolicy() { + return routingPolicy(false); + } + + private RoutingPolicy routingPolicy(boolean disabled) { return RoutingPolicy.newBuilder() .setFeeRateMilliMsat(FEE_RATE) .setFeeBaseMsat(BASE_FEE.milliSatoshis()) + .setDisabled(disabled) .build(); } diff --git a/model/src/main/java/de/cotto/lndmanagej/model/FeeConfiguration.java b/model/src/main/java/de/cotto/lndmanagej/model/FeeConfiguration.java index 1e383d2d..138e8dd5 100644 --- a/model/src/main/java/de/cotto/lndmanagej/model/FeeConfiguration.java +++ b/model/src/main/java/de/cotto/lndmanagej/model/FeeConfiguration.java @@ -4,6 +4,8 @@ public record FeeConfiguration( long outgoingFeeRate, Coins outgoingBaseFee, long incomingFeeRate, - Coins incomingBaseFee + Coins incomingBaseFee, + boolean enabledLocal, + boolean enabledRemote ) { } diff --git a/model/src/test/java/de/cotto/lndmanagej/model/ChannelStatusTest.java b/model/src/test/java/de/cotto/lndmanagej/model/ChannelStatusTest.java index 1b51705c..a4e323eb 100644 --- a/model/src/test/java/de/cotto/lndmanagej/model/ChannelStatusTest.java +++ b/model/src/test/java/de/cotto/lndmanagej/model/ChannelStatusTest.java @@ -6,7 +6,8 @@ import static de.cotto.lndmanagej.model.OpenCloseStatus.OPEN; import static org.assertj.core.api.Assertions.assertThat; class ChannelStatusTest { - private final ChannelStatus channelStatus = new ChannelStatus(false, true, false, OPEN); + private final ChannelStatus channelStatus = + new ChannelStatus(false, true, false, OPEN); @Test void privateChannel() { diff --git a/model/src/test/java/de/cotto/lndmanagej/model/FeeConfigurationTest.java b/model/src/test/java/de/cotto/lndmanagej/model/FeeConfigurationTest.java index 75c120c2..cbaf7e52 100644 --- a/model/src/test/java/de/cotto/lndmanagej/model/FeeConfigurationTest.java +++ b/model/src/test/java/de/cotto/lndmanagej/model/FeeConfigurationTest.java @@ -25,4 +25,14 @@ class FeeConfigurationTest { void incomingBaseFee() { assertThat(FEE_CONFIGURATION.incomingBaseFee()).isEqualTo(Coins.ofMilliSatoshis(4)); } + + @Test + void enabledLocal() { + assertThat(FEE_CONFIGURATION.enabledLocal()).isFalse(); + } + + @Test + void enabledRemote() { + assertThat(FEE_CONFIGURATION.enabledRemote()).isTrue(); + } } \ No newline at end of file diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/FeeConfigurationFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/FeeConfigurationFixtures.java index 5873162a..ddb11de0 100644 --- a/model/src/testFixtures/java/de/cotto/lndmanagej/model/FeeConfigurationFixtures.java +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/FeeConfigurationFixtures.java @@ -2,5 +2,12 @@ package de.cotto.lndmanagej.model; public class FeeConfigurationFixtures { public static final FeeConfiguration FEE_CONFIGURATION = - new FeeConfiguration(1, Coins.ofMilliSatoshis(2), 3, Coins.ofMilliSatoshis(4)); + new FeeConfiguration( + 1, + Coins.ofMilliSatoshis(2), + 3, + Coins.ofMilliSatoshis(4), + false, + true + ); } diff --git a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java index 38b26383..7d9f7d00 100644 --- a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java +++ b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java @@ -126,6 +126,8 @@ class ChannelControllerIT { .andExpect(jsonPath("$.balance.remoteBalance", is("223"))) .andExpect(jsonPath("$.balance.remoteReserve", is("20"))) .andExpect(jsonPath("$.balance.remoteAvailable", is("203"))) + .andExpect(jsonPath("$.feeConfiguration.enabledLocal", is(false))) + .andExpect(jsonPath("$.feeConfiguration.enabledRemote", is(true))) .andExpect(jsonPath("$.feeConfiguration.outgoingFeeRatePpm", is(1))) .andExpect(jsonPath("$.feeConfiguration.outgoingBaseFeeMilliSat", is(2))) .andExpect(jsonPath("$.feeConfiguration.incomingFeeRatePpm", is(3))) @@ -159,6 +161,8 @@ class ChannelControllerIT { .andExpect(jsonPath("$.outgoingFeeRatePpm", is(1))) .andExpect(jsonPath("$.outgoingBaseFeeMilliSat", is(2))) .andExpect(jsonPath("$.incomingFeeRatePpm", is(3))) - .andExpect(jsonPath("$.incomingBaseFeeMilliSat", is(4))); + .andExpect(jsonPath("$.incomingBaseFeeMilliSat", is(4))) + .andExpect(jsonPath("$.enabledLocal", is(false))) + .andExpect(jsonPath("$.enabledRemote", is(true))); } } \ No newline at end of file diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDto.java index 5b68562e..270a0a4a 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDto.java @@ -6,17 +6,28 @@ public record FeeConfigurationDto( long outgoingFeeRatePpm, long outgoingBaseFeeMilliSat, long incomingFeeRatePpm, - long incomingBaseFeeMilliSat + long incomingBaseFeeMilliSat, + boolean enabledLocal, + boolean enabledRemote ) { public static final FeeConfigurationDto EMPTY = - new FeeConfigurationDto(0, 0, 0, 0); + new FeeConfigurationDto( + 0, + 0, + 0, + 0, + false, + false + ); public static FeeConfigurationDto createFrom(FeeConfiguration feeConfiguration) { return new FeeConfigurationDto( feeConfiguration.outgoingFeeRate(), feeConfiguration.outgoingBaseFee().milliSatoshis(), feeConfiguration.incomingFeeRate(), - feeConfiguration.incomingBaseFee().milliSatoshis() + feeConfiguration.incomingBaseFee().milliSatoshis(), + feeConfiguration.enabledLocal(), + feeConfiguration.enabledRemote() ); } } diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDtoTest.java index 40d83272..519aca11 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/FeeConfigurationDtoTest.java @@ -8,7 +8,14 @@ import static org.assertj.core.api.Assertions.assertThat; class FeeConfigurationDtoTest { @Test void createFrom() { - FeeConfigurationDto expected = new FeeConfigurationDto(1, 2, 3, 4); + FeeConfigurationDto expected = new FeeConfigurationDto( + 1, + 2, + 3, + 4, + false, + true + ); FeeConfigurationDto dto = FeeConfigurationDto.createFrom(FEE_CONFIGURATION);