Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
688798024c | ||
|
|
66a54570c5 | ||
|
|
e42ef3a85e | ||
|
|
600556f84c | ||
|
|
a01a8c6e14 | ||
|
|
e9c6f3abde | ||
|
|
7f9463bbbc | ||
|
|
1b1fe8f08b | ||
|
|
28dd3a847a | ||
|
|
a28eead0ab | ||
|
|
87afa20019 | ||
|
|
067f6d6667 | ||
|
|
957d6c5951 | ||
|
|
d3df6aab05 | ||
|
|
4e8ce5e46f | ||
|
|
1fd24b640e | ||
|
|
c47211f984 | ||
|
|
5223edc2b7 | ||
|
|
92e626508c | ||
|
|
3e2c31f429 | ||
|
|
376d61f81d | ||
|
|
1bb781270c | ||
|
|
c0716bc6e9 | ||
|
|
358f858ad8 | ||
|
|
7a6e8a2940 | ||
|
|
96e82ad20d | ||
|
|
406afef7f7 | ||
|
|
3ebe1938ab | ||
|
|
ee2398f247 | ||
|
|
bc84429b61 | ||
|
|
ec3039d91d | ||
|
|
1483449529 | ||
|
|
e0f037ea95 | ||
|
|
b4f880b35d | ||
|
|
35fe816d0a | ||
|
|
4a4daccecd | ||
|
|
66b9d3ab92 | ||
|
|
87fc5d6ff7 | ||
|
|
e6b1f950f3 | ||
|
|
eab49fde2f | ||
|
|
aa11daf608 | ||
|
|
4e7731ff54 | ||
|
|
1c8232d1ec | ||
|
|
fd6caf859c | ||
|
|
df6412a525 | ||
|
|
c46c1385c6 | ||
|
|
dd5d96aa56 | ||
|
|
d6d563039e | ||
|
|
f5eb5d0c78 | ||
|
|
9d17ceb23f | ||
|
|
d0406afd31 | ||
|
|
6411e9bd28 | ||
|
|
db218ef440 | ||
|
|
735b65dc0f | ||
|
|
c73d762028 | ||
|
|
4f3dff6022 | ||
|
|
a792432700 | ||
|
|
590bccd4c0 | ||
|
|
d90881771c | ||
|
|
d9d75a0b29 | ||
|
|
34ffd59c1b | ||
|
|
7dce6b848e | ||
|
|
0d337bdc7b | ||
|
|
f0bf066cfd | ||
|
|
f0ad86f1b9 | ||
|
|
12d1e9560f | ||
|
|
1eaf6c5a47 | ||
|
|
dfcaac2cfa | ||
|
|
f11c02d2f2 | ||
|
|
a4eedde3fb | ||
|
|
597615209b | ||
|
|
5fc7b074f9 |
19
README.md
19
README.md
@@ -1,7 +1,7 @@
|
|||||||
LndHub
|
LndHub
|
||||||
======
|
======
|
||||||
|
|
||||||
Wrapper for Lightning Network Daemon. It provides separate accounts with minimum trust for end users
|
Wrapper for Lightning Network Daemon (lnd). It provides separate accounts with minimum trust for end users.
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
------------
|
------------
|
||||||
@@ -17,15 +17,17 @@ cd LndHub
|
|||||||
npm i
|
npm i
|
||||||
```
|
```
|
||||||
|
|
||||||
Install `bitcoind`, `lnd` and `redis`. Edit `config.js` and set it up correctly.
|
Install `bitcoind`, `lnd`, and `redis`. Edit LndHub's `config.js` to set it up correctly.
|
||||||
Copy `admin.macaroon` and `tls.cert` in root folder of LndHub.
|
Copy the files `admin.macaroon` (for Bitcoin mainnet, usually stored in `~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon`)
|
||||||
|
and `tls.cert` (usually stored in `~/.lnd/tls.cert`) into the root folder of LndHub.
|
||||||
|
|
||||||
`bitcoind` should run with `-deprecatedrpc=accounts`, for now. Lndhub expects Lnd's wallet to be unlocked, if not - it will attempt to unlock it with password stored in `config.lnd.password`.
|
LndHub expects LND's wallet to be unlocked, if not — it will attempt to unlock it with the password stored in `config.lnd.password`.
|
||||||
Don't forget to enable disk-persistance for `redis`.
|
Don't forget to configure disk-persistence for `redis` (e.g., you may want to set `appendonly` to `yes` in `redis.conf` (see
|
||||||
|
http://redis.io/topics/persistence for more information).
|
||||||
|
|
||||||
If you have no `bitcoind` instance, for example if you use neutrino, or you have no bitcoind wallet,
|
If you have no `bitcoind` instance, for example if you use neutrino, or you have no bitcoind wallet,
|
||||||
for example if you use LND for wallet managment, you can remove the bitcoind settings from `config.js`.
|
for example if you use LND for wallet managment, you can remove the bitcoind settings from `config.js`.
|
||||||
Please not that this feature is limited to Bitcoin, so you can't use this feature if you use any other cryptocurrency with LND.
|
Please note that this feature is limited to Bitcoin, so you can't use it if you use any other cryptocurrency with LND (e.g., Litecoin).
|
||||||
|
|
||||||
### Deploy to Heroku
|
### Deploy to Heroku
|
||||||
|
|
||||||
@@ -44,7 +46,8 @@ You can also view Umbrel's implementation using docker-compose [here](https://gi
|
|||||||
|
|
||||||
Can be used in ReactNative or Nodejs environment
|
Can be used in ReactNative or Nodejs environment
|
||||||
|
|
||||||
* https://github.com/BlueWallet/BlueWallet/blob/master/class/lightning-custodian-wallet.js
|
* https://github.com/BlueWallet/BlueWallet/blob/master/class/wallets/lightning-custodian-wallet.js
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
@@ -57,5 +60,5 @@ Acceptance tests are in https://github.com/BlueWallet/BlueWallet/blob/master/Lig
|
|||||||
|
|
||||||
## Responsible disclosure
|
## Responsible disclosure
|
||||||
|
|
||||||
Found critical bugs/vulnerabilities? Please email them bluewallet@bluewallet.io
|
Found critical bugs/vulnerabilities? Please email them to bluewallet@bluewallet.io
|
||||||
Thanks!
|
Thanks!
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ export class Paym {
|
|||||||
this._isPaid = null;
|
this._isPaid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get fee() {
|
|
||||||
return 0.003;
|
|
||||||
}
|
|
||||||
|
|
||||||
setInvoice(bolt11) {
|
setInvoice(bolt11) {
|
||||||
this._bolt11 = bolt11;
|
this._bolt11 = bolt11;
|
||||||
}
|
}
|
||||||
@@ -39,7 +35,7 @@ export class Paym {
|
|||||||
pub_key: this._decoded.destination,
|
pub_key: this._decoded.destination,
|
||||||
amt: this._decoded.num_satoshis,
|
amt: this._decoded.num_satoshis,
|
||||||
final_cltv_delta: 144,
|
final_cltv_delta: 144,
|
||||||
fee_limit: { fixed: Math.floor(this._decoded.num_satoshis * 0.01) + 1 },
|
fee_limit: { fixed: Math.floor(this._decoded.num_satoshis * forwardFee) + 1 },
|
||||||
};
|
};
|
||||||
let that = this;
|
let that = this;
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
@@ -74,7 +70,7 @@ export class Paym {
|
|||||||
if (payment && payment.payment_route && payment.payment_route.total_amt_msat) {
|
if (payment && payment.payment_route && payment.payment_route.total_amt_msat) {
|
||||||
// paid just now
|
// paid just now
|
||||||
this._isPaid = true;
|
this._isPaid = true;
|
||||||
payment.payment_route.total_fees = +payment.payment_route.total_fees + Math.floor(+payment.payment_route.total_amt * Paym.fee);
|
payment.payment_route.total_fees = +payment.payment_route.total_fees + Math.floor(+payment.payment_route.total_amt * internalFee);
|
||||||
if (this._bolt11) payment.pay_req = this._bolt11;
|
if (this._bolt11) payment.pay_req = this._bolt11;
|
||||||
if (this._decoded) payment.decoded = this._decoded;
|
if (this._decoded) payment.decoded = this._decoded;
|
||||||
}
|
}
|
||||||
@@ -87,7 +83,7 @@ export class Paym {
|
|||||||
if (this._bolt11) payment.pay_req = this._bolt11;
|
if (this._bolt11) payment.pay_req = this._bolt11;
|
||||||
// trying to guess the fee
|
// trying to guess the fee
|
||||||
payment.payment_route = payment.payment_route || {};
|
payment.payment_route = payment.payment_route || {};
|
||||||
payment.payment_route.total_fees = Math.floor(this._decoded.num_satoshis * 0.01); // we dont know the exact fee, so we use max (same as fee_limit)
|
payment.payment_route.total_fees = Math.floor(this._decoded.num_satoshis * forwardFee); // we dont know the exact fee, so we use max (same as fee_limit)
|
||||||
payment.payment_route.total_amt = this._decoded.num_satoshis;
|
payment.payment_route.total_amt = this._decoded.num_satoshis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export class User {
|
|||||||
let lockedPayments = await this.getLockedPayments();
|
let lockedPayments = await this.getLockedPayments();
|
||||||
for (let paym of lockedPayments) {
|
for (let paym of lockedPayments) {
|
||||||
// locked payments are processed in scripts/process-locked-payments.js
|
// locked payments are processed in scripts/process-locked-payments.js
|
||||||
calculatedBalance -= +paym.amount + /* feelimit */ Math.floor(paym.amount * 0.01);
|
calculatedBalance -= +paym.amount + /* feelimit */ Math.floor(paym.amount * forwardFee);
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculatedBalance;
|
return calculatedBalance;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
let config = {
|
let config = {
|
||||||
|
enableUpdateDescribeGraph: false,
|
||||||
postRateLimit: 100,
|
postRateLimit: 100,
|
||||||
rateLimit: 200,
|
rateLimit: 200,
|
||||||
|
forwardReserveFee: 0.01, // default 0.01
|
||||||
|
intraHubFee: 0.003, // default 0.003
|
||||||
bitcoind: {
|
bitcoind: {
|
||||||
rpc: 'http://login:password@1.1.1.1:8332/wallet/wallet.dat',
|
rpc: 'http://login:password@1.1.1.1:8332/wallet/wallet.dat',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ redis.monitor(function (err, monitor) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/****** START SET FEES FROM CONFIG AT STARTUP ******/
|
||||||
|
/** GLOBALS */
|
||||||
|
global.forwardFee = config.forwardReserveFee || 0.01;
|
||||||
|
global.internalFee = config.intraHubFee || 0.003;
|
||||||
|
/****** END SET FEES FROM CONFIG AT STARTUP ******/
|
||||||
|
|
||||||
let bitcoinclient = require('../bitcoin');
|
let bitcoinclient = require('../bitcoin');
|
||||||
let lightning = require('../lightning');
|
let lightning = require('../lightning');
|
||||||
let identity_pubkey = false;
|
let identity_pubkey = false;
|
||||||
@@ -118,8 +124,10 @@ function updateDescribeGraph() {
|
|||||||
console.log('updated graph');
|
console.log('updated graph');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (config.enableUpdateDescribeGraph) {
|
||||||
updateDescribeGraph();
|
updateDescribeGraph();
|
||||||
setInterval(updateDescribeGraph, 120000);
|
setInterval(updateDescribeGraph, 120000);
|
||||||
|
}
|
||||||
|
|
||||||
// ######################## ROUTES ########################
|
// ######################## ROUTES ########################
|
||||||
|
|
||||||
@@ -131,7 +139,13 @@ const postLimiter = rateLimit({
|
|||||||
|
|
||||||
router.post('/create', postLimiter, async function (req, res) {
|
router.post('/create', postLimiter, async function (req, res) {
|
||||||
logger.log('/create', [req.id]);
|
logger.log('/create', [req.id]);
|
||||||
if (!(req.body.partnerid && req.body.partnerid === 'bluewallet' && req.body.accounttype)) return errorBadArguments(res);
|
// Valid if the partnerid isn't there or is a string (same with accounttype)
|
||||||
|
if (! (
|
||||||
|
(!req.body.partnerid || (typeof req.body.partnerid === 'string' || req.body.partnerid instanceof String))
|
||||||
|
&& (!req.body.accounttype || (typeof req.body.accounttype === 'string' || req.body.accounttype instanceof String))
|
||||||
|
) ) return errorBadArguments(res);
|
||||||
|
|
||||||
|
if (config.sunset) return errorSunset(res);
|
||||||
|
|
||||||
let u = new User(redis, bitcoinclient, lightning);
|
let u = new User(redis, bitcoinclient, lightning);
|
||||||
await u.create();
|
await u.create();
|
||||||
@@ -170,6 +184,8 @@ router.post('/addinvoice', postLimiter, async function (req, res) {
|
|||||||
|
|
||||||
if (!req.body.amt || /*stupid NaN*/ !(req.body.amt > 0)) return errorBadArguments(res);
|
if (!req.body.amt || /*stupid NaN*/ !(req.body.amt > 0)) return errorBadArguments(res);
|
||||||
|
|
||||||
|
if (config.sunset) return errorSunsetAddInvoice(res);
|
||||||
|
|
||||||
const invoice = new Invo(redis, bitcoinclient, lightning);
|
const invoice = new Invo(redis, bitcoinclient, lightning);
|
||||||
const r_preimage = invoice.makePreimageHex();
|
const r_preimage = invoice.makePreimageHex();
|
||||||
lightning.addInvoice(
|
lightning.addInvoice(
|
||||||
@@ -229,7 +245,7 @@ router.post('/payinvoice', async function (req, res) {
|
|||||||
|
|
||||||
logger.log('/payinvoice', [req.id, 'userBalance: ' + userBalance, 'num_satoshis: ' + info.num_satoshis]);
|
logger.log('/payinvoice', [req.id, 'userBalance: ' + userBalance, 'num_satoshis: ' + info.num_satoshis]);
|
||||||
|
|
||||||
if (userBalance >= +info.num_satoshis + Math.floor(info.num_satoshis * 0.01)) {
|
if (userBalance >= +info.num_satoshis + Math.floor(info.num_satoshis * forwardFee)) {
|
||||||
// got enough balance, including 1% of payment amount - reserve for fees
|
// got enough balance, including 1% of payment amount - reserve for fees
|
||||||
|
|
||||||
if (identity_pubkey === info.destination) {
|
if (identity_pubkey === info.destination) {
|
||||||
@@ -256,8 +272,8 @@ router.post('/payinvoice', async function (req, res) {
|
|||||||
await u.savePaidLndInvoice({
|
await u.savePaidLndInvoice({
|
||||||
timestamp: parseInt(+new Date() / 1000),
|
timestamp: parseInt(+new Date() / 1000),
|
||||||
type: 'paid_invoice',
|
type: 'paid_invoice',
|
||||||
value: +info.num_satoshis + Math.floor(info.num_satoshis * Paym.fee),
|
value: +info.num_satoshis + Math.floor(info.num_satoshis * internalFee),
|
||||||
fee: Math.floor(info.num_satoshis * Paym.fee),
|
fee: Math.floor(info.num_satoshis * internalFee),
|
||||||
memo: decodeURIComponent(info.description),
|
memo: decodeURIComponent(info.description),
|
||||||
pay_req: req.body.invoice,
|
pay_req: req.body.invoice,
|
||||||
});
|
});
|
||||||
@@ -310,7 +326,7 @@ router.post('/payinvoice', async function (req, res) {
|
|||||||
let inv = {
|
let inv = {
|
||||||
payment_request: req.body.invoice,
|
payment_request: req.body.invoice,
|
||||||
amt: info.num_satoshis, // amt is used only for 'tip' invoices
|
amt: info.num_satoshis, // amt is used only for 'tip' invoices
|
||||||
fee_limit: { fixed: Math.floor(info.num_satoshis * 0.005) + 1 },
|
fee_limit: { fixed: Math.floor(info.num_satoshis * forwardFee) + 1 },
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await u.lockFunds(req.body.invoice, info);
|
await u.lockFunds(req.body.invoice, info);
|
||||||
@@ -335,6 +351,8 @@ router.get('/getbtc', async function (req, res) {
|
|||||||
return errorBadAuth(res);
|
return errorBadAuth(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.sunset) return errorSunsetAddInvoice(res);
|
||||||
|
|
||||||
let address = await u.getAddress();
|
let address = await u.getAddress();
|
||||||
if (!address) {
|
if (!address) {
|
||||||
await u.generateAddress();
|
await u.generateAddress();
|
||||||
@@ -411,8 +429,8 @@ router.get('/gettxs', async function (req, res) {
|
|||||||
for (let locked of lockedPayments) {
|
for (let locked of lockedPayments) {
|
||||||
txs.push({
|
txs.push({
|
||||||
type: 'paid_invoice',
|
type: 'paid_invoice',
|
||||||
fee: Math.floor(locked.amount * 0.01) /* feelimit */,
|
fee: Math.floor(locked.amount * forwardFee) /* feelimit */,
|
||||||
value: locked.amount + Math.floor(locked.amount * 0.01) /* feelimit */,
|
value: locked.amount + Math.floor(locked.amount * forwardFee) /* feelimit */,
|
||||||
timestamp: locked.timestamp,
|
timestamp: locked.timestamp,
|
||||||
memo: 'Payment in transition',
|
memo: 'Payment in transition',
|
||||||
});
|
});
|
||||||
@@ -492,6 +510,7 @@ router.get('/queryroutes/:source/:dest/:amt', async function (req, res) {
|
|||||||
|
|
||||||
let request = {
|
let request = {
|
||||||
pub_key: req.params.dest,
|
pub_key: req.params.dest,
|
||||||
|
use_mission_control: true,
|
||||||
amt: req.params.amt,
|
amt: req.params.amt,
|
||||||
source_pub_key: req.params.source,
|
source_pub_key: req.params.source,
|
||||||
};
|
};
|
||||||
@@ -581,3 +600,19 @@ function errorPaymentFailed(res) {
|
|||||||
message: 'Payment failed. Does the receiver have enough inbound capacity?',
|
message: 'Payment failed. Does the receiver have enough inbound capacity?',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function errorSunset(res) {
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
code: 11,
|
||||||
|
message: 'This LNDHub instance is not accepting any more users',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function errorSunsetAddInvoice(res) {
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
code: 11,
|
||||||
|
message: 'This LNDHub instance is scheduled to shut down. Withdraw any remaining funds',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ function updateLightning() {
|
|||||||
lightning.getInfo({}, function (err, info) {
|
lightning.getInfo({}, function (err, info) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('lnd failure:', err);
|
console.error('lnd failure:', err);
|
||||||
|
process.exit(4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lightningGetInfo = info;
|
lightningGetInfo = info;
|
||||||
@@ -22,6 +23,7 @@ function updateLightning() {
|
|||||||
lightning.listChannels({}, function (err, response) {
|
lightning.listChannels({}, function (err, response) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('lnd failure:', err);
|
console.error('lnd failure:', err);
|
||||||
|
process.exit(4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('updated');
|
console.log('updated');
|
||||||
@@ -60,6 +62,7 @@ const pubkey2name = {
|
|||||||
'030c3f19d742ca294a55c00376b3b355c3c90d61c6b6b39554dbc7ac19b141c14f': 'bitrefill.com',
|
'030c3f19d742ca294a55c00376b3b355c3c90d61c6b6b39554dbc7ac19b141c14f': 'bitrefill.com',
|
||||||
'03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f': 'ACINQ',
|
'03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f': 'ACINQ',
|
||||||
'03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e': 'OpenNode',
|
'03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e': 'OpenNode',
|
||||||
|
'028d98b9969fbed53784a36617eb489a59ab6dc9b9d77fcdca9ff55307cd98e3c4': 'OpenNode 2',
|
||||||
'0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3': 'coingate.com',
|
'0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3': 'coingate.com',
|
||||||
'0279c22ed7a068d10dc1a38ae66d2d6461e269226c60258c021b1ddcdfe4b00bc4': 'ln1.satoshilabs.com',
|
'0279c22ed7a068d10dc1a38ae66d2d6461e269226c60258c021b1ddcdfe4b00bc4': 'ln1.satoshilabs.com',
|
||||||
'02c91d6aa51aa940608b497b6beebcb1aec05be3c47704b682b3889424679ca490': 'lnd-21.LNBIG.com',
|
'02c91d6aa51aa940608b497b6beebcb1aec05be3c47704b682b3889424679ca490': 'lnd-21.LNBIG.com',
|
||||||
@@ -80,6 +83,10 @@ const pubkey2name = {
|
|||||||
'033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025': 'bfx-lnd0',
|
'033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025': 'bfx-lnd0',
|
||||||
'03021c5f5f57322740e4ee6936452add19dc7ea7ccf90635f95119ab82a62ae268': 'lnd1.bluewallet.io',
|
'03021c5f5f57322740e4ee6936452add19dc7ea7ccf90635f95119ab82a62ae268': 'lnd1.bluewallet.io',
|
||||||
'037cc5f9f1da20ac0d60e83989729a204a33cc2d8e80438969fadf35c1c5f1233b': 'lnd2.bluewallet.io',
|
'037cc5f9f1da20ac0d60e83989729a204a33cc2d8e80438969fadf35c1c5f1233b': 'lnd2.bluewallet.io',
|
||||||
|
'036b53093df5a932deac828cca6d663472dbc88322b05eec1d42b26ab9b16caa1c': 'okcoin',
|
||||||
|
'038f8f113c580048d847d6949371726653e02b928196bad310e3eda39ff61723f6': 'magnetron',
|
||||||
|
'03829249ef39746fd534a196510232df08b83db0967804ec71bf4120930864ff97': 'blokada.org',
|
||||||
|
'02ce691b2e321954644514db708ba2a72769a6f9142ac63e65dd87964e9cf2add9': 'Satoshis.Games',
|
||||||
};
|
};
|
||||||
|
|
||||||
router.get('/', function (req, res) {
|
router.get('/', function (req, res) {
|
||||||
@@ -98,7 +105,8 @@ router.get('/qr', function (req, res) {
|
|||||||
if (process.env.TOR_URL) {
|
if (process.env.TOR_URL) {
|
||||||
host = process.env.TOR_URL;
|
host = process.env.TOR_URL;
|
||||||
}
|
}
|
||||||
const url = 'bluewallet:setlndhuburl?url=' + encodeURIComponent(req.protocol + '://' + host);
|
const customPath = req.url.replace('/qr', '');
|
||||||
|
const url = 'bluewallet:setlndhuburl?url=' + encodeURIComponent(req.protocol + '://' + host + customPath);
|
||||||
var code = qr.image(url, { type: 'png' });
|
var code = qr.image(url, { type: 'png' });
|
||||||
res.setHeader('Content-type', 'image/png');
|
res.setHeader('Content-type', 'image/png');
|
||||||
code.pipe(res);
|
code.pipe(res);
|
||||||
|
|||||||
10
index.js
10
index.js
@@ -5,6 +5,7 @@ process.on('uncaughtException', function (err) {
|
|||||||
|
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||||
let express = require('express');
|
let express = require('express');
|
||||||
|
const helmet = require('helmet');
|
||||||
let morgan = require('morgan');
|
let morgan = require('morgan');
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
let logger = require('./utils/logger');
|
let logger = require('./utils/logger');
|
||||||
@@ -16,6 +17,8 @@ morgan.token('id', function getId(req) {
|
|||||||
|
|
||||||
let app = express();
|
let app = express();
|
||||||
app.enable('trust proxy');
|
app.enable('trust proxy');
|
||||||
|
app.use(helmet.hsts());
|
||||||
|
app.use(helmet.hidePoweredBy());
|
||||||
|
|
||||||
const rateLimit = require('express-rate-limit');
|
const rateLimit = require('express-rate-limit');
|
||||||
const limiter = rateLimit({
|
const limiter = rateLimit({
|
||||||
@@ -44,7 +47,10 @@ app.use('/static', express.static('static'));
|
|||||||
app.use(require('./controllers/api'));
|
app.use(require('./controllers/api'));
|
||||||
app.use(require('./controllers/website'));
|
app.use(require('./controllers/website'));
|
||||||
|
|
||||||
let server = app.listen(process.env.PORT || 3000, function () {
|
const bindHost = process.env.HOST || '0.0.0.0';
|
||||||
logger.log('BOOTING UP', 'Listening on port ' + (process.env.PORT || 3000));
|
const bindPort = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
let server = app.listen(bindPort, bindHost, function () {
|
||||||
|
logger.log('BOOTING UP', 'Listening on ' + bindHost + ':' + bindPort);
|
||||||
});
|
});
|
||||||
module.exports = server;
|
module.exports = server;
|
||||||
|
|||||||
1981
package-lock.json
generated
1981
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lndhub",
|
"name": "lndhub",
|
||||||
"version": "1.3.3",
|
"version": "1.4.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -12,29 +12,29 @@
|
|||||||
"author": "Igor Korsakov <overtorment@gmail.com>",
|
"author": "Igor Korsakov <overtorment@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/cli": "^7.13.0",
|
"@babel/cli": "^7.14.8",
|
||||||
"@babel/core": "^7.13.8",
|
"@babel/core": "^7.15.0",
|
||||||
"@babel/eslint-parser": "^7.13.10",
|
"@babel/eslint-parser": "^7.14.2",
|
||||||
"@babel/node": "^7.13.0",
|
"@babel/node": "^7.14.9",
|
||||||
"@babel/preset-env": "^7.13.9",
|
"@babel/preset-env": "^7.15.0",
|
||||||
"@babel/register": "^7.13.8",
|
"@babel/register": "^7.14.5",
|
||||||
"@grpc/grpc-js": "^1.2.10",
|
"@grpc/grpc-js": "^1.3.7",
|
||||||
"@grpc/proto-loader": "^0.6.0",
|
"@grpc/proto-loader": "^0.6.4",
|
||||||
"bignumber.js": "^9.0.1",
|
"bignumber.js": "^9.0.1",
|
||||||
"bitcoinjs-lib": "^5.2.0",
|
"bitcoinjs-lib": "^5.2.0",
|
||||||
"bolt11": "^1.3.1",
|
"bolt11": "^1.3.2",
|
||||||
"core-js": "^3.9.1",
|
"eslint": "^7.24.0",
|
||||||
"eslint": "^7.20.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-config-prettier": "^8.0.0",
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-rate-limit": "^5.2.6",
|
"express-rate-limit": "^5.3.0",
|
||||||
"frisbee": "^3.1.4",
|
"frisbee": "^3.1.4",
|
||||||
"ioredis": "^4.22.0",
|
"helmet": "^4.6.0",
|
||||||
"jayson": "^3.4.4",
|
"ioredis": "^4.27.8",
|
||||||
|
"jayson": "^3.6.4",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"mustache": "^4.1.0",
|
"mustache": "^4.1.0",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.3.0",
|
||||||
"qr-image": "3.2.0",
|
"qr-image": "3.2.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"request-promise": "^4.2.6",
|
"request-promise": "^4.2.6",
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ const important_channels = {
|
|||||||
uri: '03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e@18.221.23.28:9735',
|
uri: '03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e@18.221.23.28:9735',
|
||||||
wumbo: 1,
|
wumbo: 1,
|
||||||
},
|
},
|
||||||
|
'028d98b9969fbed53784a36617eb489a59ab6dc9b9d77fcdca9ff55307cd98e3c4': {
|
||||||
|
name: 'OpenNode 2',
|
||||||
|
uri: '028d98b9969fbed53784a36617eb489a59ab6dc9b9d77fcdca9ff55307cd98e3c4@18.222.70.85:9735',
|
||||||
|
wumbo: 1,
|
||||||
|
},
|
||||||
// '0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3': {
|
// '0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3': {
|
||||||
// name: 'coingate.com',
|
// name: 'coingate.com',
|
||||||
// uri: '0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3@3.124.63.44:9735',
|
// uri: '0242a4ae0c5bef18048fbecf995094b74bfb0f7391418d71ed394784373f41e4f3@3.124.63.44:9735',
|
||||||
@@ -45,9 +50,9 @@ const important_channels = {
|
|||||||
uri: '02816caed43171d3c9854e3b0ab2cf0c42be086ff1bd4005acc2a5f7db70d83774@35.238.153.25:9735',
|
uri: '02816caed43171d3c9854e3b0ab2cf0c42be086ff1bd4005acc2a5f7db70d83774@35.238.153.25:9735',
|
||||||
wumbo: 1,
|
wumbo: 1,
|
||||||
},
|
},
|
||||||
'02570432c30df86ff7dbe3b49e24e8280411674f96470154cadc76d447e339292b': {
|
'036b53093df5a932deac828cca6d663472dbc88322b05eec1d42b26ab9b16caa1c': {
|
||||||
name: 'okcoin',
|
name: 'okcoin',
|
||||||
uri: '02570432c30df86ff7dbe3b49e24e8280411674f96470154cadc76d447e339292b@8.210.75.128:26657',
|
uri: '036b53093df5a932deac828cca6d663472dbc88322b05eec1d42b26ab9b16caa1c@47.243.25.4:26658',
|
||||||
wumbo: 1,
|
wumbo: 1,
|
||||||
},
|
},
|
||||||
// '0331f80652fb840239df8dc99205792bba2e559a05469915804c08420230e23c7c': {
|
// '0331f80652fb840239df8dc99205792bba2e559a05469915804c08420230e23c7c': {
|
||||||
@@ -78,7 +83,7 @@ lightning.listChannels({}, function (err, response) {
|
|||||||
}
|
}
|
||||||
let lightningListChannels = response;
|
let lightningListChannels = response;
|
||||||
for (let channel of lightningListChannels.channels) {
|
for (let channel of lightningListChannels.channels) {
|
||||||
if (channel.capacity < 0.05 / 100000000) {
|
if (channel.capacity <= 1000000) {
|
||||||
console.log(
|
console.log(
|
||||||
'lncli closechannel',
|
'lncli closechannel',
|
||||||
channel.channel_point.replace(':', ' '),
|
channel.channel_point.replace(':', ' '),
|
||||||
|
|||||||
@@ -50,9 +50,10 @@ let lightning = require('../lightning');
|
|||||||
|
|
||||||
let locked = await U.getLockedPayments();
|
let locked = await U.getLockedPayments();
|
||||||
for (let loc of locked) {
|
for (let loc of locked) {
|
||||||
console.log('-', loc.amount + /* fee limit */ Math.floor(loc.amount * 0.01), new Date(loc.timestamp * 1000).toString(), '[locked]');
|
console.log('-', loc.amount + /* fee limit */ Math.floor(loc.amount * config.forwardReserveFee), new Date(loc.timestamp * 1000).toString(), '[locked]');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('\ncalculatedBalance\n================\n', calculatedBalance, await U.getCalculatedBalance());
|
console.log('\ncalculatedBalance\n================\n', calculatedBalance, await U.getCalculatedBalance());
|
||||||
|
console.log('txs:', txs.length, 'userinvoices:', userinvoices.length);
|
||||||
process.exit();
|
process.exit();
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user