diff --git a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializer.java b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializer.java index bcf35daa..cfecf0f8 100644 --- a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializer.java +++ b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializer.java @@ -91,7 +91,8 @@ class ArcInitializer { if (ownPubkey.equals(edge.startNode())) { return 0; } - return edge.policy().feeRate(); + long fromBaseFee = (long) Math.ceil(1.0 * 1_000 / quantization * edge.policy().baseFee().milliSatoshis()); + return edge.policy().feeRate() + fromBaseFee; } private long quantize(Coins coins) { diff --git a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java index 4f85adeb..c0ae1f8c 100644 --- a/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java +++ b/pickhardt-payments/src/main/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputation.java @@ -9,7 +9,6 @@ import de.cotto.lndmanagej.model.DirectedChannelEdge; import de.cotto.lndmanagej.model.Edge; import de.cotto.lndmanagej.model.EdgeWithLiquidityInformation; import de.cotto.lndmanagej.model.LocalChannel; -import de.cotto.lndmanagej.model.Policy; import de.cotto.lndmanagej.model.Pubkey; import de.cotto.lndmanagej.pickhardtpayments.model.EdgesWithLiquidityInformation; import de.cotto.lndmanagej.service.BalanceService; @@ -106,8 +105,7 @@ public class EdgeComputation { } private boolean shouldIgnore(DirectedChannelEdge channelEdge) { - Policy policy = channelEdge.policy(); - return policy.disabled() || policy.baseFee().isPositive(); + return channelEdge.policy().disabled(); } private Optional getKnownLiquidity(Edge edge, Pubkey ownPubKey) { diff --git a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java index d1eba707..a1ca0336 100644 --- a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java +++ b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/ArcInitializerTest.java @@ -5,6 +5,7 @@ import com.google.ortools.graph.MinCostFlow; import de.cotto.lndmanagej.model.Coins; import de.cotto.lndmanagej.model.Edge; import de.cotto.lndmanagej.model.EdgeWithLiquidityInformation; +import de.cotto.lndmanagej.model.Policy; import de.cotto.lndmanagej.model.Pubkey; import de.cotto.lndmanagej.pickhardtpayments.model.EdgesWithLiquidityInformation; import de.cotto.lndmanagej.pickhardtpayments.model.IntegerMapping; @@ -13,6 +14,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; import static de.cotto.lndmanagej.model.EdgeFixtures.EDGE; import static de.cotto.lndmanagej.model.EdgeFixtures.EDGE_1_3; import static de.cotto.lndmanagej.model.EdgeFixtures.EDGE_2_3; @@ -206,17 +209,56 @@ class ArcInitializerTest { @Test void adds_fee_rate_as_cost() { int feeRateWeight = 1; - ArcInitializer arcInitializer = new ArcInitializer( + ArcInitializer arcInitializer = getArcInitializer(QUANTIZATION, feeRateWeight); + arcInitializer.addArcs(new EdgesWithLiquidityInformation(edgeWithLiquidityInformation)); + assertThat(minCostFlow.getUnitCost(0)).isEqualTo(200); + } + + @Test + void includes_base_fee_in_assumed_fee_rate() { + Coins baseFee = Coins.ofMilliSatoshis(100); + + int feeRateWeight = 1; + int quantization = 10_000; + ArcInitializer arcInitializer = getArcInitializer(quantization, feeRateWeight); + addEdgeWithBaseFee(baseFee, quantization, arcInitializer); + + long expectedFeeRate = (long) Math.ceil(200 + 10); + assertThat(minCostFlow.getUnitCost(0)).isEqualTo(expectedFeeRate); + } + + @Test + void includes_base_fee_in_assumed_fee_rate_rounds_up() { + Coins baseFee = Coins.ofMilliSatoshis(111); + + int feeRateWeight = 1; + int quantization = 10_000; + ArcInitializer arcInitializer = getArcInitializer(quantization, feeRateWeight); + addEdgeWithBaseFee(baseFee, quantization, arcInitializer); + + long expectedFeeRate = (long) Math.ceil(200 + 12); + assertThat(minCostFlow.getUnitCost(0)).isEqualTo(expectedFeeRate); + } + + private void addEdgeWithBaseFee(Coins baseFee, int quantization, ArcInitializer arcInitializer) { + Policy policy = new Policy(200, baseFee, true, 40, Coins.ofSatoshis(10_000)); + EdgeWithLiquidityInformation edge = EdgeWithLiquidityInformation.forKnownLiquidity( + new Edge(CHANNEL_ID, PUBKEY, PUBKEY_2, CAPACITY, policy), + Coins.ofSatoshis(30L * quantization) + ); + arcInitializer.addArcs(new EdgesWithLiquidityInformation(edge)); + } + + private ArcInitializer getArcInitializer(int quantization, int feeRateWeight) { + return new ArcInitializer( minCostFlow, integerMapping, edgeMapping, - QUANTIZATION, + quantization, PIECEWISE_LINEAR_APPROXIMATIONS, feeRateWeight, PUBKEY_2 ); - arcInitializer.addArcs(new EdgesWithLiquidityInformation(edgeWithLiquidityInformation)); - assertThat(minCostFlow.getUnitCost(0)).isEqualTo(200); } } diff --git a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java index 349e68e8..220d623e 100644 --- a/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java +++ b/pickhardt-payments/src/test/java/de/cotto/lndmanagej/pickhardtpayments/EdgeComputationTest.java @@ -88,11 +88,11 @@ class EdgeComputationTest { } @Test - void does_not_add_edge_for_channel_with_base_fee() { + void adds_edge_for_channel_with_base_fee() { DirectedChannelEdge edge = new DirectedChannelEdge(CHANNEL_ID, CAPACITY, PUBKEY, PUBKEY_2, POLICY_WITH_BASE_FEE); when(grpcGraph.getChannelEdges()).thenReturn(Optional.of(Set.of(edge))); - assertThat(edgeComputation.getEdges().edges()).isEmpty(); + assertThat(edgeComputation.getEdges().edges()).isNotEmpty(); } @Test