Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
feat: attempt sendToRoute for first payment attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
mrfelton committed Mar 29, 2020
1 parent 2ae38c4 commit 1bce811
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 13 deletions.
2 changes: 2 additions & 0 deletions renderer/components/Pay/Pay.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import config from 'config'
import get from 'lodash/get'
import { injectIntl } from 'react-intl'
import { decodePayReq, getMaxFee, isOnchain, isBolt11, isPubkey } from '@zap/utils/crypto'
import { Panel } from 'components/UI'
Expand Down Expand Up @@ -245,6 +246,7 @@ class Pay extends React.Component {
payReq: values.payReq,
amt: this.amountInSats(),
feeLimit: getMaxFee(routes),
route: get(routes, '[0].isExact') && routes[0],
retries: config.invoices.retryCount,
})
// Clear payment request
Expand Down
2 changes: 1 addition & 1 deletion renderer/reducers/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ infoSelectors.commitString = createSelector(infoSelectors.version, version => {
return commitString ? commitString.replace('commit=', '') : undefined
})

// Check wether node has support for Router service
// Check whether node has support for Router service
infoSelectors.hasRouterSupport = createSelector(
infoSelectors.grpcProtoVersion,
version => {
Expand Down
9 changes: 5 additions & 4 deletions renderer/reducers/pay.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,10 @@ export const queryRoutes = (pubKey, amount) => async (dispatch, getState) => {

// Use payment probing if lnd version supports the Router service.
if (infoSelectors.hasRouterSupport(getState())) {
// First probe with a small amount for check for a valid route.
await grpc.services.Router.probePayment(pubKey, 1)
// Then probe with the full amount to check whether the channels contain enough balance for the payment.
routes.push(await grpc.services.Router.probePayment(pubKey, amount))
const route = await grpc.services.Router.probePayment(pubKey, amount)
// Flag this as an exact route. This can be used as a hint for whether to use sendToRoute to fulfil the payment.
route.isExact = true
routes.push(route)
}

// For older versions use queryRoutes.
Expand All @@ -239,6 +239,7 @@ export const queryRoutes = (pubKey, amount) => async (dispatch, getState) => {
})
routes = result
}

dispatch({ type: QUERY_ROUTES_SUCCESS, routes })
} catch (e) {
dispatch({ type: QUERY_ROUTES_FAILURE, error: e.message })
Expand Down
46 changes: 38 additions & 8 deletions renderer/reducers/payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,18 @@ const decPaymentRetry = paymentId => ({
* @param {number} options.amt Payment amount (in sats)
* @param {number} options.feeLimit The max fee to apply
* @param {number} options.retries Number of remaining retries
* @param {number} options.route Specific route to use.
* @param {string} options.originalPaymentId Id of the original payment if (required if this is a payment retry)
* @returns {Function} Thunk
*/
export const payInvoice = ({ payReq, amt, feeLimit, retries = 0, originalPaymentId }) => async (
dispatch,
getState
) => {
export const payInvoice = ({
payReq,
amt,
feeLimit,
route,
retries = 0,
originalPaymentId,
}) => async (dispatch, getState) => {
const paymentId = originalPaymentId || genId()
const isKeysend = isPubkey(payReq)
let pubkey
Expand Down Expand Up @@ -267,14 +272,39 @@ export const payInvoice = ({ payReq, amt, feeLimit, retries = 0, originalPayment

// Submit the payment to LND.
try {
let data
let data = { paymentId }

// Use Router service if lnd version supports it.
if (infoSelectors.hasRouterSupport(getState())()) {
data = await grpc.services.Router.sendPayment({
if (infoSelectors.hasRouterSupport(getState())) {
payload = {
...payload,
timeoutSeconds: PAYMENT_TIMEOUT,
})
}

// If this is the first payment attempt and we have been supplied with exact route, attempt to use route.
if (route && !originalPaymentId) {
try {
const routeToUse = { ...route }
delete routeToUse.isExact
const { failure } = await grpc.services.Router.sendToRoute({
paymentHash: Buffer.from(paymentHash, 'hex'),
route: routeToUse,
})
if (failure) {
const error = new Error(failure.code)
error.details = data
throw error
}
} catch (error) {
// If sendToRoute didn't work then try sendPayment.
data = await grpc.services.Router.sendPayment(payload)
}
}

// Otherwise, just use sendPayment.
else {
data = await grpc.services.Router.sendPayment(payload)
}
}

// For older versions use the legacy Lightning.sendPayment method.
Expand Down

0 comments on commit 1bce811

Please sign in to comment.