diff --git a/app/lnd/index.js b/app/lnd/index.js index 572dee0c..2f2b5dcb 100644 --- a/app/lnd/index.js +++ b/app/lnd/index.js @@ -1,5 +1,6 @@ import config from './config' import lightning from './lib/lightning' +import { decodeInvoice } from './utils' const lnd = lightning(config.lightningRpc, config.lightningHost) @@ -70,6 +71,13 @@ export function invoices() { }) } +// LND Get Invoice +export function invoice(payreq) { + return new Promise((resolve, reject) => { + resolve(decodeInvoice(payreq)) + }) +} + // LND Get Wallet Balance const walletBalance = new Promise((resolve, reject) => { lnd.walletBalance({}, (err, data) => { @@ -110,6 +118,7 @@ export default { allChannels, payments, invoices, + invoice, balance, createInvoice } diff --git a/app/lnd/utils/index.js b/app/lnd/utils/index.js new file mode 100644 index 00000000..92489035 --- /dev/null +++ b/app/lnd/utils/index.js @@ -0,0 +1,37 @@ +import zbase32 from 'zbase32' + +function convertBigEndianBufferToLong(longBuffer) { + let longValue = 0 + const byteArray = Buffer.from(longBuffer).swap64() + + for (let i = byteArray.length - 1; i >= 0; i--) { + longValue = (longValue * 256) + byteArray[i] + } + + return longValue +} + +export function decodeInvoice(payreq) { + const payreqBase32 = zbase32.decode(payreq) + + const bufferHexRotated = Buffer.from(payreqBase32).toString('hex') + const bufferHex = bufferHexRotated.substr(bufferHexRotated.length - 1, bufferHexRotated.length) + + bufferHexRotated.substr(0, bufferHexRotated.length - 1) + const buffer = Buffer.from(bufferHex, 'hex') + + const pubKeyBuffer = buffer.slice(0, 33) + const pubKeyHex = pubKeyBuffer.toString('hex') + + const paymentHashBuffer = buffer.slice(33, 65) + const paymentHashHex = paymentHashBuffer.toString('hex') + + const valueBuffer = buffer.slice(65, 73) + + const amount = convertBigEndianBufferToLong(valueBuffer) + + return { + payreq, + amount, + r_hash: paymentHashHex, + } +} \ No newline at end of file diff --git a/app/main.dev.js b/app/main.dev.js index 4a662192..a2be9e38 100644 --- a/app/main.dev.js +++ b/app/main.dev.js @@ -123,6 +123,15 @@ ipcMain.on('lnd', (event, { msg, data }) => { .then(invoices => event.sender.send('receiveInvoices', invoices)) .catch(error => console.log('info error: ', error)) break + case 'invoice': + // Data looks like { invoices: [] } + lnd.invoice(data.payreq) + .then(invoice => { + console.log('invoice: ', invoice) + event.sender.send('receiveInvoice', invoice) + }) + .catch(error => console.log('info error: ', error)) + break case 'balance': // Balance looks like [ { balance: '129477456' }, { balance: '243914' } ] lnd.balance() diff --git a/app/reducers/invoice.js b/app/reducers/invoice.js index f58f1bcc..5c6c25f4 100644 --- a/app/reducers/invoice.js +++ b/app/reducers/invoice.js @@ -51,13 +51,6 @@ export function receiveInvoice(invoice) { } } -export function receiveFormInvoice(formInvoice) { - return { - type: RECEIVE_FORM_INVOICE, - formInvoice - } -} - export function getInvoices() { return { type: GET_INVOICES @@ -70,31 +63,21 @@ export function sendInvoice() { } } -export function invoiceSuccessful(invoice) { - return { - type: INVOICE_SUCCESSFUL, - invoice - } -} - export function invoiceFailed() { return { type: INVOICE_FAILED } } -export const fetchInvoice = payreq => async (dispatch) => { +// Send IPC event for a specific invoice +export const fetchInvoice = payreq => dispatch => { dispatch(getInvoice()) - const invoice = await callApi(`invoice/${payreq}`, 'get') - - if (invoice) { - dispatch(receiveFormInvoice(invoice.data)) - return true - } - dispatch(invoiceFailed()) - return false + ipcRenderer.send('lnd', { msg: 'invoice', data: { payreq } }) } +// Receive IPC event for form invoice +export const receiveFormInvoice = (event, formInvoice) => dispatch => dispatch({ type: RECEIVE_FORM_INVOICE, formInvoice }) + // Send IPC event for invoices export const fetchInvoices = () => dispatch => { dispatch(getInvoices()) diff --git a/app/reducers/ipc.js b/app/reducers/ipc.js index 45638d23..97f06cee 100644 --- a/app/reducers/ipc.js +++ b/app/reducers/ipc.js @@ -3,7 +3,7 @@ import { receiveInfo } from './info' import { receivePeers } from './peers' import { receiveChannels } from './channels' import { receivePayments } from './payment' -import { receiveInvoices, createdInvoice } from './invoice' +import { receiveInvoices, createdInvoice, receiveFormInvoice } from './invoice' import { receiveBalance } from './balance' // Import all receiving IPC event handlers and pass them into createIpc @@ -13,6 +13,7 @@ const ipc = createIpc({ 'receiveChannels': receiveChannels, 'receivePayments': receivePayments, 'receiveInvoices': receiveInvoices, + 'receiveInvoice': receiveFormInvoice, 'receiveBalance': receiveBalance, 'createdInvoice': createdInvoice }) diff --git a/package.json b/package.json index 1cfa0120..6994a903 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,8 @@ "reselect": "^3.0.1", "satoshi-bitcoin": "^1.0.4", "source-map-support": "^0.4.15", - "xtend": "^4.0.1" + "xtend": "^4.0.1", + "zbase32": "^0.0.2" }, "devEngines": { "node": ">=7.x", diff --git a/yarn.lock b/yarn.lock index 1ee04b9c..daedb418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9271,6 +9271,10 @@ yauzl@2.4.1: dependencies: fd-slicer "~1.0.1" +zbase32@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/zbase32/-/zbase32-0.0.2.tgz#169c6f2130a6c27a84247017538b56826a54b283" + zip-stream@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.1.1.tgz#5216b48bbb4d2651f64d5c6e6f09eb4a7399d557"