github.com/decred/dcrlnd@v0.7.6/docs/grpc/javascript.md (about) 1 # How to write a simple `lnd` client in Javascript using `node.js` 2 3 ## Setup and Installation 4 5 First, you'll need to initialize a simple nodejs project: 6 ``` 7 npm init (or npm init -f if you want to use the default values without prompt) 8 ``` 9 10 Then you need to install the Javascript grpc and proto loader library 11 dependencies: 12 ``` 13 npm install @grpc/grpc-js @grpc/proto-loader --save 14 ``` 15 16 You also need to copy the `lnd` `lightning.proto` file in your project directory 17 (or at least somewhere reachable by your Javascript code). 18 19 The `lightning.proto` file is [located in the `lnrpc` directory of the `lnd` 20 sources](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/lightning.proto). 21 22 ### Imports and Client 23 24 Every time you work with Javascript gRPC, you will have to import `@grpc/grpc-js`, load 25 `lightning.proto`, and create a connection to your client like so. 26 27 Note that when an IP address is used to connect to the node (e.g. 192.168.1.21 instead of localhost) you need to add `--tlsextraip=192.168.1.21` to your `lnd` configuration and re-generate the certificate (delete tls.cert and tls.key and restart lnd). 28 29 ```js 30 const grpc = require('@grpc/grpc-js'); 31 const protoLoader = require('@grpc/proto-loader'); 32 const fs = require("fs"); 33 34 // Due to updated ECDSA generated tls.cert we need to let gprc know that 35 // we need to use that cipher suite otherwise there will be a handhsake 36 // error when we communicate with the lnd rpc server. 37 process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' 38 39 // We need to give the proto loader some extra options, otherwise the code won't 40 // fully work with lnd. 41 const loaderOptions = { 42 keepCase: true, 43 longs: String, 44 enums: String, 45 defaults: true, 46 oneofs: true 47 }; 48 const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions); 49 50 // Lnd cert is at ~/.lnd/tls.cert on Linux and 51 // ~/Library/Application Support/Lnd/tls.cert on Mac 52 let lndCert = fs.readFileSync("~/.lnd/tls.cert"); 53 let credentials = grpc.credentials.createSsl(lndCert); 54 let lnrpcDescriptor = grpc.loadPackageDefinition(packageDefinition); 55 let lnrpc = lnrpcDescriptor.lnrpc; 56 let lightning = new lnrpc.Lightning('localhost:10009', credentials); 57 ``` 58 59 ## Examples 60 61 Let's walk through some examples of Javascript gRPC clients. These examples 62 assume that you have at least two `lnd` nodes running, the RPC location of one 63 of which is at the default `localhost:10009`, with an open channel between the 64 two nodes. 65 66 ### Simple RPC 67 68 ```js 69 lightning.getInfo({}, function(err, response) { 70 if (err) { 71 console.log('Error: ' + err); 72 } 73 console.log('GetInfo:', response); 74 }); 75 ``` 76 77 You should get something like this in your console: 78 79 ``` 80 GetInfo: { identity_pubkey: '03c892e3f3f077ea1e381c081abb36491a2502bc43ed37ffb82e264224f325ff27', 81 alias: '', 82 num_pending_channels: 0, 83 num_active_channels: 1, 84 num_inactive_channels: 0, 85 num_peers: 1, 86 block_height: 1006, 87 block_hash: '198ba1dc43b4190e507fa5c7aea07a74ec0009a9ab308e1736dbdab5c767ff8e', 88 synced_to_chain: false, 89 testnet: false, 90 chains: [ 'bitcoin' ] } 91 ``` 92 93 ### Response-streaming RPC 94 95 ```js 96 let call = lightning.subscribeInvoices({}); 97 call.on('data', function(invoice) { 98 console.log(invoice); 99 }) 100 .on('end', function() { 101 // The server has finished sending 102 }) 103 .on('status', function(status) { 104 // Process status 105 console.log("Current status" + status); 106 }); 107 ``` 108 109 Now, create an invoice for your node at `localhost:10009`and send a payment to 110 it from another node. 111 ```bash 112 $ lncli addinvoice --amt=100 113 { 114 "r_hash": <RHASH>, 115 "pay_req": <PAYMENT_REQUEST> 116 } 117 $ lncli sendpayment --pay_req=<PAYMENT_REQUEST> 118 ``` 119 Your Javascript console should now display the details of the recently satisfied 120 invoice. 121 122 ### Bidirectional-streaming RPC 123 124 This example has a few dependencies: 125 ```shell 126 npm install --save async lodash bytebuffer 127 ``` 128 129 You can run the following in your shell or put it in a program and run it like 130 `node script.js` 131 132 ```js 133 // Load some libraries specific to this example 134 const async = require('async'); 135 const _ = require('lodash'); 136 const ByteBuffer = require('bytebuffer'); 137 138 let dest_pubkey = <RECEIVER_ID_PUBKEY>; 139 let dest_pubkey_bytes = ByteBuffer.fromHex(dest_pubkey); 140 141 // Set a listener on the bidirectional stream 142 let call = lightning.sendPayment(); 143 call.on('data', function(payment) { 144 console.log("Payment sent:"); 145 console.log(payment); 146 }); 147 call.on('end', function() { 148 // The server has finished 149 console.log("END"); 150 }); 151 152 // You can send single payments like this 153 call.write({ dest: dest_pubkey_bytes, amt: 6969 }); 154 155 // Or send a bunch of them like this 156 function paymentSender(destination, amount) { 157 return function(callback) { 158 console.log("Sending " + amount + " atoms"); 159 console.log("To: " + destination); 160 call.write({ 161 dest: destination, 162 amt: amount 163 }); 164 _.delay(callback, 2000); 165 }; 166 } 167 let payment_senders = []; 168 for (let i = 0; i < 10; i++) { 169 payment_senders[i] = paymentSender(dest_pubkey_bytes, 100); 170 } 171 async.series(payment_senders, function() { 172 call.end(); 173 }); 174 175 ``` 176 This example will send a payment of 100 atoms every 2 seconds. 177 178 179 ### Using Macaroons 180 181 To authenticate using macaroons you need to include the macaroon in the metadata 182 of each request. 183 184 The following snippet will add the macaroon to every request automatically: 185 186 ```js 187 const fs = require('fs'); 188 const grpc = require('@grpc/grpc-js'); 189 const protoLoader = require('@grpc/proto-loader'); 190 const loaderOptions = { 191 keepCase: true, 192 longs: String, 193 enums: String, 194 defaults: true, 195 oneofs: true 196 }; 197 const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions); 198 199 process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' 200 201 // Lnd admin macaroon is at ~/.lnd/data/chain/bitcoin/simnet/admin.macaroon on Linux and 202 // ~/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon on Mac 203 let m = fs.readFileSync('~/.lnd/data/chain/bitcoin/simnet/admin.macaroon'); 204 let macaroon = m.toString('hex'); 205 206 // build meta data credentials 207 let metadata = new grpc.Metadata() 208 metadata.add('macaroon', macaroon) 209 let macaroonCreds = grpc.credentials.createFromMetadataGenerator((_args, callback) => { 210 callback(null, metadata); 211 }); 212 213 // build ssl credentials using the cert the same as before 214 let lndCert = fs.readFileSync("~/.lnd/tls.cert"); 215 let sslCreds = grpc.credentials.createSsl(lndCert); 216 217 // combine the cert credentials and the macaroon auth credentials 218 // such that every call is properly encrypted and authenticated 219 let credentials = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds); 220 221 // Pass the crendentials when creating a channel 222 let lnrpcDescriptor = grpc.loadPackageDefinition(packageDefinition); 223 let lnrpc = lnrpcDescriptor.lnrpc; 224 let client = new lnrpc.Lightning('some.address:10009', credentials); 225 226 client.getInfo({}, (err, response) => { 227 if (err) { 228 console.log('Error: ' + err); 229 } 230 console.log('GetInfo:', response); 231 }); 232 ``` 233 234 ## Conclusion 235 236 With the above, you should have all the `lnd` related `gRPC` dependencies 237 installed locally in your project. In order to get up to speed with `protofbuf` 238 usage from Javascript, see [this official `protobuf` reference for 239 Javascript](https://developers.google.com/protocol-buffers/docs/reference/javascript-generated). 240 Additionally, [this official gRPC 241 resource](http://www.grpc.io/docs/tutorials/basic/node.html) provides more 242 details around how to drive `gRPC` from `node.js`. 243 244 ## API documentation 245 246 There is an [online API documentation](https://api.lightning.community?javascript) 247 available that shows all currently existing RPC methods, including code snippets 248 on how to use them.