mirror of
https://github.com/alexbosworth/balanceofsatoshis.git
synced 2026-08-13 12:33:37 +02:00
fix issues with find, tags, service keysend reqs
This commit is contained in:
parent
d15d0435be
commit
8cfd134db5
13 changed files with 461 additions and 54 deletions
|
|
@ -1,5 +1,11 @@
|
|||
# Versions
|
||||
|
||||
## Version 8.0.3
|
||||
|
||||
- `find`: Lookup node by start of public key
|
||||
- `service-keysend-requests`: Use an alternative node to pay response requests
|
||||
- `tags`: Fix issue when setting avoid on a tag without adjusting icon or keys
|
||||
|
||||
## Version 8.0.2
|
||||
|
||||
- `rebalance`: Show node icons in route descriptions
|
||||
|
|
|
|||
33
bos
33
bos
|
|
@ -1338,14 +1338,43 @@ prog
|
|||
|
||||
// Respond to keysend service requests
|
||||
.command('service-keysend-requests', 'Respond to keysend service requests')
|
||||
.help('Offering keysend services requires --keysend enabled')
|
||||
.help('Offering keysend services requires --accept-keysend in LND')
|
||||
.option('--node <node_name>', 'Saved node to respond to service requests')
|
||||
.option('--payer <pay_with_node_name>', 'Node to pay response requests with')
|
||||
.action((args, options, logger) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const {lnd} = await lndForNode(logger, options.node);
|
||||
const payer = options.payer === options.node ? null : options.payer;
|
||||
|
||||
await services.serviceKeySendRequests({
|
||||
lnd,
|
||||
logger,
|
||||
lnd: (await lnd.authenticatedLnd({logger, node: options.node})).lnd,
|
||||
pay: !payer ? lnd : (await lndForNode(logger, payer)).lnd,
|
||||
},
|
||||
responses.returnObject({logger, reject, resolve}));
|
||||
} catch (err) {
|
||||
return reject(logger.error({err}));
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// Simulate a keysend request by generating a special local invoice
|
||||
.command('simulate-keysend-request', 'Create an invoice to simulate request')
|
||||
.visible(false)
|
||||
.argument('<amount>', 'Invoice amount to simulate receiving')
|
||||
.argument('<number_value_pairs...>', 'TLV records: <number> <hex value>')
|
||||
.help('Make an invoice that represents a fake keysend with records')
|
||||
.help('This invoice can trigger keysend request services to test them out')
|
||||
.option('--node <node_name>', 'Saved node to create simulated request')
|
||||
.action((args, options, logger) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
await services.simulateKeySendRequest({
|
||||
lnd: (await lndForNode(logger, options.node)).lnd,
|
||||
tokens: Number(args.amount),
|
||||
types: args.numberValuePairs.filter((n, i) => !(i % 2)),
|
||||
values: args.numberValuePairs.filter((n, i) => i % 2),
|
||||
},
|
||||
responses.returnObject({logger, reject, resolve}));
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -135,6 +135,10 @@ module.exports = ({lnd, query}, cbk) => {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (node.public_key.startsWith(query.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return node.public_key === query;
|
||||
})
|
||||
.map(node => {
|
||||
|
|
|
|||
|
|
@ -155,10 +155,11 @@ module.exports = (args, cbk) => {
|
|||
return cbk([400, 'AmbiguousTagToAdjustSpecified', {matches}]);
|
||||
}
|
||||
|
||||
const setAvoid = args.is_avoided !== undefined;
|
||||
const setIcon = args.icon !== undefined;
|
||||
|
||||
// Exit early when not editing the tag
|
||||
if (!args.add.length && !setIcon && !args.remove.length) {
|
||||
if (!args.add.length && !setAvoid && !setIcon && !args.remove.length) {
|
||||
return cbk(null, tagMatch);
|
||||
}
|
||||
|
||||
|
|
|
|||
176
package-lock.json
generated
176
package-lock.json
generated
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "balanceofsatoshis",
|
||||
"version": "8.0.2",
|
||||
"version": "8.0.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
@ -901,6 +901,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"bolt01": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bolt01/-/bolt01-1.2.0.tgz",
|
||||
"integrity": "sha512-CPpRbmi+4CU63Mt87gitgJz5YgygirvZuyJOBzTVH0uXCtav5rl94jzsR/m+ihfYFlswvebNwy7dX/w+YV+BZg==",
|
||||
"requires": {
|
||||
"bn.js": "5.2.0"
|
||||
}
|
||||
},
|
||||
"bolt03": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/bolt03/-/bolt03-1.2.7.tgz",
|
||||
|
|
@ -1138,9 +1146,9 @@
|
|||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"cbor": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cbor/-/cbor-7.0.3.tgz",
|
||||
"integrity": "sha512-Io+lJytjYBJKgJqZQUz2bFaMPj+HtlsnT9kHSUiIJFqzWa05lm5/ycQ+NiZWpks3DR2Fz7j7axiTGeT57w/syg==",
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cbor/-/cbor-7.0.4.tgz",
|
||||
"integrity": "sha512-9hBTn31l7+9qteBso7+HPp2R5ytqFRBd98fHK4ZTpvrba8V7CuoOsEL0S6vf7+11gubMTd3RW97lOgMTl5SNfg==",
|
||||
"requires": {
|
||||
"@cto.af/textdecoder": "^0.0.0",
|
||||
"nofilter": "^2.0.3"
|
||||
|
|
@ -2129,6 +2137,32 @@
|
|||
"node-fetch": "2.6.1",
|
||||
"pushdata-bitcoin": "1.0.1",
|
||||
"varuint-bitcoin": "1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"cbor": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cbor/-/cbor-7.0.3.tgz",
|
||||
"integrity": "sha512-Io+lJytjYBJKgJqZQUz2bFaMPj+HtlsnT9kHSUiIJFqzWa05lm5/ycQ+NiZWpks3DR2Fz7j7axiTGeT57w/syg==",
|
||||
"requires": {
|
||||
"@cto.af/textdecoder": "^0.0.0",
|
||||
"nofilter": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"ln-service": {
|
||||
"version": "51.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-51.3.1.tgz",
|
||||
"integrity": "sha512-V5Q1rZbN4GY1PfxosQ1pWyyhZF/qPWivf5whL0lDWBrJ4xgsemYRkg5ce4YaUNLYv/BXfMrQVyw09w+tyq+QnQ==",
|
||||
"requires": {
|
||||
"bolt07": "1.7.1",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.17.1",
|
||||
"invoices": "1.1.6",
|
||||
"lightning": "3.2.20",
|
||||
"macaroon": "3.0.4",
|
||||
"morgan": "1.10.0",
|
||||
"ws": "7.4.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"google-auth-library": {
|
||||
|
|
@ -2946,6 +2980,15 @@
|
|||
"version": "14.14.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.32.tgz",
|
||||
"integrity": "sha512-/Ctrftx/zp4m8JOujM5ZhwzlWLx22nbQJiVqz8/zE15gOeEW+uly3FSX4fGFpcfEvFzXcMCJwq9lGVWgyARXhg=="
|
||||
},
|
||||
"cbor": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cbor/-/cbor-7.0.3.tgz",
|
||||
"integrity": "sha512-Io+lJytjYBJKgJqZQUz2bFaMPj+HtlsnT9kHSUiIJFqzWa05lm5/ycQ+NiZWpks3DR2Fz7j7axiTGeT57w/syg==",
|
||||
"requires": {
|
||||
"@cto.af/textdecoder": "^0.0.0",
|
||||
"nofilter": "^2.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2960,21 +3003,79 @@
|
|||
"goldengate": "10.0.2",
|
||||
"json2csv": "5.0.6",
|
||||
"ln-service": "51.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ln-service": {
|
||||
"version": "51.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-51.3.1.tgz",
|
||||
"integrity": "sha512-V5Q1rZbN4GY1PfxosQ1pWyyhZF/qPWivf5whL0lDWBrJ4xgsemYRkg5ce4YaUNLYv/BXfMrQVyw09w+tyq+QnQ==",
|
||||
"requires": {
|
||||
"bolt07": "1.7.1",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.17.1",
|
||||
"invoices": "1.1.6",
|
||||
"lightning": "3.2.20",
|
||||
"macaroon": "3.0.4",
|
||||
"morgan": "1.10.0",
|
||||
"ws": "7.4.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ln-service": {
|
||||
"version": "51.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-51.3.1.tgz",
|
||||
"integrity": "sha512-V5Q1rZbN4GY1PfxosQ1pWyyhZF/qPWivf5whL0lDWBrJ4xgsemYRkg5ce4YaUNLYv/BXfMrQVyw09w+tyq+QnQ==",
|
||||
"version": "51.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-51.5.0.tgz",
|
||||
"integrity": "sha512-Q22CcKJ+52mExGNvOmeEVBza82LGdbLkFVzfMjC9oPlP5DikS+sdlK5GZM/Dc5HFN5pwK7y9Ke7gRue/UxHwbw==",
|
||||
"requires": {
|
||||
"bolt07": "1.7.1",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.17.1",
|
||||
"invoices": "1.1.6",
|
||||
"lightning": "3.2.20",
|
||||
"lightning": "3.3.1",
|
||||
"macaroon": "3.0.4",
|
||||
"morgan": "1.10.0",
|
||||
"ws": "7.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": {
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.2.11.tgz",
|
||||
"integrity": "sha512-DZqx3nHBm2OGY7NKq4sppDEfx4nBAsQH/d/H/yxo/+BwpVLWLGs+OorpwQ+Fqd6EgpDEoi4MhqndjGUeLl/5GA==",
|
||||
"requires": {
|
||||
"@types/node": ">=12.12.47",
|
||||
"google-auth-library": "^6.1.1",
|
||||
"semver": "^6.2.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.14.35",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz",
|
||||
"integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag=="
|
||||
},
|
||||
"lightning": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/lightning/-/lightning-3.3.1.tgz",
|
||||
"integrity": "sha512-lzj7oODpX7XS/4qHGBG/VAMirBDK/rbWS8S9pTCSUV9ZknuXg2loCkDyPQuB3vC2MMt1QOsXn4oQUtxpPtSa1g==",
|
||||
"requires": {
|
||||
"@grpc/grpc-js": "1.2.11",
|
||||
"@grpc/proto-loader": "0.5.6",
|
||||
"@types/express": "4.17.11",
|
||||
"@types/node": "14.14.35",
|
||||
"@types/request": "2.48.5",
|
||||
"@types/ws": "7.4.0",
|
||||
"async": "3.2.0",
|
||||
"asyncjs-util": "1.2.3",
|
||||
"bitcoinjs-lib": "5.2.0",
|
||||
"bn.js": "5.2.0",
|
||||
"body-parser": "1.19.0",
|
||||
"bolt07": "1.7.1",
|
||||
"bolt09": "0.1.3",
|
||||
"cbor": "7.0.4",
|
||||
"express": "4.17.1",
|
||||
"invoices": "1.1.6",
|
||||
"psbt": "1.1.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ln-sync": {
|
||||
|
|
@ -2989,6 +3090,17 @@
|
|||
"colorette": "1.2.2",
|
||||
"lightning": "3.2.20",
|
||||
"stats-lite": "2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"cbor": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cbor/-/cbor-7.0.3.tgz",
|
||||
"integrity": "sha512-Io+lJytjYBJKgJqZQUz2bFaMPj+HtlsnT9kHSUiIJFqzWa05lm5/ycQ+NiZWpks3DR2Fz7j7axiTGeT57w/syg==",
|
||||
"requires": {
|
||||
"@cto.af/textdecoder": "^0.0.0",
|
||||
"nofilter": "^2.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ln-telegram": {
|
||||
|
|
@ -3004,6 +3116,23 @@
|
|||
"ln-sync": "0.4.4",
|
||||
"moment": "2.29.1",
|
||||
"table": "6.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"ln-service": {
|
||||
"version": "51.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-51.3.1.tgz",
|
||||
"integrity": "sha512-V5Q1rZbN4GY1PfxosQ1pWyyhZF/qPWivf5whL0lDWBrJ4xgsemYRkg5ce4YaUNLYv/BXfMrQVyw09w+tyq+QnQ==",
|
||||
"requires": {
|
||||
"bolt07": "1.7.1",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.17.1",
|
||||
"invoices": "1.1.6",
|
||||
"lightning": "3.2.20",
|
||||
"macaroon": "3.0.4",
|
||||
"morgan": "1.10.0",
|
||||
"ws": "7.4.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"load-json-file": {
|
||||
|
|
@ -3713,6 +3842,23 @@
|
|||
"bolt07": "1.7.1",
|
||||
"invoices": "1.1.6",
|
||||
"ln-service": "51.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ln-service": {
|
||||
"version": "51.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ln-service/-/ln-service-51.3.1.tgz",
|
||||
"integrity": "sha512-V5Q1rZbN4GY1PfxosQ1pWyyhZF/qPWivf5whL0lDWBrJ4xgsemYRkg5ce4YaUNLYv/BXfMrQVyw09w+tyq+QnQ==",
|
||||
"requires": {
|
||||
"bolt07": "1.7.1",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.17.1",
|
||||
"invoices": "1.1.6",
|
||||
"lightning": "3.2.20",
|
||||
"macaroon": "3.0.4",
|
||||
"morgan": "1.10.0",
|
||||
"ws": "7.4.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"process-nextick-args": {
|
||||
|
|
@ -5904,9 +6050,9 @@
|
|||
}
|
||||
},
|
||||
"telegraf": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.1.2.tgz",
|
||||
"integrity": "sha512-YZljmryOhcZgrRWU28AV7UhZ3y+jKRwPwB49PSDDmW7tKtQHrSLBkW0pCoLniDlQVz+ICBGCWXZlHfqDkQ2iNQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.3.0.tgz",
|
||||
"integrity": "sha512-MuDUtSMipzMzQp8fXbQx76jp4ZD70KREdnpH1idUzN9Zlgm6EzatBQFU4Ps0ipxtEmnBBdghBMumQwrjRe3eqg==",
|
||||
"requires": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"debug": "^4.3.1",
|
||||
|
|
@ -5916,7 +6062,7 @@
|
|||
"p-timeout": "^4.1.0",
|
||||
"safe-compare": "^1.1.4",
|
||||
"sandwich-stream": "^2.0.2",
|
||||
"typegram": "^3.1.10"
|
||||
"typegram": "^3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
|
|
@ -6101,9 +6247,9 @@
|
|||
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
|
||||
},
|
||||
"typegram": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/typegram/-/typegram-3.1.10.tgz",
|
||||
"integrity": "sha512-VfsuVP4uqk9yllRpaGp9yFpzvLKXghFCOSc3TVi+fy1IL2Bi4z2gJ9rMgVSSug4pWQP8Ui7Isvl14yYV8VEWaQ=="
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typegram/-/typegram-3.2.3.tgz",
|
||||
"integrity": "sha512-zlkY7vNTLcwQhLUyYXAUzRelzH752LBFl8m4u04d5g5P7lM9bGegeIRwzd3mVCHJH6R3s48pKeFTVSdVlN+omg=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.9.9",
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@
|
|||
"asyncjs-util": "1.2.3",
|
||||
"bitcoin-ops": "1.4.1",
|
||||
"bitcoinjs-lib": "5.2.0",
|
||||
"bolt01": "1.2.0",
|
||||
"bolt03": "1.2.7",
|
||||
"bolt07": "1.7.1",
|
||||
"caporal": "1.4.0",
|
||||
"cbor": "7.0.3",
|
||||
"cbor": "7.0.4",
|
||||
"cert-info": "1.5.1",
|
||||
"colorette": "1.2.2",
|
||||
"crypto-js": "4.0.0",
|
||||
|
|
@ -32,7 +33,7 @@
|
|||
"inquirer": "8.0.0",
|
||||
"invoices": "1.1.6",
|
||||
"ln-accounting": "4.2.6",
|
||||
"ln-service": "51.3.1",
|
||||
"ln-service": "51.5.0",
|
||||
"ln-sync": "0.4.4",
|
||||
"ln-telegram": "3.2.1",
|
||||
"moment": "2.29.1",
|
||||
|
|
@ -43,7 +44,7 @@
|
|||
"sanitize-filename": "1.6.3",
|
||||
"stats-lite": "2.2.0",
|
||||
"table": "6.0.7",
|
||||
"telegraf": "4.1.2",
|
||||
"telegraf": "4.3.0",
|
||||
"update-notifier": "5.1.0",
|
||||
"window-size": "1.1.1"
|
||||
},
|
||||
|
|
@ -76,5 +77,5 @@
|
|||
"postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis --push .",
|
||||
"test": "tap -t 60 test/arrays/*.js test/balances/*.js test/chain/*.js test/display/*.js test/encryption/*.js test/fiat/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/peers/*.js test/responses/*.js test/routing/*.js test/services/*.js test/swaps/*.js test/wallets/*.js"
|
||||
},
|
||||
"version": "8.0.2"
|
||||
"version": "8.0.3"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ const advertise = require('./advertise');
|
|||
const openBalancedChannel = require('./open_balanced_channel');
|
||||
const purchasePing = require('./purchase_ping');
|
||||
const serviceKeySendRequests = require('./service_key_send_requests');
|
||||
const simulateKeySendRequest = require('./simulate_key_send_request');
|
||||
|
||||
module.exports = {
|
||||
advertise,
|
||||
openBalancedChannel,
|
||||
purchasePing,
|
||||
serviceKeySendRequests,
|
||||
simulateKeySendRequest,
|
||||
};
|
||||
|
|
|
|||
85
services/key_send_request_arguments.js
Normal file
85
services/key_send_request_arguments.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
const {decodeTlvStream} = require('bolt01');
|
||||
|
||||
const base64AsHex = base64 => Buffer.from(base64, 'base64').toString('hex');
|
||||
const processAfter = () => new Date(Date.now() - (1000*60*60)).toISOString();
|
||||
|
||||
/** Derive key send request arguments from invoice details
|
||||
|
||||
{
|
||||
[confirmed_at]: <Settled at ISO 8601 Date String>
|
||||
description: <Invoice Description String>
|
||||
[description_hash]: <Invoice Description Hash String>
|
||||
id: <Payment Hash Hex String>
|
||||
[is_canceled]: <Invoice is Canceled Bool>
|
||||
is_confirmed: <Invoice is Confirmed Bool>
|
||||
payments: [{
|
||||
is_confirmed: <HTLC is Confirmed Bool>
|
||||
messages: [{
|
||||
type: <Message Type String>
|
||||
value: <Hex Encoded Value String>
|
||||
}]
|
||||
}]
|
||||
received: <Tokens Received Rounded Down Number>
|
||||
secret: <Invoice Preimage Hex String>
|
||||
tokens: <Invoiced Tokens Rounded Down Number>
|
||||
}
|
||||
|
||||
@returns
|
||||
{
|
||||
[arguments]: {
|
||||
id: <Payment Hash Hex String>
|
||||
messages: [{
|
||||
type: <Message Type String>
|
||||
value: <Hex Encoded Value String>
|
||||
}]
|
||||
received: <Tokens Received Rounded Down Number>
|
||||
}
|
||||
}
|
||||
*/
|
||||
module.exports = (args) => {
|
||||
const {id} = args;
|
||||
|
||||
// Exit early when there is a simulated keysend invoice
|
||||
if (!args.is_canceled && args.description_hash === args.secret) {
|
||||
try {
|
||||
const encoded = base64AsHex(args.description);
|
||||
|
||||
return {
|
||||
arguments: {
|
||||
id,
|
||||
messages: decodeTlvStream({encoded}).records,
|
||||
received: args.tokens,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Exit early when the invoice is not settled
|
||||
if (!args.is_confirmed) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Exit early when this was confirmed too long ago
|
||||
if (args.confirmed_at < processAfter()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const htlcs = args.payments.filter(n => !!n.is_confirmed);
|
||||
const {received} = args;
|
||||
|
||||
// Exit early when the invoice has no confirmed HTLCs
|
||||
if (!htlcs.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const [{messages}] = htlcs;
|
||||
|
||||
// Exit early when the first HTLC has no messages
|
||||
if (!messages.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {arguments: {id, messages, received}};
|
||||
};
|
||||
|
|
@ -3,7 +3,7 @@ const {formatTokens} = require('ln-sync');
|
|||
const {getNodeAlias} = require('ln-sync');
|
||||
const {getPayment} = require('ln-service');
|
||||
const {parsePaymentRequest} = require('invoices');
|
||||
const {pay} = require('ln-service');
|
||||
const {payViaPaymentRequest} = require('ln-service');
|
||||
const {returnResult} = require('asyncjs-util');
|
||||
|
||||
const maximumPingPrice = 200;
|
||||
|
|
@ -15,15 +15,16 @@ const tokensAsMillitokens = tok => (BigInt(tok) * BigInt(1e3)).toString();
|
|||
|
||||
{
|
||||
id: <Ping Invoice Id Hex String>
|
||||
lnd: <Authenticated LND API Object>
|
||||
lnd: <Server Authenticated LND API Object>
|
||||
logger: <Winston Logger Object>
|
||||
pay: <Payer Authenticated LND API Object>
|
||||
received: <Received Tokens Rounded Down Number>
|
||||
[request]: <BOLT 11 Encoded Payment Request String>
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
*/
|
||||
module.exports = ({id, lnd, logger, received, request}, cbk) => {
|
||||
module.exports = ({id, lnd, logger, pay, received, request}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
|
|
@ -40,6 +41,10 @@ module.exports = ({id, lnd, logger, received, request}, cbk) => {
|
|||
return cbk([400, 'ExpectedWinstonLoggerToRespondToKeySendPing']);
|
||||
}
|
||||
|
||||
if (!pay) {
|
||||
return cbk([400, 'ExpectedPayerLndToRespondToKeySendPing']);
|
||||
}
|
||||
|
||||
if (received === undefined) {
|
||||
return cbk([400, 'ExpectedReceivedAmountToRespondToKeySendPing']);
|
||||
}
|
||||
|
|
@ -68,7 +73,7 @@ module.exports = ({id, lnd, logger, received, request}, cbk) => {
|
|||
return cbk();
|
||||
}
|
||||
|
||||
return getPayment({lnd, id: parseRequest.id}, (err, res) => {
|
||||
return getPayment({id: parseRequest.id, lnd: pay}, (err, res) => {
|
||||
// Ignore errors on payment lookup
|
||||
if (!!err) {
|
||||
return cbk();
|
||||
|
|
@ -143,13 +148,15 @@ module.exports = ({id, lnd, logger, received, request}, cbk) => {
|
|||
// Exit early when the response ping tokens are not as expected
|
||||
if (parseRequest.mtokens !== tokensAsMillitokens(responsePingTokens)) {
|
||||
logger.warn({received_bad_ping: 'PingResponseTokensValueIncorrect'});
|
||||
|
||||
return cbk();
|
||||
}
|
||||
|
||||
const feeBudget = received - responsePingTokens;
|
||||
|
||||
return pay({
|
||||
lnd,
|
||||
return payViaPaymentRequest({
|
||||
request,
|
||||
lnd: pay,
|
||||
max_fee: received - responsePingTokens,
|
||||
},
|
||||
(err, res) => {
|
||||
|
|
|
|||
|
|
@ -11,18 +11,19 @@ const typePing = '8470534167946609795';
|
|||
|
||||
{
|
||||
id: <Received Payment Invoice Id Hex String>
|
||||
lnd: <Authenticated LND API Object>
|
||||
lnd: <Server Authenticated LND API Object>
|
||||
logger: <Winston Logger Object>
|
||||
messages: [{
|
||||
type: <Message Type Number String>
|
||||
value: <Raw Value Hex String>
|
||||
}]
|
||||
pay: <Payer Authenticated LND API Object>
|
||||
received: <Received Tokens Rounded Down Number>
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
*/
|
||||
module.exports = ({id, lnd, logger, messages, received}, cbk) => {
|
||||
module.exports = ({id, lnd, logger, messages, pay, received}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
|
|
@ -43,6 +44,10 @@ module.exports = ({id, lnd, logger, messages, received}, cbk) => {
|
|||
return cbk([400, 'ExpectedMessagesArrayToRespondToKeySendRequest']);
|
||||
}
|
||||
|
||||
if (!pay) {
|
||||
return cbk([400, 'ExpectedPayerLndToRespondToKeySendRequest']);
|
||||
}
|
||||
|
||||
if (received === undefined) {
|
||||
return cbk([400, 'ExpectedReceivedTokensRespondToKeySendRequest']);
|
||||
}
|
||||
|
|
@ -63,6 +68,7 @@ module.exports = ({id, lnd, logger, messages, received}, cbk) => {
|
|||
id,
|
||||
lnd,
|
||||
logger,
|
||||
pay,
|
||||
received,
|
||||
request: hexAsString(ping.value),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,20 +1,26 @@
|
|||
const asyncAuto = require('async/auto');
|
||||
const {decodeTlvStream} = require('bolt01');
|
||||
const {getInvoices} = require('ln-service');
|
||||
const {getWalletInfo} = require('ln-service');
|
||||
const {returnResult} = require('asyncjs-util');
|
||||
const {subscribeToInvoices} = require('ln-service');
|
||||
|
||||
const keySendRequestArguments = require('./key_send_request_arguments');
|
||||
const respondToKeySendRequest = require('./respond_to_key_send_request');
|
||||
|
||||
const nodeName = (alias, key) => `${alias} ${key}`.trim();
|
||||
|
||||
/** Service keysend services requests
|
||||
|
||||
{
|
||||
lnd: <Authenticated LND API Object>
|
||||
lnd: <Server Authenticated LND API Object>
|
||||
logger: <Winston Logger Object>
|
||||
pay: <Payer Authenticated LND API Object>
|
||||
}
|
||||
|
||||
@returns via cbk or Promise
|
||||
*/
|
||||
module.exports = ({lnd, logger}, cbk) => {
|
||||
module.exports = ({lnd, logger, pay}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
|
|
@ -27,11 +33,21 @@ module.exports = ({lnd, logger}, cbk) => {
|
|||
return cbk([400, 'ExpectedLoggerToServiceKeySendRequests']);
|
||||
}
|
||||
|
||||
if (!pay) {
|
||||
return cbk([400, 'ExpectedPayerLndToServiceKeySendRequests']);
|
||||
}
|
||||
|
||||
return cbk();
|
||||
},
|
||||
|
||||
// Get serving node
|
||||
getServer: ['validate', ({}, cbk) => getWalletInfo({lnd}, cbk)],
|
||||
|
||||
// Get payer info
|
||||
getPayer: ['validate', ({}, cbk) => getWalletInfo({lnd: pay}, cbk)],
|
||||
|
||||
// Listen for service requests
|
||||
listen: ['validate', ({}, cbk) => {
|
||||
listen: ['getPayer', 'getServer', ({getPayer, getServer}, cbk) => {
|
||||
const sub = subscribeToInvoices({lnd});
|
||||
|
||||
// Stop service when there is an error with the connection
|
||||
|
|
@ -41,38 +57,37 @@ module.exports = ({lnd, logger}, cbk) => {
|
|||
serving_keysend_requests: [{
|
||||
type: 'ping',
|
||||
description: 'Send back ping payment requests with a pong payment',
|
||||
serving_from: nodeName(getServer.alias, getServer.public_key),
|
||||
paying_from: nodeName(getPayer.alias, getPayer.public_key),
|
||||
}],
|
||||
});
|
||||
|
||||
const process = async invoice => {
|
||||
// Exit early when the invoice is not settled
|
||||
if (!invoice.is_confirmed) {
|
||||
return;
|
||||
}
|
||||
const {arguments} = keySendRequestArguments({
|
||||
confirmed_at: invoice.confirmed_at,
|
||||
description: invoice.description,
|
||||
description_hash: invoice.description_hash,
|
||||
id: invoice.id,
|
||||
is_canceled: invoice.is_canceled,
|
||||
is_confirmed: invoice.is_confirmed,
|
||||
payments: invoice.payments,
|
||||
received: invoice.received,
|
||||
secret: invoice.secret,
|
||||
tokens: invoice.tokens,
|
||||
});
|
||||
|
||||
const htlcs = invoice.payments.filter(n => !!n.is_confirmed);
|
||||
const {id} = invoice;
|
||||
const {received} = invoice;
|
||||
|
||||
// Exit early when the invoice has no confirmed HTLCs
|
||||
if (!htlcs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit early when the first HTLC has no
|
||||
const [{messages}] = htlcs;
|
||||
|
||||
if (!messages.length) {
|
||||
if (!arguments) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
return await respondToKeySendRequest({
|
||||
id,
|
||||
lnd,
|
||||
logger,
|
||||
messages,
|
||||
received,
|
||||
pay,
|
||||
id: arguments.id,
|
||||
messages: arguments.messages,
|
||||
received: arguments.received,
|
||||
});
|
||||
} catch (err) {
|
||||
return logger.error({err});
|
||||
|
|
|
|||
104
services/simulate_key_send_request.js
Normal file
104
services/simulate_key_send_request.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
const {randomBytes} = require('crypto');
|
||||
|
||||
const asyncAuto = require('async/auto');
|
||||
const {createInvoice} = require('ln-service');
|
||||
const {encodeTlvStream} = require('bolt01');
|
||||
const {returnResult} = require('asyncjs-util');
|
||||
|
||||
const expiry = () => new Date(Date.now() + (1000 * 60 * 5)).toISOString();
|
||||
const hexAsBase64 = hex => Buffer.from(hex, 'hex').toString('base64');
|
||||
const {isArray} = Array;
|
||||
const isHex = n => !!n && !(n.length % 2) && /^[0-9A-F]*$/i.test(n);
|
||||
const makeSecret = () => randomBytes(32).toString('hex');
|
||||
|
||||
/** Simulate a key send request with an invoice that encodes TLV records
|
||||
|
||||
{
|
||||
lnd: <Authenticated LND API Object>
|
||||
tokens: <Tokens Received Number>
|
||||
types: [<Message Type String>]
|
||||
values: [<Value Hex String>]
|
||||
}
|
||||
*/
|
||||
module.exports = ({lnd, tokens, types, values}, cbk) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return asyncAuto({
|
||||
// Check arguments
|
||||
validate: cbk => {
|
||||
if (!lnd) {
|
||||
return cbk([400, 'ExpectedLndToSimulateKeySendRequest']);
|
||||
}
|
||||
|
||||
if (!tokens) {
|
||||
return cbk([400, 'ExpectedTokensAmountToSimulateKeySendRequest']);
|
||||
}
|
||||
|
||||
if (!isArray(types) || !types.length) {
|
||||
return cbk([400, 'ExpectedArrayOfTypesToSimulateKeySendRequest']);
|
||||
}
|
||||
|
||||
if (!isArray(values) || !values.length) {
|
||||
return cbk([400, 'ExpectedArrayOfValuesToSimulateKeySendRequest']);
|
||||
}
|
||||
|
||||
if (types.length !== values.length) {
|
||||
return cbk([400, 'ExpectedEqualNumbersOfTypesToValues']);
|
||||
}
|
||||
|
||||
return cbk();
|
||||
},
|
||||
|
||||
// Map types and values into message records and encode that as TLV
|
||||
description: ['validate', ({}, cbk) => {
|
||||
try {
|
||||
// Zip together type and value arrays into consolidated records
|
||||
const records = types.map((type, i) => {
|
||||
if (!BigInt(type)) {
|
||||
throw new Error('ExpectedTypeNumberForMessages');
|
||||
}
|
||||
|
||||
if (!isHex(values[i])) {
|
||||
throw new Error('ExpectedHexValueForMessages');
|
||||
}
|
||||
|
||||
return {type, value: values[i]};
|
||||
});
|
||||
|
||||
// Encode messages as a BOLT 1 TLV stream
|
||||
const {encoded} = encodeTlvStream({records});
|
||||
|
||||
return cbk(null, hexAsBase64(encoded));
|
||||
} catch (err) {
|
||||
return cbk([400, 'FailedToEncodeRecordsAsTlvStream', {err}]);
|
||||
}
|
||||
}],
|
||||
|
||||
// Create simulated key send invoice
|
||||
createInvoice: ['description', ({description}, cbk) => {
|
||||
// To indicate this is a false invoice, the secret will be used as the
|
||||
// description hash, which is not a normal way to create an invoice and
|
||||
// would be dangerous to do for a public payment request.
|
||||
const secret = makeSecret();
|
||||
|
||||
console.log("CREATE", {
|
||||
description,
|
||||
secret,
|
||||
tokens,
|
||||
description_hash: secret,
|
||||
expires_at: expiry(),
|
||||
})
|
||||
|
||||
return createInvoice({
|
||||
description,
|
||||
lnd,
|
||||
secret,
|
||||
tokens,
|
||||
description_hash: secret,
|
||||
expires_at: expiry(),
|
||||
},
|
||||
cbk);
|
||||
}],
|
||||
},
|
||||
returnResult({reject, resolve}, cbk));
|
||||
});
|
||||
};
|
||||
|
|
@ -362,7 +362,7 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|||
from: ctx.message.from.id,
|
||||
id: connectedId,
|
||||
nodes: getNodes,
|
||||
reply: n => ctx.replyWithMarkdown(n),
|
||||
reply: n => ctx.reply(n),
|
||||
});
|
||||
} catch (err) {
|
||||
return logger.error({err});
|
||||
|
|
@ -388,6 +388,7 @@ module.exports = ({fs, id, limits, lnds, logger, payments, request}, cbk) => {
|
|||
'/liquidity [with] - View node liquidity',
|
||||
'/mempool - BTC mempool report',
|
||||
'/pay - Pay an invoice',
|
||||
'/pending - View pending channels, probes, and forwards',
|
||||
'/version - View the current bot version',
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue