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

Commit

Permalink
feat(ui): show payment route on probe summary
Browse files Browse the repository at this point in the history
  • Loading branch information
mrfelton committed Nov 7, 2020
1 parent 1b64157 commit 62302b8
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 31 deletions.
12 changes: 6 additions & 6 deletions renderer/components/Activity/PaymentModal/Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ HtlcHops.propTypes = {
hops: PropTypes.array.isRequired,
}

const Htlc = ({ htlc, isAmountVisible = true, ...rest }) => {
const amountExcludingFees = CoinBig(htlc.route.totalAmt)
.minus(htlc.route.totalFees)
export const Htlc = ({ route, isAmountVisible = true, ...rest }) => {
const amountExcludingFees = CoinBig(route.totalAmt)
.minus(route.totalFees)
.toString()
return (
<Flex alignItems="center" justifyContent="space-between" {...rest}>
Expand All @@ -56,14 +56,14 @@ const Htlc = ({ htlc, isAmountVisible = true, ...rest }) => {
<CryptoSelector ml={2} />
</Text>
)}
<HtlcHops hops={htlc.route.hops} />
<HtlcHops hops={route.hops} />
</Flex>
)
}

Htlc.propTypes = {
htlc: PropTypes.object.isRequired,
isAmountVisible: PropTypes.bool.isRequired,
route: PropTypes.object.isRequired,
}

const Route = ({ htlcs, ...rest }) => {
Expand All @@ -75,7 +75,7 @@ const Route = ({ htlcs, ...rest }) => {
return (
<React.Fragment key={htlc.attemptTimeNs + htlc.resolveTimeNs}>
{!isFirst && <Bar my={2} opacity={0.2} variant="light" />}
<Htlc htlc={htlc} isAmountVisible={isMpp} />
<Htlc isAmountVisible={isMpp} route={htlc.route} />
</React.Fragment>
)
})}
Expand Down
1 change: 1 addition & 0 deletions renderer/components/Activity/PaymentModal/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export PaymentModal from './PaymentModal'
export Route from './Route'
1 change: 1 addition & 0 deletions renderer/components/Pay/PaySummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const PaySummary = props => {
minFee={getMinFee(routes)}
mt={-3}
payReq={payReq}
route={routes[0]}
/>
)
}
Expand Down
13 changes: 10 additions & 3 deletions renderer/components/Pay/PaySummaryLightning.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import BigArrowRight from 'components/Icon/BigArrowRight'
import { Bar, DataRow, Link, Spinner, Text, Tooltip } from 'components/UI'
import { CryptoSelector, CryptoValue, FiatValue } from 'containers/UI'
import { Truncate } from 'components/Util'
import { Htlc } from 'components/Activity/PaymentModal/Route'
import messages from './messages'

