From 1bdf250ebc1703a18bbe7d992e711743434dd5b1 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sun, 12 Jan 2020 10:47:25 +0100 Subject: [PATCH 01/13] Redirect navigation flow for 0 value invocies. Detecting a zero amount invoice in checkType we redirect to a seperate view. Currently only title is changed in the view. --- jsconfig.json | 10 ++ src/action/nav-mobile.js | 4 + src/action/nav.js | 4 + src/action/payment.js | 9 +- src/view/main-mobile.js | 6 ++ src/view/main.js | 4 + .../pay-lightning-supply-amount-mobile.js | 88 ++++++++++++++++++ src/view/pay-lightning-supply-amount.js | 91 +++++++++++++++++++ 8 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 jsconfig.json create mode 100644 src/view/pay-lightning-supply-amount-mobile.js create mode 100644 src/view/pay-lightning-supply-amount.js diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 000000000..94279b62b --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2017", + "allowSyntheticDefaultImports": true, + "noEmit": true, + "checkJs": true, + "jsx": "react", + "lib": [ "dom", "es2017" ] + } +} diff --git a/src/action/nav-mobile.js b/src/action/nav-mobile.js index 9312cffbb..6328ec3af 100644 --- a/src/action/nav-mobile.js +++ b/src/action/nav-mobile.js @@ -119,6 +119,10 @@ class NavAction { this._navigate('Pay'); } + goPayLightningSupplyAmount() { + this._navigate('PayLightningSupplyAmount'); + } + goPayLightningConfirm() { this._navigate('PayLightningConfirm'); } diff --git a/src/action/nav.js b/src/action/nav.js index 3fb5cc945..d16098e05 100644 --- a/src/action/nav.js +++ b/src/action/nav.js @@ -81,6 +81,10 @@ class NavAction { this._store.route = 'Pay'; } + goPayLightningSupplyAmount() { + this._store.route = 'PayLightningSupplyAmount'; + } + goPayLightningConfirm() { this._store.route = 'PayLightningConfirm'; } diff --git a/src/action/payment.js b/src/action/payment.js index ea779b066..c4628932f 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -165,7 +165,14 @@ class PaymentAction { return this._notification.display({ msg: 'Enter an invoice or address' }); } if (await this.decodeInvoice({ invoice: this._store.payment.address })) { - this._nav.goPayLightningConfirm(); + if ( + this._store.payment.amount === '0' || + this._store.payment.amount === 0 + ) { + this._nav.goPayLightningSupplyAmount(); + } else { + this._nav.goPayLightningConfirm(); + } } else if (isAddress(this._store.payment.address)) { this._nav.goPayBitcoin(); } else { diff --git a/src/view/main-mobile.js b/src/view/main-mobile.js index 7e9a2dee1..5e00347ea 100644 --- a/src/view/main-mobile.js +++ b/src/view/main-mobile.js @@ -33,6 +33,7 @@ import SettingUnitView from './setting-unit'; import SettingFiatView from './setting-fiat'; import CLIView from './cli'; import PaymentView from './payment-mobile'; +import PayLightningSupplyAmountView from './pay-lightning-supply-amount-mobile'; import PayLightningConfirmView from './pay-lightning-confirm-mobile'; import PayLightningDoneView from './pay-lightning-done-mobile'; import PaymentFailedView from './payment-failed-mobile'; @@ -171,6 +172,10 @@ const InvoiceQR = () => ( const Pay = () => ; +const PayLightningSupplyAmount = () => ( + +); + const PayLightningConfirm = () => ( ); @@ -236,6 +241,7 @@ const InvoiceStack = createStackNavigator( const PayStack = createStackNavigator( { Pay, + PayLightningSupplyAmount, PayLightningConfirm, Wait, PayLightningDone, diff --git a/src/view/main.js b/src/view/main.js index 8066ace05..4100609d6 100644 --- a/src/view/main.js +++ b/src/view/main.js @@ -21,6 +21,7 @@ import LoaderSyncing from './loader-syncing'; import Wait from './wait'; import Home from './home'; import Payment from './payment'; +import PayLightningSupplyAmount from './pay-lightning-supply-amount'; import PayLightningConfirm from './pay-lightning-confirm'; import PayLightningDone from './pay-lightning-done'; import PaymentFailed from './payment-failed'; @@ -130,6 +131,9 @@ class MainView extends Component { {route === 'Pay' && ( )} + {route === 'PayLightningSupplyAmount' && ( + + )} {route === 'PayLightningConfirm' && ( )} diff --git a/src/view/pay-lightning-supply-amount-mobile.js b/src/view/pay-lightning-supply-amount-mobile.js new file mode 100644 index 000000000..7d4c89da1 --- /dev/null +++ b/src/view/pay-lightning-supply-amount-mobile.js @@ -0,0 +1,88 @@ +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { observer } from 'mobx-react'; +import PropTypes from 'prop-types'; +import Background from '../component/background'; +import MainContent from '../component/main-content'; +import { NamedField } from '../component/field'; +import { Header, Title } from '../component/header'; +import { CancelButton, BackButton, SmallGlasButton } from '../component/button'; +import Card from '../component/card'; +import LightningBoltIcon from '../asset/icon/lightning-bolt'; +import { FormStretcher } from '../component/form'; +import { + BalanceLabel, + BalanceLabelNumeral, + BalanceLabelUnit, +} from '../component/label'; +import { color } from '../component/style'; + +const styles = StyleSheet.create({ + balance: { + marginBottom: 10, + }, + numeral: { + color: color.blackText, + }, + unit: { + color: color.blackText, + }, + totalLbl: { + marginTop: 5, + }, + note: { + marginTop: 5, + borderBottomWidth: 0, + }, + confirmBtn: { + marginTop: 20, + }, +}); + +const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( + +
+ nav.goPay()} /> + + <LightningBoltIcon height={12} width={6.1} /> + + nav.goHome()} /> +
+ + + + + + {store.paymentAmountLabel} + + + {store.unitLabel} + + + + {store.paymentFeeLabel} {store.unitLabel} + + + {store.paymentTotalLabel} {store.unitLabel} + + {store.payment.note ? ( + + {store.payment.note} + + ) : null} + + + + payment.payLightning()}> + Confirm + +
+); + +PayLightningSupplyAmountView.propTypes = { + store: PropTypes.object.isRequired, + nav: PropTypes.object.isRequired, + payment: PropTypes.object.isRequired, +}; + +export default observer(PayLightningSupplyAmountView); diff --git a/src/view/pay-lightning-supply-amount.js b/src/view/pay-lightning-supply-amount.js new file mode 100644 index 000000000..f7d9fb92b --- /dev/null +++ b/src/view/pay-lightning-supply-amount.js @@ -0,0 +1,91 @@ +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { observer } from 'mobx-react'; +import PropTypes from 'prop-types'; +import Background from '../component/background'; +import MainContent from '../component/main-content'; +import { NamedField } from '../component/field'; +import { Header, Title } from '../component/header'; +import { CancelButton, BackButton, PillButton } from '../component/button'; +import Card from '../component/card'; +import LightningBoltIcon from '../asset/icon/lightning-bolt'; +import { FormStretcher } from '../component/form'; +import { + BalanceLabel, + BalanceLabelNumeral, + BalanceLabelUnit, +} from '../component/label'; +import { color } from '../component/style'; + +const styles = StyleSheet.create({ + balance: { + marginBottom: 10, + }, + numeral: { + color: color.blackText, + }, + unit: { + color: color.blackText, + }, + totalLbl: { + marginTop: 5, + }, + note: { + marginTop: 5, + borderBottomWidth: 0, + }, + confirmBtn: { + marginTop: 20, + }, +}); + +const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( + +
+ nav.goPay()} /> + + <LightningBoltIcon height={12} width={6.1} /> + + nav.goHome()} /> +
+ + + + + + {store.paymentAmountLabel} + + + {store.unitLabel} + + + + {store.paymentFeeLabel} {store.unitLabel} + + + {store.paymentTotalLabel} {store.unitLabel} + + {store.payment.note ? ( + + {store.payment.note} + + ) : null} + + payment.payLightning()} + > + Confirm + + + +
+); + +PayLightningSupplyAmountView.propTypes = { + store: PropTypes.object.isRequired, + nav: PropTypes.object.isRequired, + payment: PropTypes.object.isRequired, +}; + +export default observer(PayLightningSupplyAmountView); From 659cdb3094a034d18585d401ed0ff0f25c5b49d6 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sun, 12 Jan 2020 13:17:40 +0100 Subject: [PATCH 02/13] Unit tests for goPayLightningSupplyAmount and checkType. --- test/unit/action/nav.spec.js | 7 +++++++ test/unit/action/payment.spec.js | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/test/unit/action/nav.spec.js b/test/unit/action/nav.spec.js index c65ffa2c5..f2bedb5ee 100644 --- a/test/unit/action/nav.spec.js +++ b/test/unit/action/nav.spec.js @@ -116,6 +116,13 @@ describe('Action Nav Unit Tests', () => { }); }); + describe('goPayLightningSupplyAmount()', () => { + it('should set correct route', () => { + nav.goPayLightningSupplyAmount(); + expect(store.route, 'to equal', 'PayLightningSupplyAmount'); + }); + }); + describe('goPayLightningConfirm()', () => { it('should set correct route', () => { nav.goPayLightningConfirm(); diff --git a/test/unit/action/payment.spec.js b/test/unit/action/payment.spec.js index 93931b26a..25a1848bf 100644 --- a/test/unit/action/payment.spec.js +++ b/test/unit/action/payment.spec.js @@ -302,6 +302,14 @@ describe('Action Payments Unit Tests', () => { expect(payment.decodeInvoice, 'was not called'); }); + it('should detect zero amount payment', async () => { + store.payment.address = 'some-address'; + store.payment.amount = '0'; + payment.decodeInvoice.resolves(true); + await payment.checkType(); + expect(nav.goPayLightningSupplyAmount, 'was called once'); + }); + it('should decode successfully', async () => { store.payment.address = 'some-address'; payment.decodeInvoice.resolves(true); From 8157247007c962fcdae3c7908bb702bb20736b89 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 18 Jan 2020 18:33:48 +0100 Subject: [PATCH 03/13] Unpolished but working desktop zero value payments. --- src/action/payment.js | 33 ++++++++++- src/view/pay-lightning-supply-amount.js | 78 +++++++++++++------------ test/unit/action/payment.spec.js | 22 ++++++- 3 files changed, 92 insertions(+), 41 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index c4628932f..83e06f829 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -206,6 +206,26 @@ class PaymentAction { } } + /** + * Estimate the lightning transaction fee using the queryRoutes grpc api + * after which the fee is set in the store. + * @param {number} options.satAmt The amount to be payed in satoshis + * @return {Promise} + */ + async estimateLightningFeeForAmount({ amount }) { + try { + const request = await this._grpc.sendCommand('decodePayReq', { + payReq: this._store.payment.address, + }); + this.estimateLightningFee({ + destination: request.destination, + satAmt: toSatoshis(amount, this._store.settings), + }); + } catch (err) { + log.info(`Estimating lightning fee failed!`, err); + } + } + /** * Estimate the lightning transaction fee using the queryRoutes grpc api * after which the fee is set in the store. @@ -328,7 +348,8 @@ class PaymentAction { } /** - * Send the amount specified in the invoice as a lightning transaction and + * Send the amount specified in the payment.amount. If zero use the amount + * specified in the invoice as a lightning transaction and * display the wait screen while the payment confirms. * This action can be called from a view event handler as does all * the necessary error handling and notification display. @@ -343,6 +364,8 @@ class PaymentAction { try { this._nav.goWait(); const invoice = this._store.payment.address; + const { settings } = this._store; + const satAmt = toSatoshis(this._store.payment.amount, settings); const stream = this._grpc.sendStreamCommand('sendPayment'); await new Promise((resolve, reject) => { stream.on('data', data => { @@ -353,7 +376,13 @@ class PaymentAction { } }); stream.on('error', reject); - stream.write(JSON.stringify({ paymentRequest: invoice }), 'utf8'); + stream.write( + JSON.stringify({ + paymentRequest: invoice, + amt: satAmt, + }), + 'utf8' + ); }); if (failed) return; this._nav.goPayLightningDone(); diff --git a/src/view/pay-lightning-supply-amount.js b/src/view/pay-lightning-supply-amount.js index f7d9fb92b..340065b20 100644 --- a/src/view/pay-lightning-supply-amount.js +++ b/src/view/pay-lightning-supply-amount.js @@ -4,67 +4,71 @@ import { observer } from 'mobx-react'; import PropTypes from 'prop-types'; import Background from '../component/background'; import MainContent from '../component/main-content'; -import { NamedField } from '../component/field'; +import { NamedField, AmountInputField } from '../component/field'; import { Header, Title } from '../component/header'; -import { CancelButton, BackButton, PillButton } from '../component/button'; +import { + MaxButton, + CancelButton, + BackButton, + PillButton, +} from '../component/button'; import Card from '../component/card'; import LightningBoltIcon from '../asset/icon/lightning-bolt'; -import { FormStretcher } from '../component/form'; -import { - BalanceLabel, - BalanceLabelNumeral, - BalanceLabelUnit, -} from '../component/label'; +import { FormStretcher, FormText } from '../component/form'; +import { BalanceLabel, BalanceLabelUnit } from '../component/label'; import { color } from '../component/style'; const styles = StyleSheet.create({ - balance: { - marginBottom: 10, - }, - numeral: { - color: color.blackText, + description: { + paddingLeft: 20, + paddingRight: 20, }, unit: { color: color.blackText, }, - totalLbl: { - marginTop: 5, - }, - note: { - marginTop: 5, - borderBottomWidth: 0, + maxBtn: { + marginTop: 10, + marginBottom: 20, }, - confirmBtn: { + nextBtn: { marginTop: 20, + backgroundColor: color.purple, }, }); const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( - -
- nav.goPay()} /> - + <Background color={color.purple}> + <Header color={color.purple}> + <BackButton onPress={() => nav.goHome()} /> + <Title title="Specify Amount to Send"> <LightningBoltIcon height={12} width={6.1} /> nav.goHome()} />
+ + The invoice did not specify an amount. + - - {store.paymentAmountLabel} - + payment.setAmount({ amount })} + onSubmitEditing={() => + payment.estimateLightningFeeForAmount(payment.amount) + } + /> - {store.unitLabel} + {store.unitFiatLabel} - - {store.paymentFeeLabel} {store.unitLabel} - - - {store.paymentTotalLabel} {store.unitLabel} - + payment.toggleMax()} + /> {store.payment.note ? ( {store.payment.note} @@ -72,10 +76,10 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( ) : null} payment.payLightning()} + style={styles.nextBtn} + onPress={() => nav.goPayLightningConfirm()} > - Confirm + Pay diff --git a/test/unit/action/payment.spec.js b/test/unit/action/payment.spec.js index 25a1848bf..486443b3f 100644 --- a/test/unit/action/payment.spec.js +++ b/test/unit/action/payment.spec.js @@ -469,7 +469,7 @@ describe('Action Payments Unit Tests', () => { }); }); - it('should send lightning payment', async () => { + it('should send lightning payment with amount 0 if not specified.', async () => { paymentsOnStub.withArgs('data').yields({ paymentError: '' }); payment.setAddress({ address: 'lightning:some-invoice' }); await payment.payLightning(); @@ -477,7 +477,25 @@ describe('Action Payments Unit Tests', () => { expect( paymentsWriteStub, 'was called with', - JSON.stringify({ paymentRequest: 'some-invoice' }), + JSON.stringify({ paymentRequest: 'some-invoice', amt: 0 }), + 'utf8' + ); + expect(nav.goWait, 'was called once'); + expect(nav.goPayLightningDone, 'was called once'); + expect(notification.display, 'was not called'); + }); + + it('should send lightning payment with amount.', async () => { + paymentsOnStub.withArgs('data').yields({ paymentError: '' }); + payment.setAddress({ address: 'lightning:some-invoice' }); + store.settings.unit = 'btc'; + payment.setAmount({ amount: '0.0001' }); + await payment.payLightning(); + expect(grpc.sendStreamCommand, 'was called with', 'sendPayment'); + expect( + paymentsWriteStub, + 'was called with', + JSON.stringify({ paymentRequest: 'some-invoice', amt: 10000 }), 'utf8' ); expect(nav.goWait, 'was called once'); From 6e87b2ddbd26598a1a13d53719425d6951219f02 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 18 Jan 2020 21:11:27 +0100 Subject: [PATCH 04/13] Unpolished zero value invoice support for mobile. --- .../pay-lightning-supply-amount-mobile.js | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/view/pay-lightning-supply-amount-mobile.js b/src/view/pay-lightning-supply-amount-mobile.js index 7d4c89da1..52fcc69ea 100644 --- a/src/view/pay-lightning-supply-amount-mobile.js +++ b/src/view/pay-lightning-supply-amount-mobile.js @@ -4,17 +4,13 @@ import { observer } from 'mobx-react'; import PropTypes from 'prop-types'; import Background from '../component/background'; import MainContent from '../component/main-content'; -import { NamedField } from '../component/field'; +import { NamedField, AmountInputField } from '../component/field'; import { Header, Title } from '../component/header'; import { CancelButton, BackButton, SmallGlasButton } from '../component/button'; import Card from '../component/card'; import LightningBoltIcon from '../asset/icon/lightning-bolt'; import { FormStretcher } from '../component/form'; -import { - BalanceLabel, - BalanceLabelNumeral, - BalanceLabelUnit, -} from '../component/label'; +import { BalanceLabel, BalanceLabelUnit } from '../component/label'; import { color } from '../component/style'; const styles = StyleSheet.create({ @@ -52,19 +48,19 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( - - {store.paymentAmountLabel} - + payment.setAmount({ amount })} + onSubmitEditing={() => + payment.estimateLightningFeeForAmount(payment.amount) + } + /> - {store.unitLabel} + {store.unitFiatLabel} - - {store.paymentFeeLabel} {store.unitLabel} - - - {store.paymentTotalLabel} {store.unitLabel} - {store.payment.note ? ( {store.payment.note} @@ -73,7 +69,7 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( - payment.payLightning()}> + nav.goPayLightningConfirm()}> Confirm
From e9bbbcf79e962cee4fd45c1ec77af391157fe6f0 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 25 Jan 2020 14:06:13 +0100 Subject: [PATCH 05/13] Use the same background as similar views. --- src/view/pay-lightning-supply-amount.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/pay-lightning-supply-amount.js b/src/view/pay-lightning-supply-amount.js index 340065b20..e18947d97 100644 --- a/src/view/pay-lightning-supply-amount.js +++ b/src/view/pay-lightning-supply-amount.js @@ -37,7 +37,7 @@ const styles = StyleSheet.create({ }); const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( - +
nav.goHome()} /> From 44d784b3c9788a2cb06c55be93975b652a43feb6 Mon Sep 17 00:00:00 2001 From: Emil Johansson <emil.sweden@gmail.com> Date: Sat, 25 Jan 2020 14:40:25 +0100 Subject: [PATCH 06/13] Attempt at more polished UI. --- .../pay-lightning-supply-amount-mobile.js | 64 +++++++++---------- src/view/pay-lightning-supply-amount.js | 55 ++++++++-------- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/src/view/pay-lightning-supply-amount-mobile.js b/src/view/pay-lightning-supply-amount-mobile.js index 52fcc69ea..dddd1fa5f 100644 --- a/src/view/pay-lightning-supply-amount-mobile.js +++ b/src/view/pay-lightning-supply-amount-mobile.js @@ -6,71 +6,69 @@ import Background from '../component/background'; import MainContent from '../component/main-content'; import { NamedField, AmountInputField } from '../component/field'; import { Header, Title } from '../component/header'; -import { CancelButton, BackButton, SmallGlasButton } from '../component/button'; +import { CancelButton, Button, SmallGlasButton } from '../component/button'; import Card from '../component/card'; import LightningBoltIcon from '../asset/icon/lightning-bolt'; -import { FormStretcher } from '../component/form'; +import { FormStretcher, FormSubText } from '../component/form'; import { BalanceLabel, BalanceLabelUnit } from '../component/label'; import { color } from '../component/style'; const styles = StyleSheet.create({ balance: { - marginBottom: 10, - }, - numeral: { - color: color.blackText, + marginTop: 15, }, unit: { color: color.blackText, }, - totalLbl: { - marginTop: 5, - }, - note: { - marginTop: 5, - borderBottomWidth: 0, + form: { + paddingTop: 10, + paddingBottom: 10, }, - confirmBtn: { - marginTop: 20, + subText: { + paddingTop: 40, + paddingBottom: 40, }, }); const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( <Background color={color.purple}> <Header color={color.purple}> - <BackButton onPress={() => nav.goPay()} /> - <Title title="Supply Lightning Payment Amount"> + <Button disabled onPress={() => {}} /> + <Title title="Payment Request For Any Amount"> <LightningBoltIcon height={12} width={6.1} /> nav.goHome()} />
- - - - payment.setAmount({ amount })} - onSubmitEditing={() => - payment.estimateLightningFeeForAmount(payment.amount) - } - /> - - {store.unitFiatLabel} - - + + + payment.setAmount({ amount })} + onSubmitEditing={() => + payment.estimateLightningFeeForAmount(payment.amount) + } + /> + + {store.unitFiatLabel} + + + {store.payment.note ? ( {store.payment.note} ) : null} + + Payment Request did not specify an amount. This is often used for + tips/donations. + nav.goPayLightningConfirm()}> - Confirm + Pay
); diff --git a/src/view/pay-lightning-supply-amount.js b/src/view/pay-lightning-supply-amount.js index e18947d97..d9cfeaa3a 100644 --- a/src/view/pay-lightning-supply-amount.js +++ b/src/view/pay-lightning-supply-amount.js @@ -6,15 +6,10 @@ import Background from '../component/background'; import MainContent from '../component/main-content'; import { NamedField, AmountInputField } from '../component/field'; import { Header, Title } from '../component/header'; -import { - MaxButton, - CancelButton, - BackButton, - PillButton, -} from '../component/button'; +import { CancelButton, BackButton, PillButton } from '../component/button'; import Card from '../component/card'; import LightningBoltIcon from '../asset/icon/lightning-bolt'; -import { FormStretcher, FormText } from '../component/form'; +import { FormStretcher, FormSubText } from '../component/form'; import { BalanceLabel, BalanceLabelUnit } from '../component/label'; import { color } from '../component/style'; @@ -34,46 +29,48 @@ const styles = StyleSheet.create({ marginTop: 20, backgroundColor: color.purple, }, + subText: { + paddingTop: 20, + paddingBottom: 40, + paddingLeft: 40, + paddingRight: 40, + }, }); const PayLightningSupplyAmountView = ({ store, nav, payment }) => (
nav.goHome()} /> - + <Title title="Payment Request For Any Amount"> <LightningBoltIcon height={12} width={6.1} /> nav.goHome()} />
- - The invoice did not specify an amount. - - - - payment.setAmount({ amount })} - onSubmitEditing={() => - payment.estimateLightningFeeForAmount(payment.amount) - } - /> - - {store.unitFiatLabel} - - - payment.toggleMax()} + + payment.setAmount({ amount })} + onSubmitEditing={() => + payment.estimateLightningFeeForAmount(payment.amount) + } /> + + {store.unitFiatLabel} + + + {store.payment.note ? ( {store.payment.note} ) : null} + + Payment Request did not specify an amount. This is often used for + tips/donations. + Date: Fri, 31 Jan 2020 17:36:13 +0100 Subject: [PATCH 07/13] Fix issue where writing 500 yeild 0500. --- src/action/payment.js | 13 ++++++++++++- src/view/pay-lightning-supply-amount-mobile.js | 6 ++++-- src/view/pay-lightning-supply-amount.js | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index 83e06f829..38bb0d4d7 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -169,6 +169,7 @@ class PaymentAction { this._store.payment.amount === '0' || this._store.payment.amount === 0 ) { + this._store.payment.amount = null; this._nav.goPayLightningSupplyAmount(); } else { this._nav.goPayLightningConfirm(); @@ -180,6 +181,15 @@ class PaymentAction { } } + async checkAmountSuppliedAndGoPayLightningConfirm() { + if (!this._store.payment.amount) { + return this._notification.display({ msg: 'Enter an invoice or address' }); + } else { + this.reEstimateLightningFee(); + this._nav.goPayLightningConfirm(); + } + } + /** * Attempt to decode a lightning invoice using the lnd grpc api. If it is * an invoice the amount and note store values will be set and the lightning @@ -212,11 +222,12 @@ class PaymentAction { * @param {number} options.satAmt The amount to be payed in satoshis * @return {Promise} */ - async estimateLightningFeeForAmount({ amount }) { + async reEstimateLightningFee() { try { const request = await this._grpc.sendCommand('decodePayReq', { payReq: this._store.payment.address, }); + const amount = this._store.payment.amount; this.estimateLightningFee({ destination: request.destination, satAmt: toSatoshis(amount, this._store.settings), diff --git a/src/view/pay-lightning-supply-amount-mobile.js b/src/view/pay-lightning-supply-amount-mobile.js index dddd1fa5f..a92e520b3 100644 --- a/src/view/pay-lightning-supply-amount-mobile.js +++ b/src/view/pay-lightning-supply-amount-mobile.js @@ -47,7 +47,7 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( value={store.invoice.amount} onChangeText={amount => payment.setAmount({ amount })} onSubmitEditing={() => - payment.estimateLightningFeeForAmount(payment.amount) + payment.checkAmountSuppliedAndGoPayLightningConfirm() } /> @@ -67,7 +67,9 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( - nav.goPayLightningConfirm()}> + payment.checkAmountSuppliedAndGoPayLightningConfirm()} + > Pay
diff --git a/src/view/pay-lightning-supply-amount.js b/src/view/pay-lightning-supply-amount.js index d9cfeaa3a..192de47ea 100644 --- a/src/view/pay-lightning-supply-amount.js +++ b/src/view/pay-lightning-supply-amount.js @@ -54,7 +54,7 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( value={store.payment.amount} onChangeText={amount => payment.setAmount({ amount })} onSubmitEditing={() => - payment.estimateLightningFeeForAmount(payment.amount) + payment.checkAmountSuppliedAndGoPayLightningConfirm() } /> @@ -74,7 +74,7 @@ const PayLightningSupplyAmountView = ({ store, nav, payment }) => ( nav.goPayLightningConfirm()} + onPress={() => payment.checkAmountSuppliedAndGoPayLightningConfirm()} > Pay From c45d0d036e2a2cab1afc88f2e7617944f6b31800 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Fri, 31 Jan 2020 17:44:52 +0100 Subject: [PATCH 08/13] Documentation for checkAmountSuppliedAndGoPayLightningConfirm. --- src/action/payment.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/action/payment.js b/src/action/payment.js index 38bb0d4d7..cacad7cd0 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -181,6 +181,10 @@ class PaymentAction { } } + /** + * Check If payment amount was supplied and then re-estimate the routing fee + * and go to the confirmation view for lightning payments. + */ async checkAmountSuppliedAndGoPayLightningConfirm() { if (!this._store.payment.amount) { return this._notification.display({ msg: 'Enter an invoice or address' }); From 86f0fa3e2c3d12799377a0031d68ec22efa8dd3a Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 1 Feb 2020 10:14:25 +0100 Subject: [PATCH 09/13] Remove jsconfig commited by mistake. --- jsconfig.json | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 94279b62b..000000000 --- a/jsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "es2017", - "allowSyntheticDefaultImports": true, - "noEmit": true, - "checkJs": true, - "jsx": "react", - "lib": [ "dom", "es2017" ] - } -} From d1c9dfe8097d390a120bb5a13c0b16e2cbb6dba0 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 1 Feb 2020 10:19:26 +0100 Subject: [PATCH 10/13] Remove unnecesary 0 guard. --- src/action/payment.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index cacad7cd0..a7e2a2d1b 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -165,10 +165,7 @@ class PaymentAction { return this._notification.display({ msg: 'Enter an invoice or address' }); } if (await this.decodeInvoice({ invoice: this._store.payment.address })) { - if ( - this._store.payment.amount === '0' || - this._store.payment.amount === 0 - ) { + if (this._store.payment.amount === '0') { this._store.payment.amount = null; this._nav.goPayLightningSupplyAmount(); } else { From 93227257d267c8a9231d1da22aa1e69fb938f71c Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 1 Feb 2020 13:21:47 +0100 Subject: [PATCH 11/13] Make subtle dependencies more clear and improve error handling. --- src/action/payment.js | 47 ++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index a7e2a2d1b..41366472e 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -106,6 +106,7 @@ class PaymentAction { */ init() { this._store.payment.address = ''; + this._store.payment.destination = ''; this._store.payment.amount = ''; this._store.payment.targetConf = MED_TARGET_CONF; this._store.payment.fee = ''; @@ -166,7 +167,7 @@ class PaymentAction { } if (await this.decodeInvoice({ invoice: this._store.payment.address })) { if (this._store.payment.amount === '0') { - this._store.payment.amount = null; + this._store.payment.amount = ''; this._nav.goPayLightningSupplyAmount(); } else { this._nav.goPayLightningConfirm(); @@ -179,14 +180,26 @@ class PaymentAction { } /** - * Check If payment amount was supplied and then re-estimate the routing fee - * and go to the confirmation view for lightning payments. + * Check If payment amount was supplied and destination is set. Estimate + * the routing fee and go to the confirmation view for lightning payments. + * + * Note: This function is dependent on that an invoice has already been decoded. + * If payment amount is 0 the function will display a message and return. */ async checkAmountSuppliedAndGoPayLightningConfirm() { - if (!this._store.payment.amount) { - return this._notification.display({ msg: 'Enter an invoice or address' }); + if (this._store.payment.amount === '0') { + this._notification.display({ msg: 'Enter amount to pay.' }); + } else if ( + this._store.payment.destination === '' || + this._store.payment.amount === '' + ) { + this._notification.display({ msg: 'Internal Error, try again.' }); + this._nav.goHome(); } else { - this.reEstimateLightningFee(); + this.estimateLightningFee({ + destination: this._store.payment.destination, + satAmt: toSatoshis(this._store.payment.amount, this._store.settings), + }); this._nav.goPayLightningConfirm(); } } @@ -206,6 +219,7 @@ class PaymentAction { }); payment.amount = toAmount(request.numSatoshis, settings); payment.note = request.description; + payment.destination = request.destination; this.estimateLightningFee({ destination: request.destination, satAmt: request.numSatoshis, @@ -217,27 +231,6 @@ class PaymentAction { } } - /** - * Estimate the lightning transaction fee using the queryRoutes grpc api - * after which the fee is set in the store. - * @param {number} options.satAmt The amount to be payed in satoshis - * @return {Promise} - */ - async reEstimateLightningFee() { - try { - const request = await this._grpc.sendCommand('decodePayReq', { - payReq: this._store.payment.address, - }); - const amount = this._store.payment.amount; - this.estimateLightningFee({ - destination: request.destination, - satAmt: toSatoshis(amount, this._store.settings), - }); - } catch (err) { - log.info(`Estimating lightning fee failed!`, err); - } - } - /** * Estimate the lightning transaction fee using the queryRoutes grpc api * after which the fee is set in the store. From 55985e7d3c965a70944512f13f974dd1a22eb36f Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 1 Feb 2020 13:27:50 +0100 Subject: [PATCH 12/13] Make docstring for payLightning more clear. --- src/action/payment.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index 41366472e..76b39ae8a 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -353,8 +353,7 @@ class PaymentAction { } /** - * Send the amount specified in the payment.amount. If zero use the amount - * specified in the invoice as a lightning transaction and + * Send the amount specified in payment.amount as a lightning transaction and * display the wait screen while the payment confirms. * This action can be called from a view event handler as does all * the necessary error handling and notification display. From 51413f293ac594aa2efaa07cc64a1d1847484090 Mon Sep 17 00:00:00 2001 From: Emil Johansson Date: Sat, 1 Feb 2020 13:43:15 +0100 Subject: [PATCH 13/13] Change error handling in checkAmountSuppliedAndGoPayLightningConfirm. Amount will be an empty string when user have not specified in the view before pressing "pay". --- src/action/payment.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index 76b39ae8a..99b0202f8 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -187,12 +187,12 @@ class PaymentAction { * If payment amount is 0 the function will display a message and return. */ async checkAmountSuppliedAndGoPayLightningConfirm() { - if (this._store.payment.amount === '0') { - this._notification.display({ msg: 'Enter amount to pay.' }); - } else if ( - this._store.payment.destination === '' || + if ( + this._store.payment.amount === '0' || this._store.payment.amount === '' ) { + this._notification.display({ msg: 'Enter amount to pay.' }); + } else if (this._store.payment.destination === '') { this._notification.display({ msg: 'Internal Error, try again.' }); this._nav.goHome(); } else {