feat: extract signed transaction
This commit is contained in:
parent
d5cc8d9187
commit
32486d62bf
7 changed files with 133 additions and 72 deletions
|
|
@ -186,8 +186,13 @@
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-btn-dropdown>
|
</q-btn-dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
<q-spinner v-if="showChecking" color="primary"></q-spinner>
|
<q-spinner
|
||||||
|
v-if="showChecking"
|
||||||
|
size="2.55em"
|
||||||
|
color="primary"
|
||||||
|
></q-spinner>
|
||||||
<q-badge
|
<q-badge
|
||||||
v-if="changeAmount < 0"
|
v-if="changeAmount < 0"
|
||||||
class="text-subtitle2 float-right"
|
class="text-subtitle2 float-right"
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ async function payment(path) {
|
||||||
|
|
||||||
if (this.psbtBase64) {
|
if (this.psbtBase64) {
|
||||||
await this.serialSignerRef.hwwSendPsbt(this.psbtBase64)
|
await this.serialSignerRef.hwwSendPsbt(this.psbtBase64)
|
||||||
|
await this.serialSignerRef.isSendingPsbt()
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('### hwwSendPsbt')
|
console.log('### hwwSendPsbt')
|
||||||
|
|
@ -189,6 +190,77 @@ async function payment(path) {
|
||||||
}
|
}
|
||||||
this.selectChangeAddress(this.changeWallet)
|
this.selectChangeAddress(this.changeWallet)
|
||||||
},
|
},
|
||||||
|
updateSignedPsbt: async function (psbtBase64) {
|
||||||
|
console.log('### payment updateSignedPsbt psbtBase64', psbtBase64)
|
||||||
|
|
||||||
|
const data = await this.extractTxFromPsbt(psbtBase64)
|
||||||
|
if (data) {
|
||||||
|
this.signedTx = JSON.parse(data.tx_json)
|
||||||
|
this.signedTxHex = data.tx_hex
|
||||||
|
} else {
|
||||||
|
this.signedTx = null
|
||||||
|
this.signedTxHex = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
extractTxFromPsbt: async function (psbtBase64) {
|
||||||
|
console.log('### extractTxFromPsbt psbtBase64', psbtBase64)
|
||||||
|
try {
|
||||||
|
const {data} = await LNbits.api.request(
|
||||||
|
'PUT',
|
||||||
|
'/watchonly/api/v1/psbt/extract',
|
||||||
|
this.adminkey,
|
||||||
|
{
|
||||||
|
psbtBase64,
|
||||||
|
inputs: this.tx.inputs
|
||||||
|
}
|
||||||
|
)
|
||||||
|
console.log('### extractTxFromPsbt data', data)
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
console.log('### error', error)
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'warning',
|
||||||
|
message: 'Cannot finalize PSBT!',
|
||||||
|
timeout: 10000
|
||||||
|
})
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
broadcastTransaction: async function () {
|
||||||
|
try {
|
||||||
|
const wallet = this.g.user.wallets[0]
|
||||||
|
const {data} = await LNbits.api.request(
|
||||||
|
'POST',
|
||||||
|
'/watchonly/api/v1/tx',
|
||||||
|
wallet.adminkey,
|
||||||
|
{tx_hex: this.payment.signedTxHex}
|
||||||
|
)
|
||||||
|
this.payment.sentTxId = data
|
||||||
|
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Transaction broadcasted!',
|
||||||
|
caption: `${data}`,
|
||||||
|
timeout: 10000
|
||||||
|
})
|
||||||
|
|
||||||
|
this.hww.psbtSent = false
|
||||||
|
this.payment.psbtBase64Signed = null
|
||||||
|
this.payment.signedTxHex = null
|
||||||
|
this.payment.signedTx = null
|
||||||
|
this.payment.psbtBase64 = null
|
||||||
|
|
||||||
|
await this.scanAddressWithAmount()
|
||||||
|
} catch (error) {
|
||||||
|
this.payment.sentTxId = null
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'warning',
|
||||||
|
message: 'Failed to broadcast!',
|
||||||
|
caption: `${error}`,
|
||||||
|
timeout: 10000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
fetchTxHex: async function (txId) {
|
fetchTxHex: async function (txId) {
|
||||||
const {
|
const {
|
||||||
bitcoin: {transactions: transactionsAPI}
|
bitcoin: {transactions: transactionsAPI}
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,35 @@
|
||||||
</q-form>
|
</q-form>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="hww.psbtSent" position="top">
|
||||||
|
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||||
|
<q-form @submit="hwwSignPsbt" class="q-gutter-md">
|
||||||
|
<div class="row q-mt-lg">
|
||||||
|
<div class="col-12">
|
||||||
|
<span>Check transaction on your hardware device</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row q-mt-lg">
|
||||||
|
<!-- todo: disable until all data is confirmed -->
|
||||||
|
<q-btn
|
||||||
|
unelevated
|
||||||
|
color="green"
|
||||||
|
:disable="!selectedPort"
|
||||||
|
type="submit"
|
||||||
|
label="Confirm"
|
||||||
|
>
|
||||||
|
<q-spinner v-if="hww.signingPsbt" color="primary"></q-spinner>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
||||||
|
>Cancel</q-btn
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
<q-dialog v-model="hww.showWipeDialog" position="top">
|
<q-dialog v-model="hww.showWipeDialog" 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="hwwWipe" class="q-gutter-md">
|
<q-form @submit="hwwWipe" class="q-gutter-md">
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,13 @@ async function serialSigner(path) {
|
||||||
showPasswordDialog: false,
|
showPasswordDialog: false,
|
||||||
showWipeDialog: false,
|
showWipeDialog: false,
|
||||||
showRestoreDialog: false,
|
showRestoreDialog: false,
|
||||||
|
showConfirmationDialog: false,
|
||||||
showConsole: false,
|
showConsole: false,
|
||||||
showSignedPsbt: false,
|
showSignedPsbt: false,
|
||||||
sendingPsbt: false,
|
sendingPsbt: false,
|
||||||
signingPsbt: false,
|
signingPsbt: false,
|
||||||
psbtSent: false
|
psbtSent: false,
|
||||||
|
psbtSentResolve: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -113,6 +115,12 @@ async function serialSigner(path) {
|
||||||
isAuthenticated: function () {
|
isAuthenticated: function () {
|
||||||
return this.hww.authenticated
|
return this.hww.authenticated
|
||||||
},
|
},
|
||||||
|
isSendingPsbt: async function () {
|
||||||
|
if (!this.hww.sendingPsbt) return false
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.psbtSentResolve = resolve
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
checkSerialPortSupported: function () {
|
checkSerialPortSupported: function () {
|
||||||
if (!navigator.serial) {
|
if (!navigator.serial) {
|
||||||
|
|
@ -281,6 +289,7 @@ async function serialSigner(path) {
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.hww.sendingPsbt = false
|
||||||
this.$q.notify({
|
this.$q.notify({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
message: 'Failed to send data to serial port!',
|
message: 'Failed to send data to serial port!',
|
||||||
|
|
@ -292,9 +301,11 @@ async function serialSigner(path) {
|
||||||
handleSendPsbtResponse: function (res = '') {
|
handleSendPsbtResponse: function (res = '') {
|
||||||
this.hww.psbtSent = true
|
this.hww.psbtSent = true
|
||||||
this.hww.sendingPsbt = false
|
this.hww.sendingPsbt = false
|
||||||
|
this.psbtSentResolve()
|
||||||
},
|
},
|
||||||
hwwSignPsbt: async function () {
|
hwwSignPsbt: async function () {
|
||||||
try {
|
try {
|
||||||
|
this.hww.psbtSent = 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')
|
||||||
this.$q.notify({
|
this.$q.notify({
|
||||||
|
|
@ -407,6 +418,9 @@ async function serialSigner(path) {
|
||||||
this.hww.password = null
|
this.hww.password = null
|
||||||
this.hww.showPassword = false
|
this.hww.showPassword = false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
updateSignedPsbt: async function (value) {
|
||||||
|
this.$emit('signed:psbt', value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: async function () {}
|
created: async function () {}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,9 @@ const watchOnly = async () => {
|
||||||
showAddress: false,
|
showAddress: false,
|
||||||
addressNote: '',
|
addressNote: '',
|
||||||
showPayment: false,
|
showPayment: false,
|
||||||
fetchedUtxos: false
|
fetchedUtxos: false,
|
||||||
|
signedTx: null,
|
||||||
|
signedTxHex: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -202,75 +204,11 @@ const watchOnly = async () => {
|
||||||
|
|
||||||
//################### PSBT ###################
|
//################### PSBT ###################
|
||||||
|
|
||||||
extractTxFromPsbt: async function (psbtBase64) {
|
updateSignedPsbt: async function (psbtBase64) {
|
||||||
const wallet = this.g.user.wallets[0]
|
console.log('### updateSignedPsbt psbtBase64', psbtBase64)
|
||||||
try {
|
this.$refs.paymentRef.updateSignedPsbt(psbtBase64)
|
||||||
const {data} = await LNbits.api.request(
|
|
||||||
'PUT',
|
|
||||||
'/watchonly/api/v1/psbt/extract',
|
|
||||||
wallet.adminkey,
|
|
||||||
{
|
|
||||||
psbtBase64,
|
|
||||||
inputs: this.payment.tx.inputs
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'warning',
|
|
||||||
message: 'Cannot finalize PSBT!',
|
|
||||||
timeout: 10000
|
|
||||||
})
|
|
||||||
LNbits.utils.notifyApiError(error)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
updateSignedPsbt: async function (value) {
|
|
||||||
this.payment.psbtBase64Signed = value
|
|
||||||
|
|
||||||
const data = await this.extractTxFromPsbt(this.payment.psbtBase64Signed)
|
|
||||||
if (data) {
|
|
||||||
this.payment.signedTx = JSON.parse(data.tx_json)
|
|
||||||
this.payment.signedTxHex = data.tx_hex
|
|
||||||
} else {
|
|
||||||
this.payment.signedTx = null
|
|
||||||
this.payment.signedTxHex = null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
broadcastTransaction: async function () {
|
|
||||||
try {
|
|
||||||
const wallet = this.g.user.wallets[0]
|
|
||||||
const {data} = await LNbits.api.request(
|
|
||||||
'POST',
|
|
||||||
'/watchonly/api/v1/tx',
|
|
||||||
wallet.adminkey,
|
|
||||||
{tx_hex: this.payment.signedTxHex}
|
|
||||||
)
|
|
||||||
this.payment.sentTxId = data
|
|
||||||
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: 'Transaction broadcasted!',
|
|
||||||
caption: `${data}`,
|
|
||||||
timeout: 10000
|
|
||||||
})
|
|
||||||
|
|
||||||
this.hww.psbtSent = false
|
|
||||||
this.payment.psbtBase64Signed = null
|
|
||||||
this.payment.signedTxHex = null
|
|
||||||
this.payment.signedTx = null
|
|
||||||
this.payment.psbtBase64 = null
|
|
||||||
|
|
||||||
await this.scanAddressWithAmount()
|
|
||||||
} catch (error) {
|
|
||||||
this.payment.sentTxId = null
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'warning',
|
|
||||||
message: 'Failed to broadcast!',
|
|
||||||
caption: `${error}`,
|
|
||||||
timeout: 10000
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//################### SERIAL PORT ###################
|
//################### SERIAL PORT ###################
|
||||||
|
|
||||||
//################### HARDWARE WALLET ###################
|
//################### HARDWARE WALLET ###################
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,6 @@ const readFromSerialPort = reader => {
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
const {value, done} = await reader.read()
|
const {value, done} = await reader.read()
|
||||||
console.log('### serial read', value)
|
|
||||||
if (value) {
|
if (value) {
|
||||||
const values = value.split(separator)
|
const values = value.split(separator)
|
||||||
// found one or more separators
|
// found one or more separators
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@
|
||||||
:adminkey="g.user.wallets[0].adminkey"
|
:adminkey="g.user.wallets[0].adminkey"
|
||||||
>
|
>
|
||||||
<template v-slot:serial>
|
<template v-slot:serial>
|
||||||
<serial-signer ref="serialSigner"></serial-signer>
|
<serial-signer
|
||||||
|
ref="serialSigner"
|
||||||
|
@signed:psbt="updateSignedPsbt"
|
||||||
|
></serial-signer>
|
||||||
</template>
|
</template>
|
||||||
</wallet-config>
|
</wallet-config>
|
||||||
|
|
||||||
|
|
@ -113,6 +116,7 @@
|
||||||
</q-card>
|
</q-card>
|
||||||
<div class="q-pt-sm">
|
<div class="q-pt-sm">
|
||||||
<payment
|
<payment
|
||||||
|
ref="paymentRef"
|
||||||
v-show="showPayment"
|
v-show="showPayment"
|
||||||
:accounts="walletAccounts"
|
:accounts="walletAccounts"
|
||||||
:addresses="addresses"
|
:addresses="addresses"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue