Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc0d2a4c86 | ||
|
|
b125d68fff | ||
|
|
e390a06aae | ||
|
|
c8ef1e59e2 | ||
|
|
3ad92da8a6 | ||
|
|
61956f2a46 | ||
|
|
93899facd6 | ||
|
|
6723094ed6 | ||
|
|
ca1f5427cb | ||
|
|
d4e8d9b476 | ||
|
|
3a2ee779b6 | ||
|
|
ea1035e414 | ||
|
|
7afb56398a | ||
|
|
a4cd81a106 | ||
|
|
7a94225d87 | ||
|
|
9be413a549 | ||
|
|
305559174f | ||
|
|
bfdd319070 | ||
|
|
a6b08363a7 | ||
|
|
9f45c31618 | ||
|
|
d7e91f51ec | ||
|
|
b58e7dac88 | ||
|
|
7b5c6bc7e0 | ||
|
|
f9b2cca0bd | ||
|
|
376a3402bd | ||
|
|
38a3dea8c2 | ||
|
|
cdcd1fdd82 | ||
|
|
f4105292a3 | ||
|
|
6074dc6c2c | ||
|
|
76421f2850 | ||
|
|
f01c533899 | ||
|
|
6b67839414 | ||
|
|
dfe55a4f9f | ||
|
|
14d42a7aed | ||
|
|
a4b24ec00a | ||
|
|
0a0bf5caa3 | ||
|
|
2f1c89bb8f | ||
|
|
243902faad | ||
|
|
03ddddbf6a | ||
|
|
8e06bef3b9 | ||
|
|
b55e0f0327 | ||
|
|
ec9a71f4e9 | ||
|
|
9d8466b595 | ||
|
|
0f6a4d8cba | ||
|
|
b56064a7ba | ||
|
|
6507de9770 | ||
|
|
8f28fd2865 | ||
|
|
013cadc5c8 |
@@ -3,5 +3,5 @@ const config = require('./config');
|
||||
let jayson = require('jayson/promise');
|
||||
let url = require('url');
|
||||
let rpc = url.parse(config.bitcoind.rpc);
|
||||
rpc.timeout = 5000;
|
||||
rpc.timeout = 15000;
|
||||
module.exports = jayson.client.http(rpc);
|
||||
|
||||
86
class/Invo.js
Normal file
86
class/Invo.js
Normal file
@@ -0,0 +1,86 @@
|
||||
var lightningPayReq = require('bolt11');
|
||||
|
||||
export class Invo {
|
||||
constructor(redis, bitcoindrpc, lightning) {
|
||||
this._redis = redis;
|
||||
this._bitcoindrpc = bitcoindrpc;
|
||||
this._lightning = lightning;
|
||||
this._decoded = false;
|
||||
this._bolt11 = false;
|
||||
this._isPaid = null;
|
||||
}
|
||||
|
||||
setInvoice(bolt11) {
|
||||
this._bolt11 = bolt11;
|
||||
}
|
||||
|
||||
async getIsMarkedAsPaidInDatabase() {
|
||||
if (!this._bolt11) throw new Error('bolt11 is not provided');
|
||||
const decoded = lightningPayReq.decode(this._bolt11);
|
||||
let paymentHash = false;
|
||||
for (const tag of decoded.tags) {
|
||||
if (tag.tagName === 'payment_hash') {
|
||||
paymentHash = tag.data;
|
||||
}
|
||||
}
|
||||
if (!paymentHash) throw new Error('Could not find payment hash in invoice tags');
|
||||
return await this._getIsPaymentHashMarkedPaidInDatabase(paymentHash);
|
||||
}
|
||||
|
||||
async markAsPaidInDatabase() {
|
||||
if (!this._bolt11) throw new Error('bolt11 is not provided');
|
||||
const decoded = lightningPayReq.decode(this._bolt11);
|
||||
let paymentHash = false;
|
||||
for (const tag of decoded.tags) {
|
||||
if (tag.tagName === 'payment_hash') {
|
||||
paymentHash = tag.data;
|
||||
}
|
||||
}
|
||||
if (!paymentHash) throw new Error('Could not find payment hash in invoice tags');
|
||||
return await this._setIsPaymentHashPaidInDatabase(paymentHash, true);
|
||||
}
|
||||
|
||||
async markAsUnpaidInDatabase() {
|
||||
if (!this._bolt11) throw new Error('bolt11 is not provided');
|
||||
const decoded = lightningPayReq.decode(this._bolt11);
|
||||
let paymentHash = false;
|
||||
for (const tag of decoded.tags) {
|
||||
if (tag.tagName === 'payment_hash') {
|
||||
paymentHash = tag.data;
|
||||
}
|
||||
}
|
||||
if (!paymentHash) throw new Error('Could not find payment hash in invoice tags');
|
||||
return await this._setIsPaymentHashPaidInDatabase(paymentHash, false);
|
||||
}
|
||||
|
||||
async _setIsPaymentHashPaidInDatabase(paymentHash, isPaid) {
|
||||
if (isPaid) {
|
||||
return await this._redis.set('ispaid_' + paymentHash, 1);
|
||||
} else {
|
||||
return await this._redis.del('ispaid_' + paymentHash);
|
||||
}
|
||||
}
|
||||
|
||||
async _getIsPaymentHashMarkedPaidInDatabase(paymentHash) {
|
||||
return await this._redis.get('ispaid_' + paymentHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries LND ofr all user invoices
|
||||
*
|
||||
* @return {Promise<array>}
|
||||
*/
|
||||
async listInvoices() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._lightning.listInvoices(
|
||||
{
|
||||
num_max_invoices: 9000111,
|
||||
},
|
||||
function(err, response) {
|
||||
if (err) return reject(err);
|
||||
resolve(response);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ export class Paym {
|
||||
var request = {
|
||||
pub_key: this._decoded.destination,
|
||||
amt: this._decoded.num_satoshis,
|
||||
num_routes: 1,
|
||||
final_cltv_delta: 144,
|
||||
fee_limit: { fixed: Math.floor(this._decoded.num_satoshis * 0.01) + 1 },
|
||||
};
|
||||
@@ -57,9 +56,11 @@ export class Paym {
|
||||
|
||||
let request = {
|
||||
payment_hash_string: this._decoded.payment_hash,
|
||||
routes: routes,
|
||||
route: routes[0],
|
||||
};
|
||||
|
||||
console.log('sendToRouteSync:', { request });
|
||||
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._lightning.sendToRouteSync(request, function(err, response) {
|
||||
|
||||
@@ -212,6 +212,8 @@ export class User {
|
||||
|
||||
/**
|
||||
* Doent belong here, FIXME
|
||||
* @see Invo._setIsPaymentHashPaidInDatabase
|
||||
* @see Invo.markAsPaidInDatabase
|
||||
*/
|
||||
async setPaymentHashPaid(payment_hash) {
|
||||
return await this._redis.set('ispaid_' + payment_hash, 1);
|
||||
@@ -229,13 +231,29 @@ export class User {
|
||||
|
||||
/**
|
||||
* Doent belong here, FIXME
|
||||
* @see Invo._getIsPaymentHashMarkedPaidInDatabase
|
||||
* @see Invo.getIsMarkedAsPaidInDatabase
|
||||
*/
|
||||
async getPaymentHashPaid(payment_hash) {
|
||||
return await this._redis.get('ispaid_' + payment_hash);
|
||||
}
|
||||
|
||||
async getUserInvoices() {
|
||||
async syncInvoicePaid(payment_hash) {
|
||||
const invoice = await this.lookupInvoice(payment_hash);
|
||||
const ispaid = invoice.settled; // TODO: start using `state` instead as its future proof, and this one might get deprecated
|
||||
if (ispaid) {
|
||||
// so invoice was paid after all
|
||||
await this.setPaymentHashPaid(payment_hash);
|
||||
await this.clearBalanceCache();
|
||||
}
|
||||
return ispaid;
|
||||
}
|
||||
|
||||
async getUserInvoices(limit) {
|
||||
let range = await this._redis.lrange('userinvoices_for_' + this._userid, 0, -1);
|
||||
if (limit && !isNaN(parseInt(limit))) {
|
||||
range = range.slice(parseInt(limit) * -1);
|
||||
}
|
||||
let result = [];
|
||||
for (let invoice of range) {
|
||||
invoice = JSON.parse(invoice);
|
||||
@@ -243,7 +261,11 @@ export class User {
|
||||
invoice.description = '';
|
||||
for (let tag of decoded.tags) {
|
||||
if (tag.tagName === 'description') {
|
||||
invoice.description += decodeURIComponent(tag.data);
|
||||
try {
|
||||
invoice.description += decodeURIComponent(tag.data);
|
||||
} catch (_) {
|
||||
invoice.description += tag.data;
|
||||
}
|
||||
}
|
||||
if (tag.tagName === 'payment_hash') {
|
||||
invoice.payment_hash = tag.data;
|
||||
@@ -254,20 +276,14 @@ export class User {
|
||||
if (!invoice.ispaid) {
|
||||
if (decoded && decoded.timestamp > +new Date() / 1000 - 3600 * 24 * 5) {
|
||||
// if invoice is not too old we query lnd to find out if its paid
|
||||
let lookup_info = await this.lookupInvoice(invoice.payment_hash);
|
||||
invoice.ispaid = lookup_info.settled; // TODO: start using `state` instead as its future proof, and this one might get deprecated
|
||||
if (invoice.ispaid) {
|
||||
// so invoice was paid after all
|
||||
await this.setPaymentHashPaid(invoice.payment_hash);
|
||||
await this.clearBalanceCache();
|
||||
}
|
||||
invoice.ispaid = await this.syncInvoicePaid(invoice.payment_hash);
|
||||
}
|
||||
} else {
|
||||
_invoice_ispaid_cache[invoice.payment_hash] = true;
|
||||
}
|
||||
|
||||
invoice.amt = decoded.satoshis;
|
||||
invoice.expire_time = 3600;
|
||||
invoice.expire_time = 3600 * 24;
|
||||
// ^^^default; will keep for now. if we want to un-hardcode it - it should be among tags (`expire_time`)
|
||||
invoice.timestamp = decoded.timestamp;
|
||||
invoice.type = 'user_invoice';
|
||||
@@ -313,6 +329,13 @@ export class User {
|
||||
if (invoice.payment_route) {
|
||||
invoice.fee = +invoice.payment_route.total_fees;
|
||||
invoice.value = +invoice.payment_route.total_fees + +invoice.payment_route.total_amt;
|
||||
if (invoice.payment_route.total_amt_msat && invoice.payment_route.total_amt_msat / 1000 !== +invoice.payment_route.total_amt) {
|
||||
// okay, we have to account for MSAT
|
||||
invoice.value =
|
||||
+invoice.payment_route.total_fees +
|
||||
Math.max(parseInt(invoice.payment_route.total_amt_msat / 1000), +invoice.payment_route.total_amt) +
|
||||
1; // extra sat to cover for msats, as external layer (clients) dont have that resolution
|
||||
}
|
||||
} else {
|
||||
invoice.fee = 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './User';
|
||||
export * from './Lock';
|
||||
export * from './Paym';
|
||||
export * from './Invo';
|
||||
|
||||
@@ -20,12 +20,12 @@ let identity_pubkey = false;
|
||||
|
||||
bitcoinclient.request('getblockchaininfo', false, function(err, info) {
|
||||
if (info && info.result && info.result.blocks) {
|
||||
if (info.result.blocks < 550000) {
|
||||
if (info.result.chain === 'mainnet' && info.result.blocks < 550000) {
|
||||
console.error('bitcoind is not caught up');
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
console.error('bitcoind failure');
|
||||
console.error('bitcoind failure:', err, info);
|
||||
process.exit(2);
|
||||
}
|
||||
});
|
||||
@@ -33,9 +33,11 @@ bitcoinclient.request('getblockchaininfo', false, function(err, info) {
|
||||
lightning.getInfo({}, function(err, info) {
|
||||
if (err) {
|
||||
console.error('lnd failure');
|
||||
console.dir(err);
|
||||
process.exit(3);
|
||||
}
|
||||
if (info) {
|
||||
console.info(info);
|
||||
if (!info.synced_to_chain) {
|
||||
console.error('lnd not synced');
|
||||
process.exit(4);
|
||||
@@ -56,7 +58,7 @@ redis.info(function(err, info) {
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const postLimiter = rateLimit({
|
||||
windowMs: 30 * 60 * 1000,
|
||||
max: 50,
|
||||
max: 100,
|
||||
});
|
||||
|
||||
router.post('/create', postLimiter, async function(req, res) {
|
||||
@@ -128,10 +130,17 @@ router.post('/payinvoice', async function(req, res) {
|
||||
// obtaining a lock
|
||||
let lock = new Lock(redis, 'invoice_paying_for_' + u.getUserId());
|
||||
if (!(await lock.obtainLock())) {
|
||||
return errorTryAgainLater(res);
|
||||
return errorGeneralServerError(res);
|
||||
}
|
||||
|
||||
let userBalance = await u.getCalculatedBalance();
|
||||
let userBalance;
|
||||
try {
|
||||
userBalance = await u.getCalculatedBalance();
|
||||
} catch (Error) {
|
||||
logger.log('', [req.id, 'error running getCalculatedBalance():', Error.message]);
|
||||
lock.releaseLock();
|
||||
return errorTryAgainLater(res);
|
||||
}
|
||||
|
||||
lightning.decodePayReq({ pay_req: req.body.invoice }, async function(err, info) {
|
||||
if (err) {
|
||||
@@ -206,7 +215,7 @@ router.post('/payinvoice', async function(req, res) {
|
||||
return errorPaymentFailed(res);
|
||||
}
|
||||
});
|
||||
if (!info.num_satoshis && !info.num_satoshis) {
|
||||
if (!info.num_satoshis) {
|
||||
// tip invoice, but someone forgot to specify amount
|
||||
await lock.releaseLock();
|
||||
return errorBadArguments(res);
|
||||
@@ -248,18 +257,40 @@ router.get('/getbtc', async function(req, res) {
|
||||
res.send([{ address }]);
|
||||
});
|
||||
|
||||
router.get('/balance', postLimiter, async function(req, res) {
|
||||
logger.log('/balance', [req.id]);
|
||||
router.get('/checkpayment/:payment_hash', async function(req, res) {
|
||||
logger.log('/checkpayment', [req.id]);
|
||||
let u = new User(redis, bitcoinclient, lightning);
|
||||
if (!(await u.loadByAuthorization(req.headers.authorization))) {
|
||||
await u.loadByAuthorization(req.headers.authorization);
|
||||
|
||||
if (!u.getUserId()) {
|
||||
return errorBadAuth(res);
|
||||
}
|
||||
|
||||
if (!(await u.getAddress())) await u.generateAddress(); // onchain address needed further
|
||||
await u.accountForPosibleTxids();
|
||||
let balance = await u.getBalance();
|
||||
if (balance < 0) balance = 0;
|
||||
res.send({ BTC: { AvailableBalance: balance } });
|
||||
let paid = true;
|
||||
if (!(await u.getPaymentHashPaid(req.params.payment_hash))) { // Not found on cache
|
||||
paid = await u.syncInvoicePaid(req.params.payment_hash);
|
||||
}
|
||||
res.send({paid: paid});
|
||||
});
|
||||
|
||||
router.get('/balance', postLimiter, async function(req, res) {
|
||||
try {
|
||||
logger.log('/balance', [req.id]);
|
||||
let u = new User(redis, bitcoinclient, lightning);
|
||||
if (!(await u.loadByAuthorization(req.headers.authorization))) {
|
||||
return errorBadAuth(res);
|
||||
}
|
||||
logger.log('/balance', [req.id, 'userid: ' + u.getUserId()]);
|
||||
|
||||
if (!(await u.getAddress())) await u.generateAddress(); // onchain address needed further
|
||||
await u.accountForPosibleTxids();
|
||||
let balance = await u.getBalance();
|
||||
if (balance < 0) balance = 0;
|
||||
res.send({ BTC: { AvailableBalance: balance } });
|
||||
} catch (Error) {
|
||||
logger.log('', [req.id, 'error getting balance:', Error.message, 'userid:', u.getUserId()]);
|
||||
return errorGeneralServerError(res);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/getinfo', postLimiter, async function(req, res) {
|
||||
@@ -281,6 +312,7 @@ router.get('/gettxs', async function(req, res) {
|
||||
if (!(await u.loadByAuthorization(req.headers.authorization))) {
|
||||
return errorBadAuth(res);
|
||||
}
|
||||
logger.log('/gettxs', [req.id, 'userid: ' + u.getUserId()]);
|
||||
|
||||
if (!(await u.getAddress())) await u.generateAddress(); // onchain addr needed further
|
||||
try {
|
||||
@@ -298,27 +330,24 @@ router.get('/gettxs', async function(req, res) {
|
||||
}
|
||||
res.send(txs);
|
||||
} catch (Err) {
|
||||
logger.log('', [req.id, 'error:', Err]);
|
||||
logger.log('', [req.id, 'error gettxs:', Err.message, 'userid:', u.getUserId()]);
|
||||
res.send([]);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/getuserinvoices', async function(req, res) {
|
||||
router.get('/getuserinvoices', postLimiter, async function(req, res) {
|
||||
logger.log('/getuserinvoices', [req.id]);
|
||||
let u = new User(redis, bitcoinclient, lightning);
|
||||
if (!(await u.loadByAuthorization(req.headers.authorization))) {
|
||||
return errorBadAuth(res);
|
||||
}
|
||||
logger.log('/getuserinvoices', [req.id, 'userid: ' + u.getUserId()]);
|
||||
|
||||
try {
|
||||
let invoices = await u.getUserInvoices();
|
||||
if (req.query.limit && !isNaN(parseInt(req.query.limit))) {
|
||||
res.send(invoices.slice(parseInt(req.query.limit) * -1));
|
||||
} else {
|
||||
res.send(invoices);
|
||||
}
|
||||
let invoices = await u.getUserInvoices(req.query.limit);
|
||||
res.send(invoices);
|
||||
} catch (Err) {
|
||||
logger.log('', [req.id, 'error:', Err]);
|
||||
logger.log('', [req.id, 'error getting user invoices:', Err.message, 'userid:', u.getUserId()]);
|
||||
res.send([]);
|
||||
}
|
||||
});
|
||||
@@ -329,6 +358,7 @@ router.get('/getpending', async function(req, res) {
|
||||
if (!(await u.loadByAuthorization(req.headers.authorization))) {
|
||||
return errorBadAuth(res);
|
||||
}
|
||||
logger.log('/getpending', [req.id, 'userid: ' + u.getUserId()]);
|
||||
|
||||
if (!(await u.getAddress())) await u.generateAddress(); // onchain address needed further
|
||||
await u.accountForPosibleTxids();
|
||||
@@ -408,7 +438,7 @@ function errorGeneralServerError(res) {
|
||||
return res.send({
|
||||
error: true,
|
||||
code: 6,
|
||||
message: 'Server fault',
|
||||
message: 'Something went wrong. Please try again later',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ function updateLightning() {
|
||||
lightningListChannels = response;
|
||||
let channels = [];
|
||||
for (let channel of lightningListChannels.channels) {
|
||||
let divider = 524287;
|
||||
let divider = 5242870;
|
||||
let ascii_length1 = channel.local_balance / divider;
|
||||
let ascii_length2 = channel.remote_balance / divider;
|
||||
channel.ascii = '[';
|
||||
@@ -70,6 +70,12 @@ const pubkey2name = {
|
||||
'02a0bc43557fae6af7be8e3a29fdebda819e439bea9c0f8eb8ed6a0201f3471ca9': 'LightningPeachHub',
|
||||
'02d4531a2f2e6e5a9033d37d548cff4834a3898e74c3abe1985b493c42ebbd707d': 'coinfinity.co',
|
||||
'02d23fa6794d8fd056c757f3c8f4877782138dafffedc831fc570cab572620dc61': 'paywithmoon.com',
|
||||
'025f1456582e70c4c06b61d5c8ed3ce229e6d0db538be337a2dc6d163b0ebc05a5': 'paywithmoon.com',
|
||||
'02004c625d622245606a1ea2c1c69cfb4516b703b47945a3647713c05fe4aaeb1c': 'walletofsatoshi',
|
||||
'0331f80652fb840239df8dc99205792bba2e559a05469915804c08420230e23c7c': 'LightningPowerUsers.com',
|
||||
'033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025': 'bfx-lnd0',
|
||||
'03021c5f5f57322740e4ee6936452add19dc7ea7ccf90635f95119ab82a62ae268': 'lnd1.bluewallet.io',
|
||||
'037cc5f9f1da20ac0d60e83989729a204a33cc2d8e80438969fadf35c1c5f1233b': 'lnd2.bluewallet.io',
|
||||
};
|
||||
|
||||
router.get('/', function(req, res) {
|
||||
|
||||
18
doc/recover.md
Normal file
18
doc/recover.md
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
recover user's wallet
|
||||
=====================
|
||||
|
||||
* find user's id
|
||||
f0db84e6fd5dee530314fbb90cec24839f4620914e7cd0c7
|
||||
* issue new credentials via tests/integration/LightningCustodianWallet.test.js
|
||||
lndhub://3d7c028419356d017199:66666666666666666666
|
||||
(this is user:password)
|
||||
* lookup redis record `user_{login}_{password_hash} = {userid}` :
|
||||
```
|
||||
> keys user_3d7c028419356d017199*
|
||||
1) "user_3d7c028419356d017199_505018e35414147406fcacdae63babbfca9b1abfcb6d091a4cca9a7611183284"
|
||||
```
|
||||
|
||||
* save to this record old user's id:
|
||||
`> set user_3d7c028419356d017199_505018e35414147406fcacdae63babbfca9b1abfcb6d091a4cca9a7611183284 f0db84e6fd5dee530314fbb90cec24839f4620914e7cd0c7`
|
||||
done! issued credentials should point to old user
|
||||
2
index.js
2
index.js
@@ -19,7 +19,7 @@ app.enable('trust proxy');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const limiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 100,
|
||||
max: 200,
|
||||
});
|
||||
app.use(limiter);
|
||||
|
||||
|
||||
1206
package-lock.json
generated
1206
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "LndHub",
|
||||
"version": "1.1.3",
|
||||
"version": "1.2.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -14,25 +14,25 @@
|
||||
"dependencies": {
|
||||
"babel": "^6.23.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-register": "^6.26.0",
|
||||
"bignumber.js": "^8.0.1",
|
||||
"bolt11": "https://github.com/bitcoinjs/bolt11",
|
||||
"eslint": "^5.9.0",
|
||||
"eslint-config-prettier": "^3.3.0",
|
||||
"eslint-plugin-prettier": "^3.0.0",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bolt11": "^1.2.6",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.10.1",
|
||||
"eslint-plugin-prettier": "^3.1.2",
|
||||
"express": "^4.16.4",
|
||||
"express-rate-limit": "^3.4.0",
|
||||
"express-rate-limit": "^5.0.0",
|
||||
"grpc": "^1.17.0-pre1",
|
||||
"ioredis": "^4.2.0",
|
||||
"jayson": "^2.1.0",
|
||||
"ioredis": "^4.16.2",
|
||||
"jayson": "^3.1.2",
|
||||
"morgan": "^1.9.1",
|
||||
"mustache": "^3.0.1",
|
||||
"mustache": "^4.0.1",
|
||||
"node-uuid": "^1.4.8",
|
||||
"prettier": "^1.15.3",
|
||||
"prettier": "^2.0.4",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"winston": "^3.1.0"
|
||||
|
||||
@@ -1,15 +1,54 @@
|
||||
let important_channels = {
|
||||
'02d23fa6794d8fd056c757f3c8f4877782138dafffedc831fc570cab572620dc61': 'paywithmoon.com',
|
||||
'03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f': 'ACINQ',
|
||||
'03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e': 'OpenNode',
|
||||
'0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3': 'coingate.com',
|
||||
'0254ff808f53b2f8c45e74b70430f336c6c76ba2f4af289f48d6086ae6e60462d3': 'bitrefill thor',
|
||||
'025f1456582e70c4c06b61d5c8ed3ce229e6d0db538be337a2dc6d163b0ebc05a5': 'paywithmoon.com',
|
||||
'02c91d6aa51aa940608b497b6beebcb1aec05be3c47704b682b3889424679ca490': 'lnbig 21',
|
||||
'0279c22ed7a068d10dc1a38ae66d2d6461e269226c60258c021b1ddcdfe4b00bc4': 'ln1.satoshilabs.com',
|
||||
'026c7d28784791a4b31a64eb34d9ab01552055b795919165e6ae886de637632efb': 'LivingRoomOfSatoshi',
|
||||
'02816caed43171d3c9854e3b0ab2cf0c42be086ff1bd4005acc2a5f7db70d83774': 'ln.pizza',
|
||||
const important_channels = {
|
||||
'03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f': {
|
||||
name: 'ACINQ',
|
||||
uri: '03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f@34.239.230.56:9735',
|
||||
},
|
||||
'03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e': {
|
||||
name: 'OpenNode',
|
||||
uri: '03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e@18.221.23.28:9735',
|
||||
wumbo: 1,
|
||||
},
|
||||
'0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3': {
|
||||
name: 'coingate.com',
|
||||
uri: '0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3@3.124.63.44:9735',
|
||||
},
|
||||
'0254ff808f53b2f8c45e74b70430f336c6c76ba2f4af289f48d6086ae6e60462d3': {
|
||||
name: 'bitrefill thor',
|
||||
uri: '0254ff808f53b2f8c45e74b70430f336c6c76ba2f4af289f48d6086ae6e60462d3@52.30.63.2:9735',
|
||||
wumbo: 1,
|
||||
},
|
||||
'030c3f19d742ca294a55c00376b3b355c3c90d61c6b6b39554dbc7ac19b141c14f': {
|
||||
name: 'bitrefill 2',
|
||||
uri: '030c3f19d742ca294a55c00376b3b355c3c90d61c6b6b39554dbc7ac19b141c14f@52.50.244.44:9735',
|
||||
wumbo: 1,
|
||||
},
|
||||
'025f1456582e70c4c06b61d5c8ed3ce229e6d0db538be337a2dc6d163b0ebc05a5': {
|
||||
name: 'paywithmoon.com',
|
||||
uri: '025f1456582e70c4c06b61d5c8ed3ce229e6d0db538be337a2dc6d163b0ebc05a5@52.86.210.65:9735',
|
||||
},
|
||||
'0279c22ed7a068d10dc1a38ae66d2d6461e269226c60258c021b1ddcdfe4b00bc4': {
|
||||
name: 'ln1.satoshilabs.com',
|
||||
uri: '0279c22ed7a068d10dc1a38ae66d2d6461e269226c60258c021b1ddcdfe4b00bc4@157.230.28.160:9735',
|
||||
},
|
||||
'02004c625d622245606a1ea2c1c69cfb4516b703b47945a3647713c05fe4aaeb1c': {
|
||||
name: 'LivingRoomOfSatoshi',
|
||||
uri: '02004c625d622245606a1ea2c1c69cfb4516b703b47945a3647713c05fe4aaeb1c@172.81.178.151:9735',
|
||||
},
|
||||
'02816caed43171d3c9854e3b0ab2cf0c42be086ff1bd4005acc2a5f7db70d83774': {
|
||||
name: 'ln.pizza aka fold',
|
||||
uri: '02816caed43171d3c9854e3b0ab2cf0c42be086ff1bd4005acc2a5f7db70d83774@35.238.153.25:9735',
|
||||
wumbo: 1,
|
||||
},
|
||||
'0331f80652fb840239df8dc99205792bba2e559a05469915804c08420230e23c7c': {
|
||||
name: 'LightningPowerUsers.com',
|
||||
uri: '0331f80652fb840239df8dc99205792bba2e559a05469915804c08420230e23c7c@34.200.181.109:9735',
|
||||
},
|
||||
'033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025': {
|
||||
name: 'bfx-lnd0',
|
||||
uri: '033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025@34.65.85.39:9735',
|
||||
},
|
||||
};
|
||||
|
||||
let lightning = require('../lightning');
|
||||
|
||||
lightning.listChannels({}, function(err, response) {
|
||||
@@ -20,12 +59,12 @@ lightning.listChannels({}, function(err, response) {
|
||||
}
|
||||
let lightningListChannels = response;
|
||||
for (let channel of lightningListChannels.channels) {
|
||||
if (0 && channel.capacity < 5000000) {
|
||||
if (channel.capacity < 0.05 / 100000000) {
|
||||
console.log(
|
||||
'lncli closechannel',
|
||||
channel.channel_point.replace(':', ' '),
|
||||
(!channel.active && '--force') || '',
|
||||
'#',
|
||||
'; sleep 10 #',
|
||||
'low capacity channel',
|
||||
channel.capacity / 100000000,
|
||||
'btc',
|
||||
@@ -33,7 +72,27 @@ lightning.listChannels({}, function(err, response) {
|
||||
}
|
||||
}
|
||||
|
||||
for (let important of Object.keys(important_channels)) {
|
||||
console.log('# reconnect important channels that are inactive:\n');
|
||||
|
||||
for (const important of Object.keys(important_channels)) {
|
||||
for (let channel of lightningListChannels.channels) {
|
||||
if (channel.remote_pubkey === important && !channel.active) {
|
||||
console.log(
|
||||
'lncli disconnect',
|
||||
channel.remote_pubkey,
|
||||
'; sleep 5;',
|
||||
'lncli connect',
|
||||
important_channels[channel.remote_pubkey].uri,
|
||||
'#',
|
||||
important_channels[channel.remote_pubkey].name,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n# open important channels:\n');
|
||||
|
||||
for (const important of Object.keys(important_channels)) {
|
||||
let atLeastOneChannelIsSufficientCapacity = false;
|
||||
for (let channel of lightningListChannels.channels) {
|
||||
if (channel.remote_pubkey === important && channel.local_balance >= 4000000 && channel.active) {
|
||||
@@ -42,7 +101,19 @@ lightning.listChannels({}, function(err, response) {
|
||||
}
|
||||
|
||||
if (!atLeastOneChannelIsSufficientCapacity) {
|
||||
console.log('lncli openchannel --node_key ', important, '--local_amt 16777215', '#', important_channels[important]);
|
||||
console.log(
|
||||
'lncli disconnect',
|
||||
important,
|
||||
'; sleep 3;',
|
||||
'lncli openchannel --node_key',
|
||||
important,
|
||||
'--connect',
|
||||
important_channels[important].uri.split('@')[1],
|
||||
'--local_amt',
|
||||
important_channels[important].wumbo ? '167772150' : '16777215',
|
||||
'#',
|
||||
important_channels[important].name,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
/**
|
||||
* This script gets all locked payments from our database and cross-checks them with actual
|
||||
* sentout payments from LND. If locked payment is in there we moe locked payment to array of real payments for the user
|
||||
* (it is effectively spent coins by user), if not - we attempt to pay it again (if it is not too old).
|
||||
*/
|
||||
import { User, Lock, Paym } from '../class/';
|
||||
const config = require('../config');
|
||||
|
||||
const fs = require('fs');
|
||||
var Redis = require('ioredis');
|
||||
var redis = new Redis(config.redis);
|
||||
|
||||
@@ -15,6 +21,7 @@ let lightning = require('../lightning');
|
||||
let tempPaym = new Paym(redis, bitcoinclient, lightning);
|
||||
let listPayments = await tempPaym.listPayments();
|
||||
console.log('done', 'got', listPayments['payments'].length, 'payments');
|
||||
fs.writeFileSync('listPayments.json', JSON.stringify(listPayments['payments'], null, 2));
|
||||
|
||||
for (let key of keys) {
|
||||
const userid = key.replace('locked_payments_for_', '');
|
||||
@@ -34,6 +41,7 @@ let lightning = require('../lightning');
|
||||
if (daysPassed < 2) {
|
||||
// if (!await payment.isExpired()) {
|
||||
let sendResult;
|
||||
console.log('attempting to pay to route');
|
||||
try {
|
||||
sendResult = await payment.attemptPayToRoute();
|
||||
} catch (_) {
|
||||
|
||||
35
scripts/process-unpaid-invoices.js
Normal file
35
scripts/process-unpaid-invoices.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* This script goes through all user invoices in LND and if it is settled - marks it
|
||||
* so in our database. Does this only for invoices younger than week. *
|
||||
*/
|
||||
import { Invo } from '../class/';
|
||||
const config = require('../config');
|
||||
|
||||
const fs = require('fs');
|
||||
const Redis = require('ioredis');
|
||||
const redis = new Redis(config.redis);
|
||||
|
||||
let bitcoinclient = require('../bitcoin');
|
||||
let lightning = require('../lightning');
|
||||
|
||||
(async () => {
|
||||
console.log('fetching listinvoices...');
|
||||
let tempInv = new Invo(redis, bitcoinclient, lightning);
|
||||
|
||||
let listinvoices = await tempInv.listInvoices();
|
||||
console.log('done', 'got', listinvoices['invoices'].length, 'invoices');
|
||||
fs.writeFileSync('listInvoices.json', JSON.stringify(listinvoices['invoices'], null, 2));
|
||||
|
||||
let markedInvoices = 0;
|
||||
for (const invoice of listinvoices['invoices']) {
|
||||
if (invoice.state === 'SETTLED' && +invoice.creation_date >= +new Date() / 1000 - 3600 * 24 * 7) {
|
||||
tempInv.setInvoice(invoice.payment_request);
|
||||
await tempInv.markAsPaidInDatabase();
|
||||
markedInvoices++;
|
||||
process.stdout.write(markedInvoices + '\r');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('done, marked', markedInvoices, 'invoices');
|
||||
process.exit();
|
||||
})();
|
||||
@@ -62,9 +62,18 @@
|
||||
<pre class="line"><span class="dyer-white">num_active_channels:</span></pre>
|
||||
<pre class="line">{{num_active_channels}}</pre>
|
||||
<pre class="line"> </pre>
|
||||
<pre class="line"><span class="dyer-white">num_pending_channels:</span></pre>
|
||||
<pre class="line">{{num_pending_channels}}</pre>
|
||||
<pre class="line"> </pre>
|
||||
<pre class="line"><span class="dyer-white">num_peers:</span></pre>
|
||||
<pre class="line">{{num_peers}}</pre>
|
||||
<pre class="line"> </pre>
|
||||
<pre class="line"><span class="dyer-white">block_height:</span></pre>
|
||||
<pre class="line">{{block_height}}</pre>
|
||||
<pre class="line"> </pre>
|
||||
<pre class="line"><span class="dyer-white">synced_to_chain:</span></pre>
|
||||
<pre class="line">{{synced_to_chain}}</pre>
|
||||
<pre class="line"> </pre>
|
||||
<pre class="line"><span class="dyer-white">version:</span></pre>
|
||||
<pre class="line">{{version}}</pre>
|
||||
<pre class="line"> </pre>
|
||||
|
||||
@@ -37,10 +37,6 @@ if (!fs.existsSync('logs')) {
|
||||
fs.mkdirSync('logs');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} label group label
|
||||
* @param {string} message log message
|
||||
*/
|
||||
function log(label, message) {
|
||||
logger.log({
|
||||
level: 'info',
|
||||
|
||||
Reference in New Issue
Block a user