const ConfigLink = ({ feeLimit, openModal, ...rest }) => (
Expand All @@ -34,6 +35,7 @@ class PaySummaryLightning extends React.Component {
nodes: PropTypes.array,
openModal: PropTypes.func.isRequired,
payReq: PropTypes.string.isRequired,
route: PropTypes.object,
}

static defaultProps = {
Expand Down Expand Up @@ -110,6 +112,7 @@ class PaySummaryLightning extends React.Component {
minFee,
nodes,
payReq,
route,
...rest
} = this.props

Expand Down Expand Up @@ -157,9 +160,13 @@ class PaySummaryLightning extends React.Component {
</Text>
</Box>
<Box width={5 / 11}>
<Text className="hint--bottom-left" data-hint={payeeNodeKey} textAlign="right">
<Truncate maxlen={nodeAlias ? 30 : 15} text={nodeAlias || payeeNodeKey} />
</Text>
{route ? (
<Htlc route={route} />
) : (
<Text className="hint--bottom-left" data-hint={payeeNodeKey} textAlign="right">
<Truncate maxlen={nodeAlias ? 30 : 15} text={nodeAlias || payeeNodeKey} />
</Text>
)}
</Box>
</Flex>
</Box>
Expand Down
3 changes: 2 additions & 1 deletion renderer/containers/App/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from 'reducers/lnurl'
import { initBackupService } from 'reducers/backup'
import { infoSelectors } from 'reducers/info'
import { paySelectors } from 'reducers/pay'
import { setModals, modalSelectors } from 'reducers/modal'
import { fetchSuggestedNodes } from 'reducers/channels'
import { initTickers } from 'reducers/ticker'
Expand All @@ -26,7 +27,7 @@ const mapStateToProps = state => ({
activeWalletSettings: walletSelectors.activeWalletSettings(state),
isAppReady: appSelectors.isAppReady(state),
isSyncedToGraph: infoSelectors.isSyncedToGraph(),
redirectPayReq: state.pay.redirectPayReq,
redirectPayReq: paySelectors.redirectPayReq(state),
modals: modalSelectors.getModalState(state),
lnurlWithdrawParams: lnurlSelectors.lnurlWithdrawParams(state),
willShowLnurlAuthPrompt: lnurlSelectors.willShowLnurlAuthPrompt(state),
Expand Down
6 changes: 3 additions & 3 deletions renderer/containers/Channels/ChannelCreateForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { connect } from 'react-redux'
import ChannelCreateForm from 'components/Channels/ChannelCreateForm'
import { fetchTickers, tickerSelectors } from 'reducers/ticker'
import { openChannel } from 'reducers/channels'
import { queryFees } from 'reducers/pay'
import { queryFees, paySelectors } from 'reducers/pay'
import { balanceSelectors } from 'reducers/balance'
import { updateContactFormSearchQuery, contactFormSelectors } from 'reducers/contactsform'
import { walletSelectors } from 'reducers/wallet'
Expand All @@ -15,8 +15,8 @@ const mapStateToProps = state => ({
cryptoUnit: tickerSelectors.cryptoUnit(state),
walletBalance: balanceSelectors.walletBalanceConfirmed(state),
cryptoUnitName: tickerSelectors.cryptoUnitName(state),
isQueryingFees: state.pay.isQueryingFees,
onchainFees: state.pay.onchainFees,
isQueryingFees: paySelectors.isQueryingFees(state),
onchainFees: paySelectors.onchainFees(state),
lndTargetConfirmations: settingsSelectors.currentConfig(state).lndTargetConfirmations,
})

Expand Down
10 changes: 5 additions & 5 deletions renderer/containers/Pay.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { connect } from 'react-redux'
import { Pay } from 'components/Pay'
import { fetchTickers, tickerSelectors } from 'reducers/ticker'
import { setRedirectPayReq, queryFees, queryRoutes } from 'reducers/pay'
import { setRedirectPayReq, queryFees, queryRoutes, paySelectors } from 'reducers/pay'
import { balanceSelectors } from 'reducers/balance'
import { addFilter } from 'reducers/activity'
import { channelsSelectors } from 'reducers/channels'
Expand All @@ -18,11 +18,11 @@ const mapStateToProps = state => ({
channelBalance: balanceSelectors.channelBalance(state),
cryptoUnit: tickerSelectors.cryptoUnit(state),
cryptoUnitName: tickerSelectors.cryptoUnitName(state),
isQueryingFees: state.pay.isQueryingFees,
isQueryingFees: paySelectors.isQueryingFees(state),
lndTargetConfirmations: settingsSelectors.currentConfig(state).lndTargetConfirmations,
redirectPayReq: state.pay.redirectPayReq,
onchainFees: state.pay.onchainFees,
routes: state.pay.routes,
redirectPayReq: paySelectors.redirectPayReq(state),
onchainFees: paySelectors.onchainFees(state),
routes: paySelectors.routes(state),
maxOneTimeSend: channelsSelectors.maxOneTimeSend(state),
walletBalanceConfirmed: balanceSelectors.walletBalanceConfirmed(state),
})
Expand Down
3 changes: 2 additions & 1 deletion renderer/containers/Pay/PaySummaryLightning.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { connect } from 'react-redux'
import PaySummaryLightning from 'components/Pay/PaySummaryLightning'
import { paySelectors } from 'reducers/pay'
import { settingsSelectors } from 'reducers/settings'
import { tickerSelectors } from 'reducers/ticker'
import { networkSelectors } from 'reducers/network'
import { openModal } from 'reducers/modal'

const mapStateToProps = state => ({
cryptoUnitName: tickerSelectors.cryptoUnitName(state),
isQueryingRoutes: state.pay.isQueryingRoutes,
isQueryingRoutes: paySelectors.isQueryingRoutes(state),
nodes: networkSelectors.nodes(state),
feeLimit: settingsSelectors.currentConfig(state).payments.feeLimit,
})
Expand Down
6 changes: 3 additions & 3 deletions renderer/containers/Pay/PaySummaryOnChain.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { connect } from 'react-redux'
import PaySummaryOnChain from 'components/Pay/PaySummaryOnChain'
import { tickerSelectors } from 'reducers/ticker'
import { queryFees } from 'reducers/pay'
import { queryFees, paySelectors } from 'reducers/pay'
import { networkSelectors } from 'reducers/network'

const mapStateToProps = state => ({
cryptoUnitName: tickerSelectors.cryptoUnitName(state),
isQueryingFees: state.pay.isQueryingFees,
isQueryingFees: paySelectors.isQueryingFees(state),
nodes: networkSelectors.nodes(state),
onchainFees: state.pay.onchainFees,
onchainFees: paySelectors.onchainFees(state),
})

const mapDispatchToProps = {
Expand Down
1 change: 1 addition & 0 deletions renderer/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import lnurl from './lnurl'
* @property {import('./invoice').State} invoice Invoice reducer.
* @property {import('./lnurl').State} lnurl Lnurl reducer.
* @property {import('./network').State} network Network reducer.
* @property {import('./pay').State} pay Pay reducer.
* @property {import('./payment').State} payment Payment reducer.
* @property {import('./settings').State} settings Settings reducer.
* @property {import('./transaction').State} transaction Transaction reducer.
Expand Down
1 change: 1 addition & 0 deletions renderer/reducers/pay/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import payReducer from './reducer'

export default payReducer
export paySelectors from './selectors'
export * from './constants'
export * from './reducer'
export * from './ipc'
12 changes: 12 additions & 0 deletions renderer/reducers/pay/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,22 @@ const {
SET_REDIRECT_PAY_REQ,
} = constants

/**
* @typedef State
* @property {boolean} isQueryingRoutes Boolean indicating if routes are being probed
* @property {boolean} isQueryingFees Boolean indicating if fees are being queried
* @property {{fast:string|null, medium:string|null, slow:string|null}} onchainFees Onchain fee rates
* @property {string|null} queryFeesError Query fees error message
* @property {string|null} queryRoutesError Query routes error message
* @property {string|null} redirectPayReq Payrequest injected from external source
* @property {object[]} routes Routes from last probe attempt
*/

// ------------------------------------
// Initial State
// ------------------------------------

/** @type {State} */
const initialState = {
isQueryingRoutes: false,
isQueryingFees: false,
Expand Down
60 changes: 60 additions & 0 deletions renderer/reducers/pay/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { createSelector } from 'reselect'
import { networkSelectors } from 'reducers/network'
import { decorateRoute } from 'reducers/payment/utils'

/**
* @typedef {import('../index').State} State
*/

const routesSelector = state => state.pay.routes
const nodesSelector = state => networkSelectors.nodes(state)

/**
* routes - Routes relating to current payment probe..
*
* @param {State} state Redux state
* @returns {object} Config overrides
*/
export const routes = createSelector(routesSelector, nodesSelector, (routes, nodes) =>
routes.map(route => decorateRoute(route, nodes))
)

/**
* isQueryingFees - Is querying fees.
*
* @param {State} state Redux state
* @returns {boolean} Boolean indicating if fees are being queried
*/
const isQueryingFees = state => state.pay.isQueryingFees

/**
* isQueryingRoutes - Is querying routes.
*
* @param {State} state Redux state
* @returns {boolean} Boolean indicating if routes are being probed
*/
const isQueryingRoutes = state => state.pay.isQueryingRoutes

/**
* onchainFees - Onchain fee rates
*
* @param {State} state Redux state
* @returns {{fast:string|null, medium:string|null, slow:string|null}} Onchain fee rates
*/
const onchainFees = state => state.pay.onchainFees

/**
* redirectPayReq - Payrequest injected from external source
*
* @param {State} state Redux state
* @returns {string|null} Payrequest injected from external source
*/
const redirectPayReq = state => state.pay.redirectPayReq

export default {
isQueryingFees,
isQueryingRoutes,
onchainFees,
redirectPayReq,
routes,
}
42 changes: 33 additions & 9 deletions renderer/reducers/payment/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,7 @@ export const decoratePayment = (payment, nodes = []) => {

// Try to add some info about the nodes involved in payment htlcs.
if (payment.htlcs) {
const decoratedHtlcs = cloneDeep(payment.htlcs)
decoratedHtlcs.map(htlc => {
htlc.route.hops.map(hop => {
hop.alias = getNodeAlias(hop.pubKey, nodes)
return hop
})
return htlc
})
decoration.htlcs = decoratedHtlcs
decoration.htlcs = decorateHtlcs(payment.htlcs, nodes)
}

return {
Expand All @@ -91,6 +83,38 @@ export const decoratePayment = (payment, nodes = []) => {
}
}

/**
* decorateHtlcs - Decorate htlcs list with custom/computed properties.
*
* @param {object[]} htlcs Htlcs
* @param {object[]} nodes Nodes
* @returns {object} Decorated htlcs
*/
export const decorateHtlcs = (htlcs, nodes = []) => {
const decoratedHtlcs = cloneDeep(htlcs)
decoratedHtlcs.map(htlc => {
htlc.route = decorateRoute(htlc.route, nodes)
return htlc
})
return decoratedHtlcs
}

/**
* decorateRoute - Decorate route object with custom/computed properties.
*
* @param {object} route Htlcs
* @param {object[]} nodes Nodes
* @returns {object} Decorated route
*/
export const decorateRoute = (route, nodes = []) => {
const decoratedRoute = cloneDeep(route)
decoratedRoute.hops = decoratedRoute.hops.map(hop => {
hop.alias = getNodeAlias(hop.pubKey, nodes)
return hop
})
return decoratedRoute
}

/**
* prepareKeysendPayload - Prepare a keysend payment.
*
Expand Down

0 comments on commit 62302b8

Please sign in to comment.