diff --git a/doc/schemas/getroutes.json b/doc/schemas/getroutes.json index 6fc5020b23e2..04f502e2890b 100644 --- a/doc/schemas/getroutes.json +++ b/doc/schemas/getroutes.json @@ -11,7 +11,7 @@ "", "Layers are generally maintained by plugins, either to contain persistent information about capacities which have been discovered, or to contain transient information for this particular payment (such as blinded paths or routehints).", "", - "There are three automatic layers: *auto.localchans* contains information on local channels from this node (including non-public ones), and their exact current spendable capacities. *auto.sourcefree* overrides all channels (including those from previous layers) leading out of the *source* to be zero fee and zero delay. These are both useful in the case where the source is the current node. And *auto.no_mpp_support* forces getroutes to return a single path solution which is useful for payments for which MPP is not supported." + "There are four automatic layers: *auto.localchans* contains information on local channels from this node (including non-public ones), and their exact current spendable capacities. *auto.sourcefree* overrides all channels (including those from previous layers) leading out of the *source* to be zero fee and zero delay. These are both useful in the case where the source is the current node. *auto.no_mpp_support* forces getroutes to return a single path solution which is useful for payments for which MPP is not supported. And *auto.include_fees* that fixes the send amount and deducts fee from there, ie. the receiver pays for fees instead of the sender." ], "categories": [ "readonly" diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c index 23e541d75911..acb369724cd3 100644 --- a/plugins/askrene/askrene.c +++ b/plugins/askrene/askrene.c @@ -447,7 +447,8 @@ static struct route **convert_flows_to_routes(const tal_t *ctx, struct route_query *rq, u32 finalcltv, struct flow **flows, - struct amount_msat **amounts) + struct amount_msat **amounts, + bool include_fees) { struct route **routes; routes = tal_arr(ctx, struct route *, tal_count(flows)); @@ -462,26 +463,69 @@ static struct route **convert_flows_to_routes(const tal_t *ctx, r->success_prob = flow_probability(flows[i], rq); r->hops = tal_arr(r, struct route_hop, tal_count(flows[i]->path)); - /* Fill in backwards to calc amount and delay */ msat = flows[i]->delivers; delay = finalcltv; - for (int j = tal_count(flows[i]->path) - 1; j >= 0; j--) { - struct route_hop *rh = &r->hops[j]; - struct gossmap_node *far_end; - const struct half_chan *h = flow_edge(flows[i], j); - - if (!amount_msat_add_fee(&msat, h->base_fee, h->proportional_fee)) - plugin_err(rq->plugin, "Adding fee to amount"); - delay += h->delay; - - rh->scid = gossmap_chan_scid(rq->gossmap, flows[i]->path[j]); - rh->direction = flows[i]->dirs[j]; - far_end = gossmap_nth_node(rq->gossmap, flows[i]->path[j], !flows[i]->dirs[j]); - gossmap_node_get_id(rq->gossmap, far_end, &rh->node_id); - rh->amount = msat; - rh->delay = delay; + if (!include_fees) { + /* Fill in backwards to calc amount and delay */ + for (int j = tal_count(flows[i]->path) - 1; j >= 0; + j--) { + struct route_hop *rh = &r->hops[j]; + struct gossmap_node *far_end; + const struct half_chan *h = + flow_edge(flows[i], j); + + if (!amount_msat_add_fee(&msat, h->base_fee, + h->proportional_fee)) + plugin_err(rq->plugin, + "Adding fee to amount"); + delay += h->delay; + + rh->scid = gossmap_chan_scid(rq->gossmap, + flows[i]->path[j]); + rh->direction = flows[i]->dirs[j]; + far_end = gossmap_nth_node(rq->gossmap, + flows[i]->path[j], + !flows[i]->dirs[j]); + gossmap_node_get_id(rq->gossmap, far_end, + &rh->node_id); + rh->amount = msat; + rh->delay = delay; + } + } else { + /* Fill in backwards to calc delay */ + for (int j = tal_count(flows[i]->path) - 1; j >= 0; + j--) { + struct route_hop *rh = &r->hops[j]; + struct gossmap_node *far_end; + const struct half_chan *h = + flow_edge(flows[i], j); + + delay += h->delay; + + rh->scid = gossmap_chan_scid(rq->gossmap, + flows[i]->path[j]); + rh->direction = flows[i]->dirs[j]; + far_end = gossmap_nth_node(rq->gossmap, + flows[i]->path[j], + !flows[i]->dirs[j]); + gossmap_node_get_id(rq->gossmap, far_end, + &rh->node_id); + rh->delay = delay; + } + /* Compute fees forward */ + for (int j = 0; j < tal_count(flows[i]->path); j++) { + struct route_hop *rh = &r->hops[j]; + const struct half_chan *h = + flow_edge(flows[i], j); + + rh->amount = msat; + // FIXME: either before or after assignment + msat = amount_msat_sub_fee(msat, h->base_fee, + h->proportional_fee); + } } + (*amounts)[i] = flows[i]->delivers; rq_log(tmpctx, rq, LOG_INFORM, "Flow %zu/%zu: %s", i, tal_count(flows), @@ -573,6 +617,7 @@ static struct command_result *do_getroutes(struct command *cmd, struct route **routes; struct flow **flows; struct json_stream *response; + bool include_fees; /* update the gossmap */ if (gossmap_refresh(askrene->gossmap)) { @@ -684,9 +729,11 @@ static struct command_result *do_getroutes(struct command *cmd, rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows", tal_count(flows)); + include_fees = have_layer(info->layers, "auto.include_fees"); + /* convert flows to routes */ routes = convert_flows_to_routes(rq, rq, info->finalcltv, flows, - &amounts); + &amounts, include_fees); assert(tal_count(routes) == tal_count(flows)); assert(tal_count(amounts) == tal_count(flows));