Giter Site home page Giter Site logo

elementsproject / lightning-charge Goto Github PK

View Code? Open in Web Editor NEW
552.0 31.0 86.0 1.18 MB

A simple drop-in solution for accepting lightning payments

License: MIT License

JavaScript 63.26% Shell 20.17% Dockerfile 11.14% Pug 3.97% Stylus 1.47%
bitcoin lightning lightning-charge micropayments lightning-payments

lightning-charge's Introduction

Lightning Charge

build status npm release docker release MIT license Pull Requests Welcome IRC

A drop-in solution for accepting lightning payments, built on top of c-lightning.

  • Simple HTTP REST API, optimized for developer friendliness and ease of integration. Near-zero configuration.

  • Supports invoice metadata, fiat currency conversion, long polling, web hooks, websockets and server-sent-events.

  • Built-in checkout page, can be iframed or redirected to.

⚡ radically low fees ⚡ nano payments ⚡ instant confirmations ⚡

Getting Started

Setup c-lightning and nodejs (v7.6 or newer), then:

$ npm install -g lightning-charge

$ charged --api-token mySecretToken # defaults: --ln-path ~/.lightning/testnet --db-path ./charge.db --port 9112

Note: if you're running into permission issues, try following these instructions.

That's it! The Lightning Charge REST API is now running and ready to process payments. You can access it at http://localhost:9112 using the API access token configured with --api-token.

Configuration options may alternatively be provided using environment variables:

$ LN_PATH=~/.lightning/testnet DB_PATH=charge.db API_TOKEN=mySecretToken PORT=9112 charged

Listens for connections on 127.0.0.1 by default. Set -i 0.0.0.0 to bind on all available interfaces. Note that Charge does not have TLS encryption and should not normally be exposed directly to the public internet. For remote access, you should setup an SSH tunnel or a TLS-enabled reverse proxy like nginx.

See $ charged --help for the full list of available options.

Deploy with Docker

To deploy Lightning Charge with Docker, run these commands:

$ mkdir data # make sure to create the folder _before_ running docker
$ docker run -it -u `id -u` -v `pwd`/data:/data -p 9735:9735 -p 9112:9112 \
             shesek/lightning-charge --api-token mySecretToken

This will start bitcoind, lightningd and charged and hook them up together. You will then be able to access the REST API at http://localhost:9112 using mySecretToken.

Runs in testnet mode by default, set NETWORK to override.

If you want to experiment in regtest mode and don't care about persisting data, this should do:

$ docker run -it -e NETWORK=regtest -p 9112:9112 shesek/lightning-charge --api-token mySecretToken

To connect to an existing lightningd instance running on the same machine, mount the lightning data directory to /etc/lightning (e.g. -v $HOME/.lightning:/etc/lightning). Connecting to remote lightningd instances is currently not supported.

To connect to an existing bitcoind instance running on the same machine, mount the bitcoin data directory to /etc/bitcoin (e.g. -v $HOME/.bitcoin:/etc/bitcoin). To connect to a remote bitcoind instance, set BITCOIND_URI=http://[user]:[pass]@[host]:[port] (or use __cookie__:... as the login for cookie-based authentication).

Deploy to Azure

One-click deployment on Azure (by @NicolasDorier).

An instructional video is available here.

Client libraries

Clients libraries are available for JavaScript and PHP. For other languages, you can use the REST API directly using a standard HTTP library.

LApps

Below are example LApps built on top of Lightning Charge:

  • FileBazaar: an ecommerce tool for content creators that produce digital files like photos, videos, or music.

  • Lightning Publisher: accept bitcoin payments for content on WordPress blogs.

  • nanotip: a simple web server for accepting lightning donations (a lightning tip jar).

  • paypercall: easily charge for HTTP APIs on a pay-per-call basis.

  • nanopos: a simple point-of-sale system for physical stores.

  • ifpaytt: trigger IFTTT actions with lightning payments.

  • WooCommerce Lightning: a lightning gateway for the WooCommerce e-commerce software.

  • Lightning Jukebox: a lightning powered jukebox. Pay with Bitcoin to choose your music.

Third party Lapps:

REST API

All endpoints accept and return data in JSON format.

Authentication is done using HTTP basic authentication headers, with api-token as the username and the api token (configured with --api-token/-t or using the API_TOKEN environment variable) as the password.

Invoices have the following properties: id, msatoshi, msatoshi_received, quoted_currency, quoted_amount, rhash, payreq, description, created_at, expires_at, paid_at, metadata and status (one of unpaid|paid|expired).

The code samples below assume you've set CHARGE=http://api-token:mySecretToken@localhost:9112.

GET /info

Get information about the c-lightning node.

$ curl $CHARGE/info
{"id":"032c6ba19a2141c5fee6ac8b6ff6cf24456fd4e8e206716a39af3300876c3a4835","port":42259,"address":[],"version":"v0.5.2-2016-11-21-1937-ge97ee3d","blockheight":434,"network":"regtest"}

POST /invoice

Create a new invoice.

Body parameters: msatoshi, currency, amount, description, expiry, metadata and webhook.

You can specify the amount as msatoshi (1 satoshi = 1000 msatoshis), or provide a currency and amount to be converted according to the current exchange rates (via bitcoinaverage). If a currency and amount were provided, they'll be available under quoted_{currency|amount}.

expiry sets the invoice expiry time in seconds (defaults to one hour). metadata may contain arbitrary invoice-related meta-data. description is embedded in the payment request and presented by the user's wallet (keep it short).

webhook may contain a URL to be registered as a webhook (see POST /invoice/:id/webhook).

Returns 201 Created and the invoice on success.

$ curl -X POST $CHARGE/invoice -d msatoshi=10000
{"id":"KcoQHfHJSx3fVhp3b1Y3h","msatoshi":"10000","status":"unpaid","rhash":"6823e46a08f50...",
 "payreq":"lntb100n1pd99d02pp...","created_at":1515369962,"expires_at":1515373562}

# with fiat-denominated amounts
$ curl -X POST $CHARGE/invoice -d currency=EUR -d amount=0.5
{"id":"OYwwaOQAPMFvg039gj_Rb","msatoshi":"3738106","quoted_currency":"EUR","quoted_amount":"0.5",...}

# without amount (accept all payments)
$ curl -X POST $CHARGE/invoice
{"id":"W8CF0UqY7qfAHCfnchqk9","msatoshi":null,...}

