From 13738ce29f8f82cfed6c62ac6397fcd0a0592658 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Mon, 14 May 2018 16:31:54 +0800 Subject: [PATCH 1/4] Update rpc.proto for new estimateFee api --- assets/rpc.proto | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/assets/rpc.proto b/assets/rpc.proto index 663961d08..b41557975 100644 --- a/assets/rpc.proto +++ b/assets/rpc.proto @@ -191,6 +191,16 @@ service Lightning { }; } + /** lncli: `estimatefee` + EstimateFee asks the chain backend to estimate the fee rate and total fees + for a transaction that pays to multiple specified outputs. + */ + rpc EstimateFee (EstimateFeeRequest) returns (EstimateFeeResponse) { + option (google.api.http) = { + get: "/v1/transactions/fee" + }; + } + /** lncli: `sendcoins` SendCoins executes a request to send coins to a particular address. Unlike SendMany, this RPC call only allows creating a single output at a time. If @@ -654,6 +664,27 @@ message LightningAddress { string host = 2 [json_name = "host"]; } +message FeeEstimate { + /// The total fee in satoshis. + int64 fee_sat = 1; + + /// The fee rate in satoshi/byte. + int64 feerate_sat_per_byte = 2; +} + +message EstimateFeeRequest { + /// The map from addresses to amounts for the transaction. + map AddrToAmount = 1; + + /// The target number of blocks that this transaction should be confirmed by. + int32 target_conf = 2; +} + +message EstimateFeeResponse { + /// A fee estimate for the specified confirmation target. + FeeEstimate estimate = 1; +} + message SendManyRequest { /// The map from addresses to amounts map AddrToAmount = 1; From 6672fcea657c25f95e1a413159d56ed4bfbeaa57 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Mon, 14 May 2018 17:56:39 +0800 Subject: [PATCH 2/4] Implement and test payment action to estimate fees --- src/action/payment.js | 14 ++++++++++ .../action/action-integration.spec.js | 7 ++++- test/unit/action/payment.spec.js | 26 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/action/payment.js b/src/action/payment.js index 7a5766424..47304185d 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -53,6 +53,20 @@ class PaymentAction { } } + async estimateFee() { + try { + const { payment, settings } = this._store; + const AddrToAmount = {}; + AddrToAmount[payment.address] = toSatoshis(payment.amount, settings.unit); + const { estimate } = await this._grpc.sendCommand('estimateFee', { + AddrToAmount, + }); + payment.fee = estimate.fee_sat; + } catch (err) { + this._notification.display({ msg: 'Estimating 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 96994fb49..6fa103952 100644 --- a/test/integration/action/action-integration.spec.js +++ b/test/integration/action/action-integration.spec.js @@ -245,9 +245,14 @@ describe('Action Integration Tests', function() { transactions2.subscribeTransactions(); }); - it('should send some on-chain funds to node2', async () => { + it('should estimate on-chain fees', async () => { store1.payment.address = store2.walletAddress; store1.payment.amount = '10'; + await payments1.estimateFee(); + expect(store1.payment.fee, 'to be ok'); + }); + + it('should send some on-chain funds to node2', async () => { await payments1.payBitcoin(); }); diff --git a/test/unit/action/payment.spec.js b/test/unit/action/payment.spec.js index 6f28cf15f..1bc226b19 100644 --- a/test/unit/action/payment.spec.js +++ b/test/unit/action/payment.spec.js @@ -39,6 +39,7 @@ describe('Action Payments Unit Tests', () => { payment.init(); expect(store.payment.address, 'to equal', ''); expect(store.payment.amount, 'to equal', ''); + expect(store.payment.fee, 'to equal', ''); expect(store.payment.note, 'to equal', ''); expect(nav.goPay, 'was called once'); }); @@ -80,6 +81,31 @@ describe('Action Payments Unit Tests', () => { }); }); + describe('estimateFee()', () => { + it('should get fee estimate to display', async () => { + store.payment.amount = '0.00001'; + store.payment.address = 'some-address'; + grpc.sendCommand.withArgs('estimateFee').resolves({ + estimate: { + fee_sat: '8250', + feerate_sat_per_byte: '50', + }, + }); + await payment.estimateFee(); + expect(grpc.sendCommand, 'was called with', 'estimateFee', { + AddrToAmount: { 'some-address': 1000 }, + }); + expect(store.payment.fee, 'to equal', '8250'); + }); + + it('should display notification on error', async () => { + grpc.sendCommand.withArgs('estimateFee').rejects(); + await payment.estimateFee(); + expect(notification.display, 'was called once'); + expect(store.payment.fee, 'to equal', ''); + }); + }); + describe('payBitcoin()', () => { it('should send on-chain transaction', async () => { store.payment.amount = '0.00001'; From d61359e088d0e6613b5eab02a71d7c8d1ed1d3a0 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Mon, 14 May 2018 18:09:22 +0800 Subject: [PATCH 3/4] Fix bug where fees are displayed in satoshis and Not the selected unit. --- src/action/payment.js | 2 +- test/unit/action/payment.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/action/payment.js b/src/action/payment.js index 47304185d..7a6a754df 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -61,7 +61,7 @@ class PaymentAction { const { estimate } = await this._grpc.sendCommand('estimateFee', { AddrToAmount, }); - payment.fee = estimate.fee_sat; + payment.fee = toAmount(estimate.fee_sat, settings.unit); } catch (err) { this._notification.display({ msg: 'Estimating fee failed!', err }); } diff --git a/test/unit/action/payment.spec.js b/test/unit/action/payment.spec.js index 1bc226b19..428b3fd74 100644 --- a/test/unit/action/payment.spec.js +++ b/test/unit/action/payment.spec.js @@ -95,7 +95,7 @@ describe('Action Payments Unit Tests', () => { expect(grpc.sendCommand, 'was called with', 'estimateFee', { AddrToAmount: { 'some-address': 1000 }, }); - expect(store.payment.fee, 'to equal', '8250'); + expect(store.payment.fee, 'to equal', '0.0000825'); }); it('should display notification on error', async () => { From 71c19b8e86850b4ae3747a48c789f0cd853d190f Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Thu, 17 May 2018 23:01:04 +0800 Subject: [PATCH 4/4] Fix parsing satoshis in fee estimate --- src/action/payment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/action/payment.js b/src/action/payment.js index 7a6a754df..62f8d01fd 100644 --- a/src/action/payment.js +++ b/src/action/payment.js @@ -61,7 +61,7 @@ class PaymentAction { const { estimate } = await this._grpc.sendCommand('estimateFee', { AddrToAmount, }); - payment.fee = toAmount(estimate.fee_sat, settings.unit); + payment.fee = toAmount(parseSat(estimate.fee_sat), settings.unit); } catch (err) { this._notification.display({ msg: 'Estimating fee failed!', err }); }