forked from alexbosworth/balanceofsatoshis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmulti_path_payment.js
120 lines (105 loc) · 3.82 KB
/
multi_path_payment.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const {routeFromChannels} = require('ln-service');
const {sortBy} = require('./../arrays');
const cltvDeltaBuffer = 3;
const {floor} = Math;
const mtokAsTok = mtokens => Number(BigInt(mtokens) / BigInt(1e3));
const tokensAsMtokens = tokens => BigInt(tokens) * BigInt(1e3);
/** Derive multiple paths to pay to a destination
{
channels: [{
capacity: <Maximum Tokens Number>
id: <Standard Format Channel Id String>
policies: [{
[base_fee_mtokens]: <Base Fee Millitokens String>
[cltv_delta]: <Locktime Delta Number>
[fee_rate]: <Fees Charged Per Million Tokens Number>
[is_disabled]: <Channel Is Disabled Bool>
[max_htlc_mtokens]: <Maximum HTLC Millitokens Value String>
[min_htlc_mtokens]: <Minimum HTLC Millitokens Value String>
public_key: <Node Public Key String>
[updated_at]: <Edge Last Updated At ISO 8601 Date String>
}]
transaction_id: <Transaction Id Hex String>
transaction_vout: <Transaction Output Index Number>
[updated_at]: <Channel Last Updated At ISO 8601 Date String>
}]
[cltv_delta]: <CLTV Delta Number>
destination: <Destination Public Key Hex String>
height: <Current Block Height Number>
max: <Maximum Routeable Amount Tokens Number>
mtokens: <Millitokens To Pay String>
probes: [{
channels: [<Standard Format Channel Id String>]
liquidity: <Route Liquidity Tokens Number>
}]
}
@returns
{
routes: [{
fee: <Total Fee Tokens To Pay Number>
fee_mtokens: <Total Fee Millitokens To Pay String>
hops: [{
channel: <Standard Format Channel Id String>
channel_capacity: <Channel Capacity Tokens Number>
fee: <Fee Number>
fee_mtokens: <Fee Millitokens String>
forward: <Forward Tokens Number>
forward_mtokens: <Forward Millitokens String>
[public_key]: <Public Key Hex String>
timeout: <Timeout Block Height Number>
}]
[messages]: [{
type: <Message Type Number String>
value: <Message Raw Value Hex Encoded String>
}]
mtokens: <Total Millitokens To Pay String>
[payment]: <Payment Identifier Hex String>
timeout: <Expiration Block Height Number>
tokens: <Total Tokens To Pay Number>
[total_mtokens]: <Total Millitokens String>
}]
}
*/
module.exports = args => {
const amounts = args.probes.map(probe => {
return floor(mtokAsTok(args.mtokens) * probe.liquidity / args.max);
});
const total = amounts.reduce((sum, n) => sum + n, Number());
const remainder = BigInt(args.mtokens) - tokensAsMtokens(total);
const routesToCreate = args.probes.map(probe => {
return {
channels: probe.channels.map(id => args.channels.find(n => n.id === id)),
cltv_delta: args.cltv_delta + cltvDeltaBuffer,
destination: args.destination,
height: args.height,
payment: args.payment,
tokens: floor(mtokAsTok(args.mtokens) * probe.liquidity / args.max),
total_mtokens: args.mtokens,
};
});
const {sorted} = sortBy({array: routesToCreate, attribute: 'tokens'});
const totalAdjusted = sorted.map((route, i) => {
route.mtokens = tokensAsMtokens(route.tokens).toString();
// For simplicity, only adjust the largest route, the first one
if (!!i) {
return route;
}
// Adjust the route to carry the mtokens that didn't divide evenly
route.mtokens = (BigInt(route.mtokens) + remainder).toString();
return route;
});
return {
routes: totalAdjusted.map(path => {
const {route} = routeFromChannels({
channels: path.channels,
cltv_delta: path.cltv_delta,
destination: path.destination,
height: path.height,
mtokens: path.mtokens,
payment: path.payment,
total_mtokens: path.total_mtokens,
});
return route;
}),
};
};