# with metadata as application/json
$ curl -X POST $CHARGE/invoice -H 'Content-Type: application/json' \
  -d '{"msatoshi":7000,"metadata":{"customer_id":9817,"products":[593,182]}}'
{"id":"PLKV1f8B7sth7w2OeDOt_","msatoshi":"7000","metadata":{"customer_id":9817,"products":[593,182]},...}

# with metadata as application/x-www-form-urlencoded
$ curl -X POST $CHARGE/invoice -d msatoshi=5000 -d metadata[customer_id]=9817 -d metadata[product_id]=7189
{"id":"58H9eoerBpKML9FvnMQtG","msatoshi":"5000","metadata":{"customer_id":"9817","product_id":"7189"},...}

GET /invoices

List all invoices.

$ curl $CHARGE/invoices
[{"id":"KcoQHfHJSx3fVhp3b1Y3h","msatoshi":"10000",...},{"id":"PLKV1f8B7sth7w2OeDOt_","msatoshi":"7000"},...]

GET /invoice/:id

Get the specified invoice.

$ curl $CHARGE/invoice/OYwwaOQAPMFvg039gj_Rb
{"id":"OYwwaOQAPMFvg039gj_Rb","msatoshi":"3738106","quoted_currency":"EUR","quoted_amount":"0.5","status":"unpaid",...}

DELETE /invoice/:id

Delete the specified invoice.

Body parameters: status

The current status of the invoice needs to be specified in the request body.

$ curl -X DELETE $CHARGE/invoice/OYwwaOQAPMFvg039gj_Rb -d status=unpaid
204 No Content

GET /invoice/:id/wait?timeout=[sec]

Long-polling invoice payment notification.

Waits for the invoice to be paid, then returns 200 OK and the updated invoice.

If timeout (defaults to 30s) is reached before the invoice is paid, returns 402 Payment Required.

If the invoice is expired and can no longer be paid, returns 410 Gone.

$ curl $CHARGE/invoice/OYwwaOQAPMFvg039gj_Rb/wait?timeout=60
# zZZZzzZ
{"id":"OYwwaOQAPMFvg039gj_Rb","msatoshi":"3738106","status":"paid","paid_at":1515371152,...}

POST /invoice/:id/webhook

Register a URL as a web hook to be notified once the invoice is paid.

Body parameters: url.

Returns 201 Created on success. Once the payment is made, a POST request with the updated invoice will be made to the provided URL.

If the invoice is already paid, returns 405 Method Not Allowed. If the invoice is expired, returns 410 Gone.

Webhooks can also be registered during invoice creation using the webhook parameter.

For security reasons, the provided url should contain a secret token used to verify the authenticity of the request (see an example HMAC-based implementation at woocommerce-gateway-lightning here, here and here).

$ curl -X POST $CHARGE/invoice/OYwwaOQAPMFvg039gj_Rb/webhook -d url=http://example.com/callback
Created

GET /payment-stream

Subscribe to payment updates as a server-sent events stream.

$ curl $CHARGE/payment-stream
# zzZZzZZ
data:{"id":"OYwwaOQAPMFvg039gj_Rb","msatoshi":"3738106","status":"paid","paid_at":1515371152,...}
# zZZzzZz
data:{"id":"KcoQHfHJSx3fVhp3b1Y3h","msatoshi":"10000","status":"paid","paid_at":1515681209,...}
# zZZzzzz...

Or via JavaScript:

const es = new EventSource('http://api-token:[TOKEN]@localhost:9112/payment-stream')

es.addEventListener('message', msg => {
  const inv = JSON.parse(msg.data)
  console.log('Paid invoice:', inv)
})

(EventSource is natively available in modern browsers, or via the eventsource library in nodejs)

WebSocket API

GET /ws

Subscribe to payment updates over WebSocket.

const ws = new WebSocket('http://api-token:[TOKEN]@localhost:9112/ws')

ws.addEventListener('message', msg => {
  const inv = JSON.parse(msg.data)
  console.log('Paid invoice:', inv)
})

Tests

Requires bitcoind, bitcoin-cli, lightningd, lightning-cli and jq to be in your PATH.

$ git clone https://github.com/ElementsProject/lightning-charge.git
$ cd lightning-charge
$ npm install
$ npm test

This will setup a temporary testing environment with a bitcoind regtest node and two c-lightning nodes with a funded channel, then start the Lightning Charge server and run the unit tests (written with mocha and supertest).

To run in verbose mode, set the VERBOSE environment variable: $ VERBOSE=1 npm test.

To pass arguments to mocha, use $ npm test -- [mocha opts].

To prevent the test environment files from being deleted after completing the tests, set KEEP_TMPDIR=1.

To setup a testing environment without running the tests, run $ npm run testenv. This will display information about the running services and keep them alive for further inspection.

Tests can also be run using docker: $ docker build --build-arg TESTRUNNER=1 -t charge . && docker run -it --entrypoint npm charge test

License

MIT

lightning-charge's People

Contributors

dimitris-t avatar grubles avatar kikoncuo avatar nicolasdorier avatar shesek avatar verretor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lightning-charge's Issues

Payment page for customers

Add a server-hosted payment page with instructions for the lightning payment that e-commerce stores can redirect customers to (similarly to how the checkout process with PayPal and other payment providers works), as an alternative to embedding the payment directly into the store.

Invalidate an invoice

Use case:

In BTCPay, the user can decide to pay the invoice partly in BTC, partly in LTC, and soon, partly on lightning.

When the invoice is created I create all the addresses in all the alts, and soon, all the invoices on lightning charge. When an address receive a payment, I generate a fresh address.

But I will also need to generate a new lightning invoice, because the amount due changed.
I would like to invalidate the previous invoice (which has the wrong amount now) if that happen.

This is a "nice to have feature" because I can be sure the user can't screw up and pay too much by mistake. But I can do without, as merchants are kind of used to deal with users sending not enough/too much already.

SQLITE_CONSTRAINT when trying to create an invoice

When trying to create an invoice through any of the POST /invoice examples in the README, I always get the same error:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Error: SQLITE_CONSTRAINT: NOT NULL constraint failed: invoice.rhash</pre>
</body>
</html>

