diff --git a/lnbits/extensions/watchonly/crud.py b/lnbits/extensions/watchonly/crud.py
index 21fea6f0..de338b91 100644
--- a/lnbits/extensions/watchonly/crud.py
+++ b/lnbits/extensions/watchonly/crud.py
@@ -23,9 +23,10 @@ async def create_watch_wallet(w: WalletAccount) -> WalletAccount:
type,
address_no,
balance,
- network
+ network,
+ meta
)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
wallet_id,
@@ -37,6 +38,7 @@ async def create_watch_wallet(w: WalletAccount) -> WalletAccount:
w.address_no,
w.balance,
w.network,
+ w.meta,
),
)
diff --git a/lnbits/extensions/watchonly/migrations.py b/lnbits/extensions/watchonly/migrations.py
index 0c06b738..76f7f951 100644
--- a/lnbits/extensions/watchonly/migrations.py
+++ b/lnbits/extensions/watchonly/migrations.py
@@ -93,3 +93,10 @@ async def m006_drop_mempool_table(db):
Mempool data is now part of `config`
"""
await db.execute("DROP TABLE watchonly.mempool;")
+
+
+async def m007_add_wallet_meta_data(db):
+ """
+ Add 'meta' for storing various metadata about the wallet
+ """
+ await db.execute("ALTER TABLE watchonly.wallets ADD COLUMN meta TEXT DEFAULT '{}';")
diff --git a/lnbits/extensions/watchonly/models.py b/lnbits/extensions/watchonly/models.py
index 0c08780d..cedaa210 100644
--- a/lnbits/extensions/watchonly/models.py
+++ b/lnbits/extensions/watchonly/models.py
@@ -9,6 +9,7 @@ class CreateWallet(BaseModel):
masterpub: str = Query("")
title: str = Query("")
network: str = "Mainnet"
+ meta: str = "{}"
class WalletAccount(BaseModel):
@@ -21,6 +22,7 @@ class WalletAccount(BaseModel):
balance: int
type: Optional[str] = ""
network: str = "Mainnet"
+ meta: str = "{}"
@classmethod
def from_row(cls, row: Row) -> "WalletAccount":
diff --git a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html
index 68b81980..b256ea60 100644
--- a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html
+++ b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html
@@ -170,6 +170,31 @@
type="password"
label="Password"
>
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
Enter new password (8 numbers/letters)
Master Pubkey:
-
+
+
+
+
+
+
+
Last Address Index:
diff --git a/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js b/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js
index d5ad5e32..d8df84e1 100644
--- a/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js
+++ b/lnbits/extensions/watchonly/static/components/wallet-list/wallet-list.js
@@ -118,9 +118,11 @@ async function walletList(path) {
},
createWalletAccount: async function (data) {
try {
+ const meta = {accountPath: this.accountPath}
if (this.formDialog.useSerialPort) {
const {xpub, fingerprint} = await this.fetchXpubFromHww()
if (!xpub) return
+ meta.xpub = xpub
const path = this.accountPath.substring(2)
const outputType = this.formDialog.addressType.id
if (outputType === 'sh') {
@@ -129,6 +131,7 @@ async function walletList(path) {
data.masterpub = `${outputType}([${fingerprint}/${path}]${xpub}/{0,1}/*)`
}
}
+ data.meta = JSON.stringify(meta)
const response = await LNbits.api.request(
'POST',
'/watchonly/api/v1/wallet',
@@ -247,7 +250,7 @@ async function walletList(path) {
const wallet = this.walletAccounts.find(w => w.id === walletId) || {}
wallet.address_no = addressData.addressIndex
- this.$emit('new-receive-address', addressData)
+ this.$emit('new-receive-address', {addressData, wallet})
},
showAddAccountDialog: function () {
this.formDialog.show = true
@@ -283,6 +286,16 @@ async function walletList(path) {
const addressType =
this.addressTypeOptions.find(t => t.id === value.id) || {}
this.accountPath = addressType[`path${this.network}`]
+ },
+ // todo: bad. base.js not present in custom components
+ copyText: function (text, message, position) {
+ var notify = this.$q.notify
+ Quasar.utils.copyToClipboard(text).then(function () {
+ notify({
+ message: message || 'Copied to clipboard!',
+ position: position || 'bottom'
+ })
+ })
}
},
created: async function () {
diff --git a/lnbits/extensions/watchonly/static/js/index.js b/lnbits/extensions/watchonly/static/js/index.js
index 61255c50..45f2293b 100644
--- a/lnbits/extensions/watchonly/static/js/index.js
+++ b/lnbits/extensions/watchonly/static/js/index.js
@@ -172,10 +172,6 @@ const watchOnly = async () => {
this.$refs.paymentRef.updateSignedPsbt(psbtBase64)
},
- //################### SERIAL PORT ###################
-
- //################### HARDWARE WALLET ###################
-
//################### UTXOs ###################
scanAllAddresses: async function () {
await this.refreshAddresses()
@@ -380,6 +376,26 @@ const watchOnly = async () => {
showAddressDetails: function (addressData) {
this.openQrCodeDialog(addressData)
},
+ showAddressDetailsWithConfirmation: function ({addressData, wallet}) {
+ this.showAddressDetails(addressData)
+ if (this.$refs.serialSigner.isConnected()) {
+ if (this.$refs.serialSigner.isAuthenticated()) {
+ if (wallet.meta?.accountPath) {
+ const branchIndex = addressData.isChange ? 1 : 0
+ const path =
+ wallet.meta.accountPath +
+ `/${branchIndex}/${addressData.addressIndex}`
+ this.$refs.serialSigner.hwwShowAddress(path, addressData.address)
+ }
+ } else {
+ this.$q.notify({
+ type: 'warning',
+ message: 'Please login in order to confirm address on device',
+ timeout: 10000
+ })
+ }
+ }
+ },
initUtxos: function (addresses) {
if (!this.fetchedUtxos && addresses.length) {
this.fetchedUtxos = true
diff --git a/lnbits/extensions/watchonly/static/js/map.js b/lnbits/extensions/watchonly/static/js/map.js
index ecc0b316..81093936 100644
--- a/lnbits/extensions/watchonly/static/js/map.js
+++ b/lnbits/extensions/watchonly/static/js/map.js
@@ -74,6 +74,7 @@ const mapWalletAccount = function (o) {
'YYYY-MM-DD HH:mm'
)
: '',
+ meta: o.meta ? JSON.parse(o.meta) : null,
label: o.title,
expanded: false
})
diff --git a/lnbits/extensions/watchonly/static/js/utils.js b/lnbits/extensions/watchonly/static/js/utils.js
index 5e39a37f..c73dd9c0 100644
--- a/lnbits/extensions/watchonly/static/js/utils.js
+++ b/lnbits/extensions/watchonly/static/js/utils.js
@@ -3,6 +3,7 @@ const PSBT_BASE64_PREFIX = 'cHNidP8'
const COMMAND_PING = '/ping'
const COMMAND_PASSWORD = '/password'
const COMMAND_PASSWORD_CLEAR = '/password-clear'
+const COMMAND_ADDRESS = '/address'
const COMMAND_SEND_PSBT = '/psbt'
const COMMAND_SIGN_PSBT = '/sign'
const COMMAND_HELP = '/help'
diff --git a/lnbits/extensions/watchonly/templates/watchonly/index.html b/lnbits/extensions/watchonly/templates/watchonly/index.html
index 1a564489..f9ffc298 100644
--- a/lnbits/extensions/watchonly/templates/watchonly/index.html
+++ b/lnbits/extensions/watchonly/templates/watchonly/index.html
@@ -27,7 +27,7 @@
:addresses="addresses"
:serial-signer-ref="$refs.serialSigner"
@accounts-update="updateAccounts"
- @new-receive-address="showAddressDetails"
+ @new-receive-address="showAddressDetailsWithConfirmation"
>
@@ -148,7 +148,8 @@
- {{SITE_TITLE}} Onchain Wallet (watch-only) Extension (v0.100)
+ {{SITE_TITLE}} Onchain Wallet (watch-only) Extension
+ (v0.100)
diff --git a/lnbits/extensions/watchonly/views_api.py b/lnbits/extensions/watchonly/views_api.py
index 1a4b93ed..3bfa4707 100644
--- a/lnbits/extensions/watchonly/views_api.py
+++ b/lnbits/extensions/watchonly/views_api.py
@@ -93,6 +93,7 @@ async def api_wallet_create_or_update(
address_no=-1, # so fresh address on empty wallet can get address with index 0
balance=0,
network=network["name"],
+ meta=data.meta,
)
wallets = await get_watch_wallets(w.wallet.user, network["name"])
@@ -137,7 +138,7 @@ async def api_wallet_delete(wallet_id, w: WalletTypeInfo = Depends(require_admin
await delete_watch_wallet(wallet_id)
await delete_addresses_for_wallet(wallet_id)
- raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
+ return "", HTTPStatus.NO_CONTENT
#############################ADDRESSES##########################