UNPKG

balanceofsatoshis

Version:
121 lines (105 loc) 3.91 kB
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; }), }; };