charged daemon shows:

  lightning-client #1 --> invoice ["10000","8gcq7sOTkiqZiTODgfNZY","Lightning Charge Invoice",null] +17s
  lightning-client #1 <-- {"payment_hash":"42fa88fbe1f85516866a6fb4e4a0bcece294bca0428e947509305c6808317181","expiry_time":1516535310,"expires_at":1516535310,"bolt11":"lnbc100n1pdxgml7pp5gtag37lplp23dpn2d76wfg9uan3ff09qg28fgagfxpwxszp3wxqsdp8f35kw6r5de5kueeqgd5xzun8v5syjmnkda5kxegcqpggwmectjsfxeeuxwnpyccz8mhz2s7s5uv6kdzj3mnmq5ju0hctgmyyqrrrafmmma0sxuv2c9xvseg0cgxrvlmuf8fggh83hdjmsq32dgpr36dlj"} +40ms
  lightning-charge saving invoice: { id: '8gcq7sOTkiqZiTODgfNZY',
  description: undefined,
  metadata: undefined,
  msatoshi: '10000',
  quoted_currency: undefined,
  quoted_amount: undefined,
  rhash: undefined,
  payreq: 'lnbc100n1pdxgml7pp5gtag37lplp23dpn2d76wfg9uan3ff09qg28fgagfxpwxszp3wxqsdp8f35kw6r5de5kueeqgd5xzun8v5syjmnkda5kxegcqpggwmectjsfxeeuxwnpyccz8mhz2s7s5uv6kdzj3mnmq5ju0hctgmyyqrrrafmmma0sxuv2c9xvseg0cgxrvlmuf8fggh83hdjmsq32dgpr36dlj',
  expires_at: 1516535310,
  created_at: 1516531710,
  completed: false } +0ms
  knex:query insert into `invoice` (`completed`, `created_at`, `description`, `expires_at`, `id`, `metadata`, `msatoshi`, `payreq`, `quoted_amount`, `quoted_currency`, `rhash`) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +17s
  knex:bindings [ false,
  knex:bindings   1516531710,
  knex:bindings   null,
  knex:bindings   1516535310,
  knex:bindings   '8gcq7sOTkiqZiTODgfNZY',
  knex:bindings   'null',
  knex:bindings   '10000',
  knex:bindings   'lnbc100n1pdxgml7pp5gtag37lplp23dpn2d76wfg9uan3ff09qg28fgagfxpwxszp3wxqsdp8f35kw6r5de5kueeqgd5xzun8v5syjmnkda5kxegcqpggwmectjsfxeeuxwnpyccz8mhz2s7s5uv6kdzj3mnmq5ju0hctgmyyqrrrafmmma0sxuv2c9xvseg0cgxrvlmuf8fggh83hdjmsq32dgpr36dlj',
  knex:bindings   null,
  knex:bindings   null,
  knex:bindings   null ] +17s
POST /invoice 500 28.228 ms - 194
Error: SQLITE_CONSTRAINT: NOT NULL constraint failed: invoice.rhash

lightningd gets the request and creates the invoice, but charged doesn't seem to be mapping the response properly to its own invoice model.

Error handling for invalid requests

Even though in #20 I was obviously not having the rights to listen to the correct port the problem is still valid:

as u can see after starting chared I was able to handle an incoming request and then when a new http request came in GET http://clientapi.ipip.net/echo.php?info=20180128151721 (which some person directed to mu IP adress on my open port 9112) the server crashed... this should not happen

rpickhardt@ip-172-31-5-23:~/lightning-charge$ ./bin/charged -i 0.0.0.0 --port 9112 HTTP server running on 0.0.0.0:9112
POST /invoice 201 3737.292 ms - 631
GET /invoice/9f1eJsPicXnHdhdtKlTL3 200 2.643 ms - 668
GET /invoice/9f1eJsPicXnHdhdtKlTL3/wait?timeout=24 402 24175.133 ms - 16
GET /invoice/9f1eJsPicXnHdhdtKlTL3 200 1.446 ms - 668 
GET /invoice/9f1eJsPicXnHdhdtKlTL3/wait?timeout=24 402 24021.948 ms - 16 
GET /invoice/9f1eJsPicXnHdhdtKlTL3/wait?timeout=24 402 24007.696 ms - 16
GET /invoice/9f1eJsPicXnHdhdtKlTL3/wait?timeout=24 402 24014.377 ms - 16 
GET /invoice/9f1eJsPicXnHdhdtKlTL3/wait?timeout=24 402 24020.857 ms - 16 
GET http://clientapi.ipip.net/echo.php?info=20180128151721 404 27.217 ms - 147 
Error: Database error
at LightningClient.once.response (/export/home/rpickhardt/lightning-
charge/node_modules/lightning-client/index.js:145:28)                                                                                                                               
at Object.onceWrapper (events.js:315:30)                                                                                                                                                                                                                
at emitOne (events.js:116:13)                                                                                                                                                                                                                           
at LightningClient.emit (events.js:211:7)                                                                                                                                                                                                               
at _.each.str (/export/home/rpickhardt/lightning-charge/node_modules/lightning-
client/index.js:61:23)                                                                                                                                                   
at arrayEach (/export/home/rpickhardt/lightning-charge/node_modules/lodash/lodash.js:537:11)                                                                                                                                                            
at Function.forEach (/export/home/rpickhardt/lightning-
charge/node_modules/lodash/lodash.js:9359:14)                                                                                                                                                    
at Socket.LightningClient.client.on.data (/export/home/rpickhardt/lightning-
charge/node_modules/lightning-client/index.js:52:15)                                                                                                                        
at emitOne (events.js:116:13)                                                                                                                                                                                                                           
at Socket.emit (events.js:211:7)                                                                                                                                                                                                                        
at addChunk (_stream_readable.js:263:12)                                                                                                                                                                                                                
at readableAddChunk (_stream_readable.js:250:11)                                                                                                                                                                                                        
at Socket.Readable.push (_stream_readable.js:208:10)                                                                                                                                                                                                    
at Pipe.onread (net.js:594:20)                                                                                                                                                                                                                      
/export/home/rpickhardt/lightning-charge/src/app.js:14                                                                                                                                                                                                                          
throw err;                                                                                                                                                                                                                                              
^                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
Error: Database error                                                                                                                                                                                                                                       
at LightningClient.once.response (/export/home/rpickhardt/lightning-
charge/node_modules/lightning-client/index.js:145:28)                                                                                                                               
at Object.onceWrapper (events.js:315:30)                                                                                                                                                                                                                
at emitOne (events.js:116:13)                                                                                                                                                                                                                           
at LightningClient.emit (events.js:211:7)                                                                                                                                                                                                               
at _.each.str (/export/home/rpickhardt/lightning-charge/node_modules/lightning-
client/index.js:61:23)                                                                                                                                                   
at arrayEach (/export/home/rpickhardt/lightning-charge/node_modules/lodash/lodash.js:537:11)                                                                                                                                                            
at Function.forEach (/export/home/rpickhardt/lightning-
charge/node_modules/lodash/lodash.js:9359:14)                                                                                                                                                    
at Socket.LightningClient.client.on.data (/export/home/rpickhardt/lightning-
charge/node_modules/lightning-client/index.js:52:15)                                                                                                                        
at emitOne (events.js:116:13)                                                                                                                                                                                                                           
at Socket.emit (events.js:211:7)                                                                                                                                                                                                                        
at addChunk (_stream_readable.js:263:12)                                                                                                                                                                                                                
at readableAddChunk (_stream_readable.js:250:11)                                                                                                                                                                                                        
at Socket.Readable.push (_stream_readable.js:208:10)                                                                                                                                                                                                    
at Pipe.onread (net.js:594:20)         

