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 26f3f08a..28a3d633 100644 --- a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java +++ b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ChannelControllerIT.java @@ -20,6 +20,7 @@ import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT; import static de.cotto.lndmanagej.model.FeeConfigurationFixtures.FEE_CONFIGURATION; +import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL; import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_PRIVATE; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS_2; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; @@ -102,4 +103,15 @@ class ChannelControllerIT { mockMvc.perform(get(CHANNEL_PREFIX + "/details")) .andExpect(status().isNotFound()); } + + @Test + void getFeeConfiguration() throws Exception { + when(channelService.getLocalChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL)); + when(feeService.getFeeConfiguration(CHANNEL_ID)).thenReturn(FEE_CONFIGURATION); + mockMvc.perform(get(CHANNEL_PREFIX + "/fee-configuration")) + .andExpect(jsonPath("$.outgoingFeeRatePpm", is(1))) + .andExpect(jsonPath("$.outgoingBaseFeeMilliSat", is(2))) + .andExpect(jsonPath("$.incomingFeeRatePpm", is(3))) + .andExpect(jsonPath("$.incomingBaseFeeMilliSat", is(4))); + } } \ No newline at end of file diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java b/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java index e0c19d37..343bd189 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/ChannelController.java @@ -24,6 +24,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Nullable; + @RestController @RequestMapping("/api/channel/{channelId}") @Import(ObjectMapperConfiguration.class) @@ -69,6 +71,21 @@ public class ChannelController { ); } + @GetMapping("/fee-configuration") + public FeeConfigurationDto getFeeConfiguration(@PathVariable ChannelId channelId) { + metrics.mark(MetricRegistry.name(getClass(), "getFeeConfiguration")); + LocalChannel localChannel = channelService.getLocalChannel(channelId).orElse(null); + return getFeeConfiguration(localChannel); + } + + private FeeConfigurationDto getFeeConfiguration(@Nullable LocalChannel channel) { + if (channel == null || channel.getStatus().openCloseStatus() != OpenCloseStatus.OPEN) { + return FeeConfigurationDto.EMPTY; + } + FeeConfiguration feeConfiguration = feeService.getFeeConfiguration(channel.getId()); + return FeeConfigurationDto.createFrom(feeConfiguration); + } + private BalanceInformation getBalanceInformation(ChannelId channelId) { return balanceService.getBalanceInformation(channelId) .orElse(BalanceInformation.EMPTY); @@ -79,12 +96,4 @@ public class ChannelController { Coins closeCosts = onChainCostService.getCloseCosts(channelId).orElse(Coins.NONE); return new OnChainCostsDto(openCosts, closeCosts); } - - private FeeConfigurationDto getFeeConfiguration(LocalChannel channel) { - if (channel.getStatus().openCloseStatus() == OpenCloseStatus.OPEN) { - FeeConfiguration feeConfiguration = feeService.getFeeConfiguration(channel.getId()); - return FeeConfigurationDto.createFrom(feeConfiguration); - } - return new FeeConfigurationDto(0, 0, 0, 0); - } } 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 61d38cba..5b68562e 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 @@ -8,6 +8,9 @@ public record FeeConfigurationDto( long incomingFeeRatePpm, long incomingBaseFeeMilliSat ) { + public static final FeeConfigurationDto EMPTY = + new FeeConfigurationDto(0, 0, 0, 0); + public static FeeConfigurationDto createFrom(FeeConfiguration feeConfiguration) { return new FeeConfigurationDto( feeConfiguration.outgoingFeeRate(), diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java index 879ab35e..2eb8e62e 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/ChannelControllerTest.java @@ -124,6 +124,19 @@ class ChannelControllerTest { assertThat(channelController.getDetails(CHANNEL_ID)).isEqualTo(expectedDetails); } + @Test + void getFeeConfiguration() { + when(channelService.getLocalChannel(CHANNEL_ID)).thenReturn(Optional.of(LOCAL_OPEN_CHANNEL)); + when(feeService.getFeeConfiguration(CHANNEL_ID)).thenReturn(FEE_CONFIGURATION); + assertThat(channelController.getFeeConfiguration(CHANNEL_ID)).isEqualTo(FEE_CONFIGURATION_DTO); + verify(metrics).mark(argThat(name -> name.endsWith(".getFeeConfiguration"))); + } + + @Test + void getFeeConfiguration_waiting_close() { + assertThat(channelController.getFeeConfiguration(CHANNEL_ID)).isEqualTo(FeeConfigurationDto.EMPTY); + } + private ChannelDetailsDto mockForChannelWithoutFeeConfiguration(LocalChannel channel) { when(nodeService.getAlias(PUBKEY_2)).thenReturn(ALIAS_2); when(channelService.getLocalChannel(CHANNEL_ID)).thenReturn(Optional.of(channel)); @@ -133,7 +146,7 @@ class ChannelControllerTest { ALIAS_2, BalanceInformation.EMPTY, ON_CHAIN_COSTS, - new FeeConfigurationDto(0, 0, 0, 0) + FeeConfigurationDto.EMPTY ); } } \ No newline at end of file diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java index acde09bd..8f421d04 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/ChannelDetailsDtoTest.java @@ -18,10 +18,13 @@ import static org.assertj.core.api.Assertions.assertThat; class ChannelDetailsDtoTest { private static final OnChainCostsDto ON_CHAIN_COSTS = new OnChainCostsDto(Coins.ofSatoshis(1), Coins.ofSatoshis(2)); - private static final FeeConfigurationDto FEE_CONFIGURATION_DTO = - new FeeConfigurationDto(0, 0, 0, 0); - private static final ChannelDetailsDto CHANNEL_DETAILS_DTO = - new ChannelDetailsDto(CLOSED_CHANNEL, ALIAS, BALANCE_INFORMATION, ON_CHAIN_COSTS, FEE_CONFIGURATION_DTO); + private static final ChannelDetailsDto CHANNEL_DETAILS_DTO = new ChannelDetailsDto( + CLOSED_CHANNEL, + ALIAS, + BALANCE_INFORMATION, + ON_CHAIN_COSTS, + FeeConfigurationDto.EMPTY + ); @Test void channelIdShort() { @@ -70,7 +73,7 @@ class ChannelDetailsDtoTest { ALIAS, BALANCE_INFORMATION, ON_CHAIN_COSTS, - FEE_CONFIGURATION_DTO + FeeConfigurationDto.EMPTY ); ChannelStatusDto channelStatusDto = ChannelStatusDto.createFrom(new ChannelStatus(false, true, false, OPEN));