diff --git a/electron/lnurl/service.js b/electron/lnurl/service.js index 0584347b5fe..c829d5d2321 100644 --- a/electron/lnurl/service.js +++ b/electron/lnurl/service.js @@ -30,13 +30,16 @@ export default class LnurlService { this.mainWindow = mainWindow this.withdrawParams = {} - this.isWithdrawalProcessing = false + this.isWithdrawProcessing = false this.channelParams = {} this.isChannelProcessing = false - ipcMain.on('lnurlFinalizeWithdraw', this.onFinishWithdrawal) - ipcMain.on('lnurlFinalizeChannel', this.onFinishChannel) + ipcMain.on('lnurlFinishWithdraw', this.onFinishWithdraw) + ipcMain.on('lnurlCancelWithdraw', this.onCancelWithdraw) + + ipcMain.on('lnurlFinishChannel', this.onFinishChannel) + ipcMain.on('lnurlCancelChannel', this.onCancelChannel) } /** @@ -44,8 +47,11 @@ export default class LnurlService { * `LnurlService` instance is of no use anymore. */ terminate() { - ipcMain.off('lnurlFinalizeWithdraw', this.onFinishWithdrawal) - ipcMain.off('lnurlFinalizeChannel', this.onFinishChannel) + ipcMain.off('lnurlFinishWithdraw', this.onFinishWithdraw) + ipcMain.off('lnurlCancelWithdraw', this.onCancelWithdraw) + + ipcMain.off('lnurlFinishChannel', this.onFinishChannel) + ipcMain.off('lnurlCancelChannel', this.onCancelChannel) } /** @@ -75,7 +81,7 @@ export default class LnurlService { switch (res.tag) { case 'withdrawRequest': this.withdrawParams = res - await this.startWithdrawal(lnurl) + await this.startWithdraw(lnurl) break case 'channelRequest': @@ -93,25 +99,25 @@ export default class LnurlService { } /** - * startWithdrawal - Initiates lnurl withdrawal process by sending query to + * startWithdraw - Initiates lnurl withdrawal process by sending query to * renderer process to generate LN invoice. * * @param {string} lnurl decoded lnurl */ - async startWithdrawal(lnurl) { - if (this.isWithdrawalProcessing) { + async startWithdraw(lnurl) { + const { status, reason, maxWithdrawable, defaultDescription } = this.withdrawParams + const service = getServiceName(lnurl) + + if (this.isWithdrawProcessing) { mainLog.warn('Error processing lnurl withdraw request: busy') - this.send('lnurlWithdrawalBusy') + this.send('lnurlWithdrawError', { service, reason: 'service busy' }) return } - this.isWithdrawalProcessing = true - - const { status, reason, maxWithdrawable, defaultDescription } = this.withdrawParams - const service = getServiceName(lnurl) + this.isWithdrawProcessing = true if (status === LNURL_STATUS_ERROR) { const withdrawParams = { status, reason, service } - this.isWithdrawalProcessing = false + this.isWithdrawProcessing = false mainLog.error('Unable to process lnurl withdraw request: %o', withdrawParams) this.send('lnurlWithdrawError', withdrawParams) return @@ -123,30 +129,46 @@ export default class LnurlService { } /** - * onFinishChannel - Finalizes an lnurl-withdraw request. + * resetWithdraw - Resets lnurl-withdraw state. + */ + resetWithdraw = () => { + this.isWithdrawProcessing = false + this.withdrawParams = {} + } + + /** + * onCancelWithdraw - Cancels an lnurl-withdraw request. + */ + onCancelWithdraw = () => { + this.resetWithdraw() + mainLog.info('Cancelling lnurl withdrawal request: %o', this.withdrawParams) + } + + /** + * onFinishWithdraw - Finalizes an lnurl-withdraw request. * * @param {object} event Event * @param {object} data Data */ - onFinishWithdrawal = async (event, { paymentRequest }) => { + onFinishWithdraw = async (event, { paymentRequest }) => { + mainLog.info('Finishing lnurl withdraw request: %o', this.withdrawParams) + const { callback, secret, service } = this.withdrawParams try { - const { callback, secret } = this.withdrawParams if (callback && secret && paymentRequest) { const { data } = await makeWithdrawRequest({ callback, secret, invoice: paymentRequest }) - if (data.status === LNURL_STATUS_ERROR) { - mainLog.warn('Unable to complete lnurl withdraw request: %o', data) - this.send('lnurlWithdrawError', data) - return + mainLog.warn('Got error from lnurl withdraw request: %s', data) + throw new Error(data.reason) } mainLog.info('Completed withdraw request: %o', data) + this.send('lnurlWithdrawSuccess', { service }) } } catch (e) { - mainLog.warn('Unable to complete lnurl withdrawal request: %s', e) + mainLog.warn('Unable to complete lnurl withdraw request: %s', e.message) + this.send('lnurlWithdrawError', { service, reason: e.message }) } finally { - this.isWithdrawalProcessing = false - this.withdrawParams = {} + this.resetWithdraw() } } @@ -155,15 +177,15 @@ export default class LnurlService { * process to initiate channel connect. */ async startChannel() { + const { status, uri } = this.channelParams + if (this.isChannelProcessing) { mainLog.warn('Error processing lnurl channel request: busy') - this.send('lnurlChannelBusy') + this.send('lnurlChannelError', { uri, reason: 'service busy' }) return } this.isChannelProcessing = true - const { status, uri } = this.channelParams - if (status === LNURL_STATUS_ERROR) { const channelParams = { status, uri } this.isChannelProcessing = false @@ -177,6 +199,22 @@ export default class LnurlService { this.send('lnurlChannelRequest', channelParams) } + /** + * resetChannel - Resets lnurl-withdraw state. + */ + resetChannel = () => { + this.isChannelProcessing = false + this.channelParams = {} + } + + /** + * onCancelChannel - Cancels an lnurl-channel request. + */ + onCancelChannel = () => { + this.resetChannel() + mainLog.info('Cancelling lnurl channel request: %o', this.channelParams) + } + /** * onFinishChannel - Finalizes an lnurl-channel request. * @@ -184,24 +222,25 @@ export default class LnurlService { * @param {object} data Data */ onFinishChannel = async (event, { pubkey }) => { + mainLog.info('Finishing lnurl channel request: %o', this.channelParams) + const { callback, secret, uri } = this.channelParams try { - const { callback, secret, uri } = this.channelParams if (callback && secret && pubkey) { const { data } = await makeChannelRequest({ callback, secret, pubkey, isPrivate: true }) if (data.status === LNURL_STATUS_ERROR) { - mainLog.warn('Unable to complete lnurl channel request: %o', data) - this.send('lnurlChannelError', { ...data, uri }) - return + mainLog.warn('Got error from lnurl channel request: %s', data) + throw new Error(data.reason) } mainLog.info('Completed channel request: %o', data) + this.send('lnurlChannelSuccess', { uri }) } } catch (e) { - mainLog.warn('Unable to complete lnurl channel request: %s', e) + mainLog.warn('Unable to complete lnurl channel request: %s', e.message) + this.send('lnurlChannelError', { uri, reason: e.message }) } finally { - this.isChannelProcessing = false - this.channelParams = {} + this.resetChannel() } } } diff --git a/renderer/components/App/App.js b/renderer/components/App/App.js index a236653cbf9..9b71e3afd64 100644 --- a/renderer/components/App/App.js +++ b/renderer/components/App/App.js @@ -5,7 +5,7 @@ import LnurlChannelPrompt from 'containers/Channels/LnurlChannelPrompt' import createScheduler from '@zap/utils/scheduler' import Wallet from 'containers/Wallet' import Activity from 'containers/Activity' -import LnurlWithdrawalPrompt from 'containers/Pay/LnurlWithdrawalPrompt' +import LnurlWithdrawPrompt from 'containers/Pay/LnurlWithdrawPrompt' // Bitcoin blocks come on average every 10 mins // but we poll a lot more frequently to make UI a little bit more responsive @@ -43,9 +43,9 @@ const App = ({ lnurlChannelParams, lnurlWithdrawParams, finishLnurlChannel, - finishLnurlWithdrawal, + finishLnurlWithdraw, willShowLnurlChannelPrompt, - willShowLnurlWithdrawalPrompt, + willShowLnurlWithdrawPrompt, }) => { /** * App scheduler / polling service setup. Add new app-wide polls here @@ -96,8 +96,8 @@ const App = ({ // initialize backup service in forceUseTokens mode to avoid // launching it for wallets that don't have backup setup initBackupService() - if (!willShowLnurlWithdrawalPrompt) { - finishLnurlWithdrawal() + if (!willShowLnurlWithdrawPrompt) { + finishLnurlWithdraw() } if (!willShowLnurlChannelPrompt) { finishLnurlChannel() @@ -112,11 +112,11 @@ const App = ({ setIsWalletOpen, updateAutopilotNodeScores, finishLnurlChannel, - finishLnurlWithdrawal, + finishLnurlWithdraw, lnurlChannelParams, lnurlWithdrawParams, willShowLnurlChannelPrompt, - willShowLnurlWithdrawalPrompt, + willShowLnurlWithdrawPrompt, ]) // Open the pay form when a payment link is used. @@ -136,7 +136,7 @@ const App = ({ - {willShowLnurlWithdrawalPrompt && } + {willShowLnurlWithdrawPrompt && } {willShowLnurlChannelPrompt && } ) @@ -148,7 +148,7 @@ App.propTypes = { fetchSuggestedNodes: PropTypes.func.isRequired, fetchTransactions: PropTypes.func.isRequired, finishLnurlChannel: PropTypes.func.isRequired, - finishLnurlWithdrawal: PropTypes.func.isRequired, + finishLnurlWithdraw: PropTypes.func.isRequired, initActivityHistory: PropTypes.func.isRequired, initBackupService: PropTypes.func.isRequired, initTickers: PropTypes.func.isRequired, @@ -161,7 +161,7 @@ App.propTypes = { setModals: PropTypes.func.isRequired, updateAutopilotNodeScores: PropTypes.func.isRequired, willShowLnurlChannelPrompt: PropTypes.bool, - willShowLnurlWithdrawalPrompt: PropTypes.bool, + willShowLnurlWithdrawPrompt: PropTypes.bool, } export default App diff --git a/renderer/components/Channels/LnurlChannelPrompt.js b/renderer/components/Channels/LnurlChannelPrompt.js index 5f532fdde50..0d9f3794827 100644 --- a/renderer/components/Channels/LnurlChannelPrompt.js +++ b/renderer/components/Channels/LnurlChannelPrompt.js @@ -6,8 +6,8 @@ import { Dialog, Heading, Button, DialogOverlay, Text } from 'components/UI' import { Form } from 'components/Form' import messages from './messages' -const LnurlChannelPrompt = ({ params, onOk, onCancel }) => { - const { service, uri } = params +const LnurlChannelPrompt = ({ params, onOk, onCancel, onClose }) => { + const { uri } = params const buttons = ( <>