actually the bash tells me c-lightning crashed and therefor probably charge could not connect via cli. I open another bug in the c-lightning repo

Update Installation Docs for Ubuntu

Hi,

I was setting up lightning-charge to integrate with the WordPress Plugin. I had some difficulties with installation in my environment so I thought this might useful to other devs. Please let me know if this would be better closed.

Environment

  • Ubuntu 18.04 x64

Installation

  1. Nodejs 7 and 10 were not compatible with lightning-charge, had to install nodejs8

    • $ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash

    • $ apt-get install nodejs

  2. Errors running npm install lightning-charge, had to include the following flags

    • $ npm install --unsafe-perm --verbose -g lightning-charge
  3. Sqlite3 dependency weren't found in the node_modules, had to run npm rebuild

    • $ cd /usr/lib/node_modules/lightning-charge
    • $ npm rebuild

After the above steps everything worked well following the steps in the README to run the server.

Failed to install with node10 on FreeBSD 12

Failed to install package with npm@node10 on FreeBSD10. If npm@node8 is used package install is succesfull.

Errorlog:

npm install --unsafe-perm -g lightning-charge --sqlite=/usr/local

16159 info lifecycle [email protected]install: [email protected]
16160 verbose lifecycle [email protected]
install: unsafe-perm in lifecycle true
16161 verbose lifecycle [email protected]install: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/.bin:/usr/local/lib/node_modules/lightning-charge/node_modules/.bin:/usr/local/lib/node_modules/.bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/root/bin
16162 verbose lifecycle [email protected]
install: CWD: /usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3
16163 silly lifecycle [email protected]install: Args: [ '-c', 'node-pre-gyp install --fallback-to-build' ]
16164 silly lifecycle [email protected]
install: Returned: code: 1 signal: null
16165 info lifecycle [email protected]~install: Failed to exec install script
16166 timing action:install Completed in 14059ms
16167 verbose unlock done using /root/.npm/_locks/staging-3a08f0df5026584d.lock for /usr/local/lib/node_modules/.staging
16168 timing stage:rollbackFailedOptional Completed in 2041ms
16169 timing stage:runTopLevelLifecycles Completed in 34196ms
16170 warn optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/lightning-charge/node_modules/fsevents):
16171 warn notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"freebsd","arch":"x64"})
16172 verbose notsup SKIPPING OPTIONAL DEPENDENCY: Valid OS: darwin
16172 verbose notsup SKIPPING OPTIONAL DEPENDENCY: Valid Arch: any
16172 verbose notsup SKIPPING OPTIONAL DEPENDENCY: Actual OS: freebsd
16172 verbose notsup SKIPPING OPTIONAL DEPENDENCY: Actual Arch: x64
16173 verbose stack Error: [email protected] install: node-pre-gyp install --fallback-to-build
16173 verbose stack Exit status 1
16173 verbose stack at EventEmitter. (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:301:16)
16173 verbose stack at EventEmitter.emit (events.js:189:13)
16173 verbose stack at ChildProcess. (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
16173 verbose stack at ChildProcess.emit (events.js:189:13)
16173 verbose stack at maybeClose (internal/child_process.js:970:16)
16173 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
16174 verbose pkgid [email protected]
16175 verbose cwd /root
16176 verbose FreeBSD 12.0-RELEASE
16177 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "--unsafe-perm" "-g" "lightning-charge" "--sqlite=/usr/local"
16178 verbose node v10.15.3
16179 verbose npm v6.9.0
16180 error code ELIFECYCLE
16181 error errno 1
16182 error [email protected] install: node-pre-gyp install --fallback-to-build
16182 error Exit status 1
16183 error Failed at the [email protected] install script.
16183 error This is probably not a problem with npm. There is likely additional logging output above.
16184 verbose exit [ 1, true ]

Install lightning-charge

npm install -g lightning-charge
npm ERR! path /usr/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/abbrev
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall rename
npm ERR! enoent ENOENT: no such file or directory, rename '/usr/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/abbrev' -> '/usr/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/.abbrev.DELETE'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent 

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2018-04-12T16_09_42_127Z-debug.log

My environment is Ubuntu

Trying to use docker image

Hey there, thanks for releasing this!

In the README it says the docker image contains bitcoind, c-lightning and charged -- I am getting quite a few lightning-rpc errors though?

Here's my docker-compose.yml:

version: '2'
services:
  charge:
    image: shesek/lightning-charge
    volumes:
      - ~/.lightning:/root.lightning
      - ~/.bitcoin:/root/.bitcoin
      - ~/.charged/charge.db:/opt/charged/sqlite.db
    environment:
      - API_TOKEN=tacquitos
    ports:
      - 9112:9112

And here's the output I'm getting when trying to make an invoice:

charge_1  | 2018-01-17T05:31:58.274Z lightning-client #1 --> invoice ["10000","NFOcWboDN0Z~KxMQezbbh","Lightning Charge Invoice",null]
charge_1  | Lightning client connection error Error: This socket is closed
charge_1  |     at Socket._writeGeneric (net.js:726:18)
charge_1  |     at Socket._write (net.js:786:8)
charge_1  |     at doWrite (_stream_writable.js:387:12)
charge_1  |     at writeOrBuffer (_stream_writable.js:373:5)
charge_1  |     at Socket.Writable.write (_stream_writable.js:290:11)
charge_1  |     at Socket.write (net.js:704:40)
charge_1  |     at Promise (/opt/charged/node_modules/lightning-client/index.js:149:30)
charge_1  |     at new Promise (<anonymous>)
charge_1  |     at clientConnectionPromise.then (/opt/charged/node_modules/lightning-client/index.js:137:25)
charge_1  |     at <anonymous>
charge_1  |     at process._tickCallback (internal/process/next_tick.js:188:7)
charge_1  | 2018-01-17T05:32:11.173Z lightning-client Trying to reconnect...
charge_1  | Lightning client connection error { Error: connect ECONNREFUSED /root/.lightning/lightning-rpc
charge_1  |     at Object._errnoException (util.js:1022:11)
charge_1  |     at _exceptionWithHostPort (util.js:1044:20)
charge_1  |     at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1182:14)
charge_1  |   code: 'ECONNREFUSED',
charge_1  |   errno: 'ECONNREFUSED',
charge_1  |   syscall: 'connect',
charge_1  |   address: '/root/.lightning/lightning-rpc' }
charge_1  | 2018-01-17T05:32:11.179Z lightning-client Trying to reconnect...
charge_1  | Lightning client connection error { Error: connect ECONNREFUSED /root/.lightning/lightning-rpc
charge_1  |     at Object._errnoException (util.js:1022:11)
charge_1  |     at _exceptionWithHostPort (util.js:1044:20)
charge_1  |     at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1182:14)
charge_1  |   code: 'ECONNREFUSED',
charge_1  |   errno: 'ECONNREFUSED',
charge_1  |   syscall: 'connect',
charge_1  |   address: '/root/.lightning/lightning-rpc' }

