diff --git a/src/action/payment.js b/src/action/payment.js index 5cd27232a..fd97ee8b2 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -70,6 +70,10 @@ class PaymentAction { }); payment.amount = toAmount(parseSat(request.num_satoshis), settings.unit); payment.note = request.description; + await this.estimateLightningFee({ + destination: request.destination, + satAmt: request.num_satoshis, + }); return true; } catch (err) { log.info(`Decoding payment request failed: ${err.message}`); @@ -77,6 +81,20 @@ class PaymentAction { } } + async estimateLightningFee({ destination, satAmt }) { + try { + const { payment, settings } = this._store; + const { routes } = await this._grpc.sendCommand('queryRoutes', { + pub_key: destination, + amt: satAmt, + num_routes: 1, + }); + payment.fee = toAmount(parseSat(routes[0].total_fees), settings.unit); + } catch (err) { + log.error(`Estimating lightning fee failed!`, err); + } + } + async payBitcoin() { try { const { payment, settings } = this._store; diff --git a/test/integration/action/action-integration.spec.js b/test/integration/action/action-integration.spec.js index 29ebcd26f..5a04ad794 100644 --- a/test/integration/action/action-integration.spec.js +++ b/test/integration/action/action-integration.spec.js @@ -344,11 +344,16 @@ describe('Action Integration Tests', function() { expect(isValid, 'to be', false); }); - it('should decode invoice and return true', async () => { + it('should decode invoice, set fee and return true', async () => { const isValid = await payments1.decodeInvoice({ invoice: store2.invoice.uri, }); expect(isValid, 'to be', true); + expect( + parseFloat(store1.payment.fee), + 'to be greater than or equal to', + 0 + ); }); it('should send lightning payment from request', async () => { diff --git a/test/unit/action/payment.spec.js b/test/unit/action/payment.spec.js index b94209c00..4e682d79d 100644 --- a/test/unit/action/payment.spec.js +++ b/test/unit/action/payment.spec.js @@ -139,21 +139,48 @@ describe('Action Payments Unit Tests', () => { grpc.sendCommand.withArgs('decodePayReq').resolves({ num_satoshis: '1700', description: 'foo', + destination: 'bar', }); + grpc.sendCommand + .withArgs('queryRoutes', { + pub_key: 'bar', + amt: '1700', + num_routes: 1, + }) + .resolves({ + routes: [{ total_fees: '100' }], + }); const isValid = await payment.decodeInvoice({ invoice: 'some-invoice' }); expect(isValid, 'to be', true); expect(store.payment.amount, 'to match', /^0[,.]0{4}1{1}7{1}$/); expect(store.payment.note, 'to be', 'foo'); + expect(store.payment.fee, 'to match', /^0[,.]0{5}1{1}$/); }); - it('should set response to null on error', async () => { + it('should set nothing on decode error', async () => { grpc.sendCommand.withArgs('decodePayReq').rejects(new Error('Boom!')); const isValid = await payment.decodeInvoice({ invoice: 'some-invoice' }); expect(isValid, 'to be', false); expect(store.payment.amount, 'to be', ''); expect(store.payment.note, 'to be', ''); + expect(store.payment.fee, 'to be', ''); expect(logger.info, 'was called once'); }); + + it('should set no fee on query route error', async () => { + grpc.sendCommand.withArgs('decodePayReq').resolves({ + num_satoshis: '1700', + description: 'foo', + destination: 'bar', + }); + grpc.sendCommand.withArgs('queryRoutes').rejects(new Error('Boom!')); + const isValid = await payment.decodeInvoice({ invoice: 'some-invoice' }); + expect(isValid, 'to be', true); + expect(store.payment.amount, 'to match', /^0[,.]0{4}1{1}7{1}$/); + expect(store.payment.note, 'to be', 'foo'); + expect(store.payment.fee, 'to be', ''); + expect(logger.error, 'was called once'); + }); }); describe('payBitcoin()', () => {