Skip to content
Permalink
Browse files

feat(wallet): ability to include invoice routing hints

Add the ability for remote node operators to specify wether or not
routing hints should be included in invoices. This enables users of
remote nodes to better operate over private channels.

Fix #2165
  • Loading branch information...
mrfelton committed May 11, 2019
1 parent 82539f4 commit 815770408269bf5dbcd1b267378132aabdd08601
@@ -1,10 +1,23 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Box } from 'rebass'
import { Box, Flex } from 'rebass'
import { FormattedMessage, injectIntl, intlShape } from 'react-intl'
import { Bar, Button, Form, Header, Panel, Text, TextArea } from 'components/UI'
import {
Bar,
Button,
Form,
Header,
Label,
Panel,
Span,
Text,
TextArea,
Toggle,
Tooltip,
} from 'components/UI'
import { CurrencyFieldGroup } from 'containers/UI'
import Lightning from 'components/Icon/Lightning'
import Padlock from 'components/Icon/Padlock'
import RequestSummary from './RequestSummary'
import messages from './messages'

@@ -17,23 +30,17 @@ class Request extends React.Component {
}

static propTypes = {
/** Currently selected cryptocurrency (key). */
activeWalletSettings: PropTypes.shape({
type: PropTypes.string.isRequired,
}).isRequired,
createInvoice: PropTypes.func.isRequired,
/** Human readable chain name */
cryptoCurrency: PropTypes.string.isRequired,
/** Ticker symbol of the currently selected cryptocurrency. */
cryptoCurrencyTicker: PropTypes.string.isRequired,
/** Boolean indicating wether the form is being processed. If true, form buttons are disabled. */
cryptoName: PropTypes.string.isRequired,
/** Fetch fiat ticker data. */
fetchTickers: PropTypes.func.isRequired,
/** Lnd invoice object for the payment request */
intl: intlShape.isRequired,
/** Lightning Payment request. */
invoice: PropTypes.object,
/** Show a notification */
isProcessing: PropTypes.bool,
/** Create an invoice using the supplied details */
payReq: PropTypes.string,
showNotification: PropTypes.func.isRequired,
}
@@ -94,7 +101,7 @@ class Request extends React.Component {
*/
onSubmit = values => {
const { cryptoCurrency, createInvoice } = this.props
createInvoice(values.amountCrypto, cryptoCurrency, values.memo)
createInvoice(values.amountCrypto, cryptoCurrency, values.memo, values.routingHints)
}

/**
@@ -145,6 +152,7 @@ class Request extends React.Component {
css={{ resize: 'vertical', 'min-height': '48px' }}
field="memo"
label={intl.formatMessage({ ...messages.memo })}
mb={3}
name="memo"
placeholder={intl.formatMessage({ ...messages.memo_placeholder })}
rows={3}
@@ -156,11 +164,31 @@ class Request extends React.Component {
)
}

renderRoutingHints = () => (
<Flex alignItems="center" justifyContent="space-between">
<Flex>
<Span color="gray" fontSize="s" mr={2}>
<Padlock />
</Span>
<Flex>
<Label htmlFor="routingHints">
<FormattedMessage {...messages.routing_hints_label} />
</Label>
<Tooltip ml={1}>
<FormattedMessage {...messages.routing_hints_tooltip} />
</Tooltip>
</Flex>
</Flex>
<Toggle field="routingHints" />
</Flex>
)

/**
* Form renderer.
*/
render() {
const {
activeWalletSettings,
createInvoice,
cryptoCurrency,
cryptoCurrencyTicker,
@@ -209,6 +237,7 @@ class Request extends React.Component {
{this.renderHelpText()}
{this.renderAmountFields()}
{this.renderMemoField()}
{activeWalletSettings.type !== 'local' && this.renderRoutingHints()}
</React.Fragment>
) : (
<RequestSummary
@@ -12,6 +12,8 @@ export default defineMessages({
total: 'Total',
memo: 'Memo',
memo_placeholder: 'For example "Dinner last night"',
routing_hints_label: 'Include routing hints',
routing_hints_tooltip: 'Whether this invoice should include routing hints for private channels.',
memo_tooltip:
'Add some describer text to your payment request for the recipient to see when paying.',
not_paid: 'not paid',
@@ -3,8 +3,10 @@ import { Request } from 'components/Request'
import { fetchTickers, tickerSelectors } from 'reducers/ticker'
import { createInvoice, invoiceSelectors } from 'reducers/invoice'
import { showNotification } from 'reducers/notification'
import { walletSelectors } from 'reducers/wallet'

const mapStateToProps = state => ({
activeWalletSettings: walletSelectors.activeWalletSettings(state),
cryptoName: tickerSelectors.cryptoName(state),
cryptoCurrency: state.ticker.currency,
cryptoCurrencyTicker: tickerSelectors.currencyName(state),
@@ -96,7 +96,7 @@ export const receiveInvoices = ({ invoices }) => dispatch => {
}

// Send IPC event for creating an invoice
export const createInvoice = (amount, currency, memo) => async (dispatch, getState) => {
export const createInvoice = (amount, currency, memo, isPrivate) => async (dispatch, getState) => {
const state = getState()

// backend needs value in satoshis no matter what currency we are using
@@ -107,15 +107,15 @@ export const createInvoice = (amount, currency, memo) => async (dispatch, getSta
// Grab the activeWallet type from our local store. If the active connection type is local (light clients using
// neutrino) we will have to flag private as true when creating this invoice. All light cliets open private channels
// (both manual and autopilot ones). In order for these clients to receive money through these channels the invoices
// need to come with routing hints for private channels
// need to come with routing hints for private channels.
const activeWalletSettings = walletSelectors.activeWalletSettings(state)

try {
const grpc = await grpcService
const invoice = await grpc.services.Lightning.createInvoice({
value,
memo,
private: activeWalletSettings.type === 'local',
private: isPrivate || activeWalletSettings.type === 'local',
})
dispatch(createdInvoice(invoice))
} catch (e) {
@@ -89,11 +89,11 @@ async function getChannels() {
async function createInvoice(payload) {
const invoice = await this.addInvoice(payload)
const decodedInvoice = await this.decodePayReq({ pay_req: invoice.payment_request })

return {
...decodedInvoice,
memo: payload.memo,
value: payload.value,
private: payload.private,
r_hash: Buffer.from(invoice.r_hash, 'hex').toString('hex'),
payment_request: invoice.payment_request,
creation_date: Date.now() / 1000,

0 comments on commit 8157704

Please sign in to comment.
You can’t perform that action at this time.