Thanks again for all the hard work, so excited to use this!

EDIT:

If it helps, I can successfully ping the server normally to check for invoices, and get an empty list back:

$ curl -u api-token:tacquitos http://hotness:9112/invoices
[]

node-pre-gyp ERR! UNCAUGHT EXCEPTION

Hello

c-lightning is working almost fine, I opened a few channels and made some payments.

I tried to install "lightning charge" but no success :( Can you help?

`root@vmi178998:~# sudo npm install -g lightning-charge
/usr/local/bin/charged -> /usr/local/lib/node_modules/lightning-charge/bin/charged

[email protected] install /usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3
node-pre-gyp install --fallback-to-build

node-pre-gyp ERR! UNCAUGHT EXCEPTION
node-pre-gyp ERR! stack TypeError: Buffer.alloc is not a function
node-pre-gyp ERR! stack at Object. (/usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/tar/lib/pack.js:32:20)
node-pre-gyp ERR! stack at Module._compile (module.js:410:26)
node-pre-gyp ERR! stack at Object.Module._extensions..js (module.js:417:10)
node-pre-gyp ERR! stack at Module.load (module.js:344:32)
node-pre-gyp ERR! stack at Function.Module._load (module.js:301:12)
node-pre-gyp ERR! stack at Module.require (module.js:354:17)
node-pre-gyp ERR! stack at require (internal/module.js:12:17)
node-pre-gyp ERR! stack at Object. (/usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/tar/lib/create.js:6:14)
node-pre-gyp ERR! stack at Module._compile (module.js:410:26)
node-pre-gyp ERR! stack at Object.Module._extensions..js (module.js:417:10)
node-pre-gyp ERR! System Linux 4.4.0-121-generic
node-pre-gyp ERR! command "/usr/bin/nodejs" "/usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3
node-pre-gyp ERR! node -v v4.2.6
node-pre-gyp ERR! node-pre-gyp -v v0.9.0
node-pre-gyp ERR! This is a bug in node-pre-gyp.
node-pre-gyp ERR! Try to update node-pre-gyp and file an issue if it does not help:
node-pre-gyp ERR! https://github.com/mapbox/node-pre-gyp/issues
/usr/local/lib
└── (empty)

npm ERR! Linux 4.4.0-121-generic
npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "install" "-g" "lightning-charge"
npm ERR! node v4.2.6
npm ERR! npm v3.5.2
npm ERR! code ELIFECYCLE

npm ERR! [email protected] install: node-pre-gyp install --fallback-to-build
npm ERR! Exit status 7
npm ERR!
npm ERR! Failed at the [email protected] install script 'node-pre-gyp install --fallback-to-build'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the sqlite3 package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-pre-gyp install --fallback-to-build
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs sqlite3
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls sqlite3
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR! /root/npm-debug.log
npm ERR! code 1
`

npm-debug.log file here: https://pastebin.com/y7FvRBc0

Thank you
P.

Enabling remote access to lightning-charge - Documentation

For accessing lightning-charge from a remote machine it is necessary to specify the host parameter to listen on all devices like so:

charged -t [API-TOKEN] -i 0.0.0.0

Is there any reason this is not documented?
I think it's uncommon to have the nodes and the store on the same machine so i would be glad having at least one hint in the documentation commenting this.

Server crashes if invalid API request comes hin

For stupid reasons I had to run the charge server on port 25. As soon as SMTP sockets have been opened the server crashed:

rpickhardt@ip-172-31-5-23:~/lightning-charge$ ./bin/charged -i 0.0.0.0 --port 25 events.js:183 throw er; // Unhandled 'error' event ^ Error: listen EACCES 0.0.0.0:25 at Object._errnoException (util.js:1022:11) at _exceptionWithHostPort (util.js:1044:20) at Server.setupListenHandle [as _listen2] (net.js:1334:19) at listenInCluster (net.js:1392:12) at doListen (net.js:1501:7) at _combinedTickCallback (internal/process/next_tick.js:141:11) Projects should transition to using getblockchaininfo, getnetworkinfo, and getwalletinfo before upgrading to 0.16", at process._tickCallback (internal/process/next_tick.js:180:9)

I think the error is in the following file at line 4 (completely not sure though since I don't get the flow of data within java script. That language will stay strange to me for the rest of my life):

process.on('unhandledRejection', err => { throw err })

I could be totally wrong I tried to look at the code but as you know I am totally not a javascript kind of person so I won't provide a patch for this. However I think the server should / must be robust against invalid api requests... if you point me to the correct part of the code I am happy to provide a patch that doesn't die if the sytax of an request is wrong but rather puts something to the log files

Channel management?

So if I create an app with charged, does it automatically open/close channels? How do you "fund" charged?

If charged apps only rely on channels opened by customers, won't that have poor connectivity to the LN graph? Shouldn't you, from your own charged app, open a channel with some large node everyone else is already connected to?

Thanks!

Sending a payment to the address on the invoice is never able to find a route

Maybe I am missing something but it seems this tool is incomplete? I have the image up and running and figured out that I had to ssh into the box and open some channels via lightning-cli manually. But even after doing this (and being able to successfully send a payment to starblocks) I am never able to find a route to receive an incoming payment. That is with both my eclair for android and my lightning-charge node being connected to the same acinq node. Given the whole point of this project appears to be accepting payments I don't see any documentation on what I could be missing to actually be able to receive the payment? It doesn't even appear this image exposes the right port for the lightningd to even be discovered?

SyntaxError: Unexpected Idenfier

Hi,

Trying the Getting Started section for the first time on a fresh machine and I get the below error when attempting to run $ charged. It's probably something I messed up or missed in the config.

/usr/local/lib/node_modules/lightning-charge/migrations/20180120115425_completed-fields.js:8
exports.down = async db => {
                     ^^

SyntaxError: Unexpected identifier
    at createScript (vm.js:56:10)
    ...
    at /usr/local/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:136:25
    ...
    at Promise._settlePromise (/usr/local/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:569:18)

Anything obvious? Any suggestions?

My apologies in advance if it's something I missed and thanks for this awesome project!!!!

Doubt with lightning-charge and nanotip

I don't know if this is the right place to ask for this. But the irc channel at freenode is kinda empty.
I have the following set up: A full bitcoin node and lightning node running c-lightning.
On top of my lighting node I have lightning charge and nanotip.

But in https://github.com/ElementsProject/lightning-charge it says the following

Note that Charge does not have TLS encryption and should not normally be exposed directly to the public internet. For remote access, you should setup an SSH tunnel or a TLS-enabled reverse proxy like nginx.

So a searched online and get my nanotip working using a ssh tunnel like this

$ ssh user@external_ip -R 9000:localhost:9112 -f -N

It is working and I think I did everything right!
My nanotip can be reached from the web but to create a invoice it uses port 9000. And that port has a ssh tunnel to 9112 port of lighting charge.
Is the correct approach?

Correctly handle 0 value invoices

These should be rejected I think.

LightningError: '0' is not a valid positive number  
    at createError (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/error/typed.js:31:22)                                                                                               
    at LightningClient.once.res (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/lightning-client/index.js:109:28)                                                                      
    at Object.onceWrapper (events.js:272:13)        
    at LightningClient.emit (events.js:180:13)      
    at Parser.LightningClient.parser.onValue (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/lightning-client/index.js:59:17)                                                          
    at Parser.proto.emit (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/jsonparse/jsonparse.js:337:8)                                                                                 
    at Parser.proto.pop (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/jsonparse/jsonparse.js:332:8)                                                                                  
    at Parser.proto.onToken (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/jsonparse/jsonparse.js:402:12)                                                                             
    at Parser.proto.write (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/jsonparse/jsonparse.js:135:34)                                                                               
    at Socket.LightningClient.client.on.data (/home/[redacted]/.npm-packages/lib/node_modules/lightning-charge/node_modules/lightning-client/index.js:54:53)                                                          
    at Socket.emit (events.js:180:13)               
    at addChunk (_stream_readable.js:269:12)        
    at readableAddChunk (_stream_readable.js:256:11)                                                     
    at Socket.Readable.push (_stream_readable.js:213:10)                                                 
    at Pipe.onread (net.js:581:20)

/invoice/:id/wait still uses default Express timeout

Like the title describes this path still uses the default timeout of Express which is set to 120 seconds.

Since Express is build on top of the built-in Node.js HTTP server, check this out:
https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_server_timeout

So if you tell the /invoice/wait call to timeout after 600 seconds it still gives you a empty reply after 120 seconds have passed. After that any lightning-charged-client wont understand this http code and will just throw an exception.

How to reproduce:

  1. Create a invoice with a expiry of 600 seconds.
  2. curl -v -m 600 http://api-token:[email protected]:9112/invoice/<invoice_id>/wait?timeout=600

After 120 seconds will result in:
curl: (52) Empty reply from server

Docker does not work with separate lightningd instance

The charge's docker is messed up if I use a separate lightningd.

if [ -S /etc/lightning/lightning-rpc ]; then
problem is: When the dependent lightningd start the socket is not yet created
So charge fire its own lightningd instance...
I think you should keep SKIP_BITCOIND and SKIP_LIGHTNINGD and wait for the file to be created.

npm installation fails

Command : sudo npm install -g lightning-charge

Hardware: raspberry pi 3

OS: Raspbian

Error

$ sudo npm install -g lightning-charge
npm ERR! code 128
npm ERR! Command failed: /usr/bin/git clone -q git://github.com/shesek/lightning-client-js.git /root/.npm/_cacache/tmp/git-clone-42cb7618
npm ERR! fatal: could not create leading directories of '/root/.npm/_cacache/tmp/git-clone-42cb7618': Permission denied
npm ERR! 

Im possibly doing something stupid here. Any insights?

npm install failed

npm install -g lightning-charge

npm ERR! code 1
npm ERR! Command failed: /usr/bin/git clone -q git://github.com/shesek/lightning-client-js.git /home/parmax/.npm/_cacache/tmp/git-clone-b5410c31
npm ERR! /home/parmax/.npm/_cacache/tmp/git-clone-b5410c31/.git: Permission denied
npm ERR!

npm ERR! A complete log of this run can be found in:
npm ERR! /home/parmax/.npm/_logs/2018-02-02T17_00_55_324Z-debug.log

ARMv7

Do you have any plans to release this to run on ARM processors? If not do you have any suggestions on how to change it to run on ARM?

Unexpected identifier error being thrown when evaluating CLI params

Running the following versions on a Centos 7.5.1804 box:

node v6.14.3
charged 0.4.0

Steps to reproduce:

Except for #45 trying to start charged with either:

charged --api-token NstxQtqsWHubkdbimZ --ln-path /home/username/.lightning --max-wait 90 --port 9112 --host xxx.xxx.xxx.xxx
charged --api-token NstxQtqsWHubkdbimZ --ln-path /home/username/.lightning --port 9112 --host xxx.xxx.xxx.xxx
charged --api-token NstxQtqsWHubkdbimZ --ln-path /home/username/.lightning/ --host xxx.xxx.xxx.xxx
charged --api-token NstxQtqsWHubkdbimZ --host xxx.xxx.xxx.xxx
charged --api-token NstxQtqsWHubkdbimZ --host 0.0.0.0
charged --api-token NstxQtqsWHubkdbimZ
charged --api-token NstxQtqsWHubk

charged -t NstxQtqsWHubkdbimZ -l /home/username/.lightning/ -d /home/username/.charged/sqlite.db -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t NstxQtqsWHubkdbimZ -l /home/username/.lightning/ -d ./.charged/sqlite.db -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t NstxQtqsWHubkdbimZ -l /home/username/.lightning -d ./.charged -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t NstxQtqsWHubkdbimZ -l /home/username/.lightning -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t NstxQtqsWHubkdbimZ -i xxx.xxx.xxx.xxx
charged -t NstxQtqsWHubkdbimZ
charged -t 1127589647 -l /home/username/.lightning -d /home/username/.charged/sqlite.db -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t 1127589647 -l /home/username/.lightning -d /home/username/.charged/sqlite.db -w 90 -p 9112 -i 0.0.0.0
charged -t 1127589647 -i 0.0.0.0
charged -t 1127589647 -l /home/username/.lightning -d /home/username/.charged/sqlite.db -w 90 -p 9112 -i 0.0.0.0
charged -t 1127589647 -l /home/username/.lightning --db-path ./charge.db -w 90 -p 9112 -i 0.0.0.0

... results in the following error being thrown:

/usr/lib/node_modules/lightning-charge/migrations/20180120115425_completed-fields.js:8
exports.down = async db => {
                     ^^

SyntaxError: Unexpected identifier
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:549:28)
    at Object.Module._extensions..js (module.js:586:10)
    at Module.load (module.js:494:32)
    at tryModuleLoad (module.js:453:12)
    at Function.Module._load (module.js:445:3)
    at Module.require (module.js:504:17)
    at require (internal/module.js:20:19)
    at /usr/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:137:25
    at arrayFilter (/usr/lib/node_modules/lightning-charge/node_modules/knex/node_modules/lodash/_arrayFilter.js:18:9)
    at filter (/usr/lib/node_modules/lightning-charge/node_modules/knex/node_modules/lodash/filter.js:45:10)
    at /usr/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:136:112
    at tryCatcher (/usr/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/usr/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:509:35)
    at Promise._settlePromise (/usr/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:569:18)
/usr/lib/node_modules/lightning-charge/migrations/20180120115425_completed-fields.js:8
exports.down = async db => {
                     ^^

SyntaxError: Unexpected identifier
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:549:28)
    at Object.Module._extensions..js (module.js:586:10)
    at Module.load (module.js:494:32)
    at tryModuleLoad (module.js:453:12)
    at Function.Module._load (module.js:445:3)
    at Module.require (module.js:504:17)
    at require (internal/module.js:20:19)
    at /usr/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:137:25
    at arrayFilter (/usr/lib/node_modules/lightning-charge/node_modules/knex/node_modules/lodash/_arrayFilter.js:18:9)
    at filter (/usr/lib/node_modules/lightning-charge/node_modules/knex/node_modules/lodash/filter.js:45:10)
    at /usr/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:136:112
    at tryCatcher (/usr/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/usr/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:509:35)
    at Promise._settlePromise (/usr/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:569:18)

Throttling

Would it be a good enhancement to enable throttling on creation of invoices?

Bandwidth?

I would like to give Lightning Charge a try on a cloud server, but I'm concerned about bandwidth.

How much bandwidth should I expect to use in a month?

Depending on how much bandwidth is needed, I may need to look into a home server for Lightning Charge.

Running lightning-charge on top of lnd/lncli

I know I'm skating on thin ice and risk breaking some eggshells 😉, but in the spirit of interoperability and friendly cooperation:

  • Is there a way of running the lightning-charge API on top of lightningnetwork/lnd?
  • Are there already projects out there trying this?
  • Is the REST API described in the README stable or are there still a lot of changes?
  • What events does the WebSocket API support?
  • Do you think the current test coverage is enough to run other ElementsProjects like e.g. nanopos on top of a compatible REST API or are they using a lot of undocumented stuff?

Display node URI below invoice

This is useful if the user doesn't have a path to your node yet or if all inbound channels are full. It could be an optional setting.

Unexpected identifier error

Good day,

Sorry if this is a noob question.

I've already setup bitcoind and lightningd in my machine.

The problem is whenever I run charged or charged --api-token mytokenhere it shows this error.

exports.down = async db => {
                     ^^

SyntaxError: Unexpected identifier
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:542:28)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at /home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:136:25
    at arrayFilter (/home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/lodash/_arrayFilter.js:18:9)
    at filter (/home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/lodash/filter.js:45:10)
    at /home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/knex/lib/migrate/index.js:135:112
    at tryCatcher (/home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:509:35)
    at Promise._settlePromise (/home/bitcoin/.npm-global/lib/node_modules/lightning-charge/node_modules/bluebird/js/release/promise.js:569:18)
/home/bitcoin/.npm-global/lib/node_modules/lightning-charge/migrations/20180120115425_completed-fields.js:8

Thanks

Error: SQLITE_CANTOPEN: unable to open database file

Running the following versions on a Centos 7.5.1804 box:

node v6.14.3
charged 0.4.0

Trying to start charged with either ...

charged -t NstxQtqsWHubkdbimZ -l /home/username/.lightning -d /home/username/.charged -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t NstxQtqsWHubkdbimZ -l /home/username/.lightning/ -d /home/username/.charged/ -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t 1127589647 -l /home/username/.lightning -d /home/username/.charged -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t 1127589647 -l /home/username/.lightning -d /home/username/.charged/ -w 90 -p 9112 -i xxx.xxx.xxx.xxx
charged -t 1127589647 -l /home/username/.lightning -d /home/username/.charged -w 90 -p 9112 -i 0.0.0.0

... results in the following error being thrown:

Error: SQLITE_CANTOPEN: unable to open database file
    at Error (native)
/usr/lib/node_modules/lightning-charge/dist/app.js:21
            throw err;
            ^

Error: SQLITE_CANTOPEN: unable to open database file
    at Error (native)

The sqlite.db file can be red and written by any user:

[username@host .charged]$ ls -al
total 20
drwxrwxr-x.  2 username username    23 Jul 10 21:28 .
drwx------. 12 username username  4096 Jul 10 21:33 ..
-rw-rw-rw-.  1 username username 16384 Jul 10 21:02 sqlite.db

Currency exchange conversion

Allow specifying invoice amounts in other currencies and convert to bitcoins. The invoice should lock-in the exchange rate for some pre-determined time, then expire.

Problem with sqlite3

charged --api-token password
Knex: run
$ npm install sqlite3 --save
Error: Cannot find module '/home/pi/.npm-global/lib/node_modules/lightning-charge/node_modules/sqlite3/lib/binding/node-v51-linux-arm/node_sqlite3.node'

and the followings always errors
npm install sqlite3 --save

Any idea?

charged ALWAYS reports that it is running on localhost, no matter what the host is set to, and will only respond to connections to localhost

using ubuntu 16.04 LTS, intel core i7-3770

$charged --api-token ??????? # defaults: --ln-path ~/.lightning --db-path ./charge.db --port 9112 --host 192.168.1.5

results in...
HTTP server running on localhost:9112

No GET /invoice/blaaa messages are being generated when I try to connect to http://192.168.1.5:9112/invoice/blaaa , I just get "connection refused".

I tried setting the ip and host on both lightningd (using --ipaddr) and charged, with no change.

I disabled firewall (ufw). no change.

If I connect to
http://127.0.0.1:9112/invoice/blaaa.
then everything works as expected.

so as far as I can tell, changing hosts from localhost, does nothing, and trying to connect to the server from any other interface other than localhost is refused.

Invoice expiry

Invoices should expire after some pre-determined timeout is reached. Especially important for invoices quoted in fiat currencies, where the exchange rate should only be locked-in for limited time.

Multiple API keys

Hi,

I would like to know if there is a plain (or if it is possible?) to create multiple api keys without runnning multiple charged instances?

Thank you!

Add authentication support

An initial simple implementation could require a shared secret token configure in .env to be provided using HTTP basic authentication headers. Once support is added here, authentication support should be added to the client libraries as well.

Cannot find module

Running charged gives me this error:

Knex: run
$ npm install sqlite3 --save
Error: Cannot find module '/usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3/lib/binding/node-v57-linux-x64/node_sqlite3.node'
    at Function.Module._resolveFilename (module.js:538:15)
    at Function.Module._load (module.js:468:25)
    at Module.require (module.js:587:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/usr/local/lib/node_modules/lightning-charge/node_modules/sqlite3/lib/sqlite3.js:4:15)
    at Module._compile (module.js:643:30)
    at Object.Module._extensions..js (module.js:654:10)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)
    at Module.require (module.js:587:17)
    at require (internal/module.js:11:18)
    at Client_SQLite3._driver (/usr/local/lib/node_modules/lightning-charge/node_modules/knex/lib/dialects/sqlite3/index.js:79:12)
    at Client_SQLite3.initializeDriver (/usr/local/lib/node_modules/lightning-charge/node_modules/knex/lib/client.js:249:26)
    at Client_SQLite3.Client (/usr/local/lib/node_modules/lightning-charge/node_modules/knex/lib/client.js:126:10)
    at new Client_SQLite3 (/usr/local/lib/node_modules/lightning-charge/node_modules/knex/lib/dialects/sqlite3/index.js:62:20)

I tried to find the node-v57-linux-x64 folder, but I could only find the node-v48-linux-x64 folder instead.

Start Up

What's the recommended way to start lightning-charge automatically on boot?

Exchange rate should be cached

I donno the bitcoinaverage's rate limit, but sometimes in my test env it happen that I get a 429 that is pretty annoying. Also there is no reason to overload bitcoinaverage of request when they update the ticket only every 15s.

exchange-rate.js could be replaced with:

import big from 'big.js'                                                                                                                                                                                                                                                        
import request from 'superagent'                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                
const FIXED_RATES    = { BTC: 1 }                                                                                                                                                                                                                                               
    , BTC_MSAT_RATIO = big('100000000000')                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                
const enc = encodeURIComponent                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                
const now = () => Date.now()                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                
// Fetch current exchange rate from BitcoinAverage                                                                                                                                                                                                                              
const getRate_ = millisecDelta => {                                                                                                                                                                                                                                            
  const cache = {}                                                                                                                                                                                                                                                              
  return (async (currency) => {                                                                                                                                                                                                                                                 
    const cached = cache[currency]                                                                                                                                                                                                                                              
    if (cached && (now() - cached.time) <= millisecDelta) {                                                                                                                                                                                                                     
      return cached.rate                                                                                                                                                                                                                                                        
    }                                                                                                                                                                                                                                                                           
    else {                                                                                                                                                                                                                                                                      
      try {                                                                                                                                                                                                                                                                     
        const rate  = (await request.get(`https://apiv2.bitcoinaverage.com/indices/global/ticker/short?crypto=BTC&fiat=${enc(currency)}`))                                                                                                                                      
          .body['BTC'+currency].last                                                                                                                                                                                                                                            
        cache[currency] = {rate, time: now()}                                                                                                                                                                                                                                   
        return rate                                                                                                                                                                                                                                                             
      }                                                                                                                                                                                                                                                                         
      catch(err) {                                                                                                                                                                                                                                                              
        return Promise.reject(err.status == 404 ? new Error('Unknown currency: '+currency) : err)                                                                                                                                                                               
      }                                                                                                                                                                                                                                                                         
    }                                                                                                                                                                                                                                                                           
  })                                                                                                                                                                                                                                                                            
}                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                
// bitcoinaverage update the ticker every 15 seconds                                                                                                                                                                                                                            
// one minute old prices seems resonable?                                                                                                                                                                                                                                       
const cacheDelta = Number.isNaN(parseInt(process.env.CACHE_D)) ? 0 : parseInt(process.env.CACHE_D)                                                                                                                                                                              
                                                                                                                                                                                                                                                                                
const getRate = getRate_(cacheDelta)                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                
// Convert `amount` units of `currency` to msatoshis                                                                                                                                                                                                                            
const toMsat = async (currency, amount) =>                                                                                                                                                                                                                                      
  big(amount)                                                                                                                                                                                                                                                                   
    .div(FIXED_RATES[currency] || await getRate(currency))                                                                                                                                                                                                                      
    .mul(BTC_MSAT_RATIO)                                                                                                                                                                                                                                                        
    .round(0, 3) // round up to nearest msatoshi                                                                                                                                                                                                                                
    .toFixed(0)                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                
module.exports = { getRate, toMsat }  

Note that we use env varse to set our cache, for example declared in a docker-compose file. And that there are no breaking changes cause the default behavior is to set the cache to 0ms.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.