mirror of
https://github.com/alexbosworth/balanceofsatoshis.git
synced 2026-08-13 12:33:37 +02:00
120 lines
3.8 KiB
JavaScript
120 lines
3.8 KiB
JavaScript
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;
|
|
}),
|
|
};
|
|
};
|