feat: confirm outputs and fee

This commit is contained in:
Vlad Stan 2022-07-28 12:39:06 +03:00
parent d541bebf38
commit 8746045428
11 changed files with 136 additions and 38 deletions

View file

@ -9,7 +9,7 @@ async function addressList(path) {
'accounts', 'accounts',
'mempool_endpoint', 'mempool_endpoint',
'inkey', 'inkey',
'sats_denominated' 'sats-denominated'
], ],
watch: { watch: {
immediate: true, immediate: true,
@ -90,7 +90,7 @@ async function addressList(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
getWalletName: function (walletId) { getWalletName: function (walletId) {
const wallet = (this.accounts || []).find(wl => wl.id === walletId) const wallet = (this.accounts || []).find(wl => wl.id === walletId)

View file

@ -4,7 +4,7 @@ async function feeRate(path) {
name: 'fee-rate', name: 'fee-rate',
template, template,
props: ['rate', 'fee-value', 'sats_denominated'], props: ['rate', 'fee-value', 'sats-denominated'],
computed: { computed: {
feeRate: { feeRate: {
@ -31,7 +31,7 @@ async function feeRate(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
refreshRecommendedFees: async function () { refreshRecommendedFees: async function () {

View file

@ -4,7 +4,7 @@ async function history(path) {
name: 'history', name: 'history',
template, template,
props: ['history', 'mempool_endpoint', 'sats_denominated'], props: ['history', 'mempool_endpoint', 'sats-denominated'],
data: function () { data: function () {
return { return {
historyTable: { historyTable: {
@ -73,7 +73,7 @@ async function history(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
getFilteredAddressesHistory: function () { getFilteredAddressesHistory: function () {
return this.history.filter(a => (!a.isChange || a.sent) && !a.isSubItem) return this.history.filter(a => (!a.isChange || a.sent) && !a.isSubItem)

View file

@ -7,7 +7,7 @@
:fee-rate="feeRate" :fee-rate="feeRate"
:tx-size="txSizeNoChange" :tx-size="txSizeNoChange"
:selected-amount="selectedAmount" :selected-amount="selectedAmount"
:sats-denominated="sats_denominated" :sats-denominated="satsDenominated"
@update:outputs="handleOutputsChange" @update:outputs="handleOutputsChange"
></send-to> ></send-to>
</q-card-section> </q-card-section>
@ -79,7 +79,7 @@
:selectable="true" :selectable="true"
:payed-amount="totalPayedAmount" :payed-amount="totalPayedAmount"
:mempool_endpoint="mempool_endpoint" :mempool_endpoint="mempool_endpoint"
:sats-denominated="sats_denominated" :sats-denominated="satsDenominated"
></utxo-list> ></utxo-list>
</div> </div>
</div> </div>
@ -160,7 +160,7 @@
<q-btn-dropdown <q-btn-dropdown
split split
unelevated unelevated
:disabled="changeAmount < 0" :disabled="changeAmount < 0 || showChecking"
label="Check & Send" label="Check & Send"
color="green" color="green"
type="submit" type="submit"

View file

@ -9,7 +9,7 @@ async function payment(path) {
'addresses', 'addresses',
'utxos', 'utxos',
'mempool_endpoint', 'mempool_endpoint',
'sats_denominated', 'sats-denominated',
'serial-signer-ref', 'serial-signer-ref',
'adminkey' 'adminkey'
], ],
@ -77,7 +77,7 @@ async function payment(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
checkAndSend: async function () { checkAndSend: async function () {
this.showChecking = true this.showChecking = true
@ -94,12 +94,23 @@ async function payment(path) {
await this.createPsbt() await this.createPsbt()
if (this.psbtBase64) { if (this.psbtBase64) {
await this.serialSignerRef.hwwSendPsbt(this.psbtBase64) const txData = {
outputs: this.tx.outputs,
feeRate: this.tx.fee_rate,
feeValue: this.feeValue
}
await this.serialSignerRef.hwwSendPsbt(this.psbtBase64, txData)
await this.serialSignerRef.isSendingPsbt() await this.serialSignerRef.isSendingPsbt()
} }
console.log('### hwwSendPsbt') console.log('### hwwSendPsbt')
} catch (error) { } catch (error) {
console.error(error)
this.$q.notify({
type: 'warning',
message: 'Cannot check and sign PSBT!',
timeout: 10000
})
} finally { } finally {
this.showChecking = false this.showChecking = false
this.psbtBase64 = null this.psbtBase64 = null

View file

@ -9,7 +9,7 @@ async function sendTo(path) {
'tx-size', 'tx-size',
'selected-amount', 'selected-amount',
'fee-rate', 'fee-rate',
'sats_denominated' 'sats-denominated'
], ],
computed: { computed: {
@ -44,7 +44,7 @@ async function sendTo(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
addPaymentAddress: function () { addPaymentAddress: function () {
this.dataLocal.push({address: '', amount: undefined}) this.dataLocal.push({address: '', amount: undefined})

View file

@ -153,30 +153,88 @@
</q-card> </q-card>
</q-dialog> </q-dialog>
<q-dialog v-model="hww.psbtSent" position="top"> <q-dialog v-model="hww.showConfirmationDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card"> <q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwSignPsbt" class="q-gutter-md"> <q-form @submit="hwwSignPsbt" class="q-gutter-md">
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<div class="col-12"> <div class="col-12">
<span>Check transaction on your hardware device</span> <span>Check data on your hardware device.</span>
</div>
</div>
<div v-if="tx">
<div v-if="!hww.confirm.showFee" class="row q-mt-lg">
<div class="col-12">
<span class="text-subtitle2"
>Output {{hww.confirm.outputIndex}}</span
>
</div>
</div>
<div v-if="!hww.confirm.showFee" class="row q-mt-lg">
<div class="col-3">
<span>Address:</span>
</div>
<div class="col-9">
<span>{{tx.outputs[hww.confirm.outputIndex].address}}</span>
</div>
</div>
<div v-if="!hww.confirm.showFee" class="row q-mt-lg">
<div class="col-3">
<span>Amount:</span>
</div>
<div class="col-9">
<span
>{{satBtc(tx.outputs[hww.confirm.outputIndex].amount)}}</span
>
</div>
</div>
<div v-if="hww.confirm.showFee" class="row q-mt-lg">
<div class="col-3">
<span>Fee: </span>
</div>
<div class="col-9">
<span>{{satBtc(tx.feeValue)}}</span>
</div>
</div>
<div v-if="hww.confirm.showFee" class="row q-mt-lg">
<div class="col-3">
<span>Fee Rate:</span>
</div>
<div class="col-9">
<span>{{tx.feeRate}} sats/vbyte</span>
</div>
</div> </div>
</div> </div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<!-- todo: disable until all data is confirmed --> <div class="col-6">
<q-btn <q-btn
v-if="hww.confirm.confirmed"
unelevated unelevated
color="green" color="green"
:disable="!selectedPort" :disable="!selectedPort"
type="submit" type="submit"
class="float-left"
label="Confirm" label="Confirm"
> >
<q-spinner v-if="hww.signingPsbt" color="primary"></q-spinner> <q-spinner v-if="hww.signingPsbt" color="primary"></q-spinner>
</q-btn> </q-btn>
<q-btn v-close-popup flat color="grey" class="q-ml-auto" </div>
<div class="col-3">
<q-btn
unelevated
color="secondary"
label="Next"
class="float-left"
v-if="!hww.confirm.confirmed"
@click="hwwConfirmNext"
>
</q-btn>
</div>
<div class="col-3">
<q-btn v-close-popup flat color="grey" class="float-right"
>Cancel</q-btn >Cancel</q-btn
> >
</div> </div>
</div>
</q-form> </q-form>
</q-card> </q-card>
</q-dialog> </q-dialog>

View file

@ -28,14 +28,23 @@ async function serialSigner(path) {
showSignedPsbt: false, showSignedPsbt: false,
sendingPsbt: false, sendingPsbt: false,
signingPsbt: false, signingPsbt: false,
psbtSent: false, psbtSentResolve: null,
psbtSentResolve: null confirm: {
outputIndex: 0,
showFee: false,
confirmed: false
}
}, },
tx: null, // todo: move to hww
showConsole: false showConsole: false
} }
}, },
methods: { methods: {
satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this.satsDenominated)
},
openSerialPort: async function () { openSerialPort: async function () {
if (!this.checkSerialPortSupported()) return false if (!this.checkSerialPortSupported()) return false
if (this.selectedPort) return true if (this.selectedPort) return true
@ -219,6 +228,17 @@ async function serialSigner(path) {
}) })
} }
}, },
hwwConfirmNext: async function () {
if (this.hww.confirm.showFee === true) {
this.hww.confirm.confirmed = true
return
}
this.hww.confirm.outputIndex += 1
if (this.hww.confirm.outputIndex >= this.tx.outputs.length) {
this.hww.confirm.showFee = true
}
await this.writer.write(COMMAND_CONFIRM_NEXT + '\n')
},
hwwLogin: async function () { hwwLogin: async function () {
try { try {
await this.writer.write( await this.writer.write(
@ -275,8 +295,10 @@ async function serialSigner(path) {
}) })
} }
}, },
hwwSendPsbt: async function (psbtBase64) { hwwSendPsbt: async function (psbtBase64, tx) {
try { try {
console.log('### hwwSendPsbt tx', tx)
this.tx = tx
this.hww.sendingPsbt = true this.hww.sendingPsbt = true
await this.writer.write(COMMAND_SEND_PSBT + ' ' + psbtBase64 + '\n') await this.writer.write(COMMAND_SEND_PSBT + ' ' + psbtBase64 + '\n')
this.$q.notify({ this.$q.notify({
@ -295,13 +317,19 @@ async function serialSigner(path) {
} }
}, },
handleSendPsbtResponse: function (res = '') { handleSendPsbtResponse: function (res = '') {
this.hww.psbtSent = true this.hww.confirm.outputIndex = 0
this.hww.showConfirmationDialog = true
this.hww.confirm = {
outputIndex: 0,
showFee: false,
confirmed: false
}
this.hww.sendingPsbt = false this.hww.sendingPsbt = false
this.psbtSentResolve() this.psbtSentResolve()
}, },
hwwSignPsbt: async function () { hwwSignPsbt: async function () {
try { try {
this.hww.psbtSent = false this.hww.showConfirmationDialog = false
this.hww.signingPsbt = true this.hww.signingPsbt = true
await this.writer.write(COMMAND_SIGN_PSBT + '\n') await this.writer.write(COMMAND_SIGN_PSBT + '\n')
} catch (error) { } catch (error) {

View file

@ -9,7 +9,7 @@ async function utxoList(path) {
'accounts', 'accounts',
'selectable', 'selectable',
'payed-amount', 'payed-amount',
'sats_denominated', 'sats-denominated',
'mempool_endpoint' 'mempool_endpoint'
], ],
@ -90,7 +90,7 @@ async function utxoList(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
getWalletName: function (walletId) { getWalletName: function (walletId) {
const wallet = (this.accounts || []).find(wl => wl.id === walletId) const wallet = (this.accounts || []).find(wl => wl.id === walletId)

View file

@ -50,7 +50,7 @@ async function walletList(path) {
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this.satsDenominated)
}, },
addWalletAccount: async function () { addWalletAccount: async function () {

View file

@ -7,6 +7,7 @@ const COMMAND_HELP = '/help'
const COMMAND_WIPE = '/wipe' const COMMAND_WIPE = '/wipe'
const COMMAND_SEED = '/seed' const COMMAND_SEED = '/seed'
const COMMAND_RESTORE = '/restore' const COMMAND_RESTORE = '/restore'
const COMMAND_CONFIRM_NEXT = '/confirm-next'
const DEFAULT_RECEIVE_GAP_LIMIT = 20 const DEFAULT_RECEIVE_GAP_LIMIT = 20