mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2024-11-20 10:39:59 +01:00
feat: add accounts using the HWW
This commit is contained in:
parent
73265a9951
commit
2ac8ee95b0
@ -29,8 +29,9 @@ async function serialSigner(path) {
|
||||
showSignedPsbt: false,
|
||||
sendingPsbt: false,
|
||||
signingPsbt: false,
|
||||
psbtSentResolve: null,
|
||||
loginResolve: null,
|
||||
psbtSentResolve: null,
|
||||
xpubResolve: null,
|
||||
confirm: {
|
||||
outputIndex: 0,
|
||||
showFee: false
|
||||
@ -105,7 +106,6 @@ async function serialSigner(path) {
|
||||
})
|
||||
} catch (error) {
|
||||
this.selectedPort = null
|
||||
console.log('### error', error)
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Cannot close serial port!',
|
||||
@ -137,6 +137,12 @@ async function serialSigner(path) {
|
||||
})
|
||||
},
|
||||
|
||||
isFetchingXpub: async function () {
|
||||
return new Promise(resolve => {
|
||||
this.xpubResolve = resolve
|
||||
})
|
||||
},
|
||||
|
||||
checkSerialPortSupported: function () {
|
||||
if (!navigator.serial) {
|
||||
this.$q.notify({
|
||||
@ -162,7 +168,6 @@ async function serialSigner(path) {
|
||||
try {
|
||||
while (true) {
|
||||
const {value, done} = await readStringUntil('\n')
|
||||
console.log('### value', value)
|
||||
if (value) {
|
||||
this.handleSerialPortResponse(value)
|
||||
this.updateSerialPortConsole(value)
|
||||
@ -180,15 +185,31 @@ async function serialSigner(path) {
|
||||
}
|
||||
},
|
||||
handleSerialPortResponse: function (value) {
|
||||
const msg = value.split(' ')
|
||||
if (msg[0] == COMMAND_SIGN_PSBT) this.handleSignResponse(msg[1])
|
||||
else if (msg[0] == COMMAND_PASSWORD) this.handleLoginResponse(msg[1])
|
||||
else if (msg[0] == COMMAND_PASSWORD_CLEAR)
|
||||
this.handleLogoutResponse(msg[1])
|
||||
else if (msg[0] == COMMAND_SEND_PSBT)
|
||||
this.handleSendPsbtResponse(msg[1])
|
||||
else if (msg[0] == COMMAND_WIPE) this.handleWipeResponse(msg[1])
|
||||
else console.log('### console', value)
|
||||
const command = value.split(' ')[0]
|
||||
const commandData = value.substring(command.length).trim()
|
||||
|
||||
switch (command) {
|
||||
case COMMAND_SIGN_PSBT:
|
||||
this.handleSignResponse(commandData)
|
||||
break
|
||||
case COMMAND_PASSWORD:
|
||||
this.handleLoginResponse(commandData)
|
||||
break
|
||||
case COMMAND_PASSWORD_CLEAR:
|
||||
this.handleLogoutResponse(commandData)
|
||||
break
|
||||
case COMMAND_SEND_PSBT:
|
||||
this.handleSendPsbtResponse(commandData)
|
||||
break
|
||||
case COMMAND_WIPE:
|
||||
this.handleWipeResponse(commandData)
|
||||
break
|
||||
case COMMAND_XPUB:
|
||||
this.handleXpubResponse(commandData)
|
||||
break
|
||||
default:
|
||||
console.log('### console', value)
|
||||
}
|
||||
},
|
||||
updateSerialPortConsole: function (value) {
|
||||
this.receivedData += value + '\n'
|
||||
@ -304,7 +325,6 @@ async function serialSigner(path) {
|
||||
}
|
||||
},
|
||||
handleLogoutResponse: function (res = '') {
|
||||
console.log('###handleLogoutResponse ', res)
|
||||
this.hww.authenticated = !(res.trim() === '1')
|
||||
if (this.hww.authenticated) {
|
||||
this.$q.notify({
|
||||
@ -316,7 +336,6 @@ async function serialSigner(path) {
|
||||
},
|
||||
hwwSendPsbt: async function (psbtBase64, tx) {
|
||||
try {
|
||||
console.log('### hwwSendPsbt tx', tx)
|
||||
this.tx = tx
|
||||
this.hww.sendingPsbt = true
|
||||
await this.writer.write(
|
||||
@ -427,7 +446,6 @@ async function serialSigner(path) {
|
||||
},
|
||||
handleWipeResponse: function (res = '') {
|
||||
const wiped = res.trim() === '1'
|
||||
console.log('### wiped', wiped)
|
||||
if (wiped) {
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
@ -443,6 +461,36 @@ async function serialSigner(path) {
|
||||
})
|
||||
}
|
||||
},
|
||||
hwwXpub: async function (path) {
|
||||
try {
|
||||
await this.writer.write(
|
||||
COMMAND_XPUB + ' ' + this.network + ' ' + path + '\n'
|
||||
)
|
||||
} catch (error) {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Failed to fetch XPub!',
|
||||
caption: `${error}`,
|
||||
timeout: 10000
|
||||
})
|
||||
}
|
||||
},
|
||||
handleXpubResponse: function (res = '') {
|
||||
const args = res.trim().split(' ')
|
||||
if (args.length < 3 || args[0].trim() !== '1') {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Failed to fetch XPub!',
|
||||
caption: `${res}`,
|
||||
timeout: 10000
|
||||
})
|
||||
this.xpubResolve({})
|
||||
return
|
||||
}
|
||||
const xpub = args[1].trim()
|
||||
const fingerprint = args[2].trim()
|
||||
this.xpubResolve({xpub, fingerprint})
|
||||
},
|
||||
hwwShowSeed: async function () {
|
||||
try {
|
||||
await this.writer.write(COMMAND_SEED + '\n')
|
||||
|
@ -205,7 +205,7 @@
|
||||
v-if="formDialog.useSerialPort"
|
||||
filled
|
||||
type="text"
|
||||
v-model="formDialog.data.accountPath"
|
||||
v-model="accountPath"
|
||||
height="50px"
|
||||
autogrow
|
||||
label="Account Path"
|
||||
@ -216,7 +216,7 @@
|
||||
unelevated
|
||||
color="primary"
|
||||
:disable="
|
||||
(formDialog.data.masterpub == null && formDialog.data.accountPath == null)||
|
||||
(formDialog.data.masterpub == null && accountPath == null)||
|
||||
formDialog.data.title == null"
|
||||
type="submit"
|
||||
>Add Watch-Only Account</q-btn
|
||||
|
@ -18,13 +18,15 @@ async function walletList(path) {
|
||||
address: {},
|
||||
formDialog: {
|
||||
show: false,
|
||||
addressType: {
|
||||
label: 'Pay-to-witness-pubkey-hash scripts (P2WPKH)',
|
||||
value: 'wpkh'
|
||||
},
|
||||
|
||||
addressType: 'wpkh',
|
||||
useSerialPort: false,
|
||||
data: {}
|
||||
data: {
|
||||
title: '',
|
||||
masterpub: ''
|
||||
}
|
||||
},
|
||||
accountPath: '',
|
||||
filter: '',
|
||||
addressTypeOptions: [
|
||||
{
|
||||
@ -103,6 +105,17 @@ async function walletList(path) {
|
||||
},
|
||||
createWalletAccount: async function (data) {
|
||||
try {
|
||||
if (this.formDialog.useSerialPort) {
|
||||
const {xpub, fingerprint} = await this.fetchXpubFromHww()
|
||||
if (!xpub) return
|
||||
const path = this.accountPath.substring(2)
|
||||
const outputType = this.formDialog.addressType
|
||||
if (outputType === 'sh') {
|
||||
data.masterpub = `${outputType}(wpkh([${fingerprint}/${path}]${xpub}/{0,1}/*))`
|
||||
} else {
|
||||
data.masterpub = `${outputType}([${fingerprint}/${path}]${xpub}/{0,1}/*)`
|
||||
}
|
||||
}
|
||||
const response = await LNbits.api.request(
|
||||
'POST',
|
||||
'/watchonly/api/v1/wallet',
|
||||
@ -117,6 +130,20 @@ async function walletList(path) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
fetchXpubFromHww: async function () {
|
||||
const error = findAccountPathIssues(this.accountPath)
|
||||
if (error) {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Invalid derivation path.',
|
||||
caption: error,
|
||||
timeout: 10000
|
||||
})
|
||||
return
|
||||
}
|
||||
await this.serialSignerRef.hwwXpub(this.accountPath)
|
||||
return await this.serialSignerRef.isFetchingXpub()
|
||||
},
|
||||
deleteWalletAccount: function (walletAccountId) {
|
||||
LNbits.utils
|
||||
.confirmDialog(
|
||||
@ -214,7 +241,6 @@ async function walletList(path) {
|
||||
this.formDialog.useSerialPort = false
|
||||
},
|
||||
getXpubFromDevice: async function () {
|
||||
this.handleAddressTypeChanged('wpkh')
|
||||
try {
|
||||
if (!this.serialSignerRef.isConnected()) {
|
||||
const portOpen = await this.serialSignerRef.openSerialPort()
|
||||
@ -239,12 +265,13 @@ async function walletList(path) {
|
||||
handleAddressTypeChanged: function (value) {
|
||||
const addressType =
|
||||
this.addressTypeOptions.find(t => t.value === value) || {}
|
||||
this.formDialog.data.accountPath = addressType.path
|
||||
this.accountPath = addressType.path
|
||||
}
|
||||
},
|
||||
created: async function () {
|
||||
if (this.inkey) {
|
||||
await this.refreshWalletAccounts()
|
||||
this.handleAddressTypeChanged('wpkh')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -9,6 +9,7 @@ const COMMAND_SEED = '/seed'
|
||||
const COMMAND_RESTORE = '/restore'
|
||||
const COMMAND_CONFIRM_NEXT = '/confirm-next'
|
||||
const COMMAND_CANCEL = '/cancel'
|
||||
const COMMAND_XPUB = '/xpub'
|
||||
|
||||
const DEFAULT_RECEIVE_GAP_LIMIT = 20
|
||||
|
||||
@ -171,3 +172,12 @@ function loadTemplateAsync(path) {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function findAccountPathIssues(path = '') {
|
||||
const p = path.split('/')
|
||||
if (p[0] !== 'm') return "Path must start with 'm/'"
|
||||
for (let i = 1; i < p.length; i++) {
|
||||
if (p[i].endsWith('')) p[i] = p[i].substring(0, p[i].length - 1)
|
||||
if (isNaN(p[i])) return `${p[i]} is not a valid value`
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user