feat: propagate config update only when explicitly updated

This commit is contained in:
Vlad Stan 2022-08-01 10:45:31 +03:00
parent 657ed7a37c
commit 4671954896
11 changed files with 102 additions and 80 deletions

View file

@ -18,6 +18,7 @@ class WalletAccount(BaseModel):
address_no: int address_no: int
balance: int balance: int
type: str = "" type: str = ""
network: str = "Mainnet"
@classmethod @classmethod
def from_row(cls, row: Row) -> "WalletAccount": def from_row(cls, row: Row) -> "WalletAccount":
@ -100,3 +101,4 @@ class Config(BaseModel):
receive_gap_limit = 20 receive_gap_limit = 20
change_gap_limit = 5 change_gap_limit = 5
sats_denominated = True sats_denominated = True
network = "Mainnet"

View file

@ -35,13 +35,14 @@ async function feeRate(path) {
}, },
refreshRecommendedFees: async function () { refreshRecommendedFees: async function () {
const { const fn = async () => {
bitcoin: {fees: feesAPI} const {
} = mempoolJS({ bitcoin: {fees: feesAPI}
hostname: new URL(this.mempoolEndpoint).hostname } = mempoolJS({
}) hostname: this.mempoolEndpoint
})
const fn = async () => feesAPI.getFeesRecommended() return feesAPI.getFeesRecommended()
}
this.recommededFees = await retryWithDelay(fn) this.recommededFees = await retryWithDelay(fn)
}, },
getFeeRateLabel: function (feeRate) { getFeeRateLabel: function (feeRate) {

View file

@ -2,7 +2,6 @@
<q-form @submit="checkAndSend" ref="paymentFormRef" class="q-gutter-md"> <q-form @submit="checkAndSend" ref="paymentFormRef" class="q-gutter-md">
<q-card class="q-mt-lg"> <q-card class="q-mt-lg">
<q-card-section> <q-card-section>
<send-to <send-to
:data.sync="sendToList" :data.sync="sendToList"
:fee-rate="feeRate" :fee-rate="feeRate"
@ -42,7 +41,11 @@
<div v-show="showCustomFee" class="row items-center no-wrap q-mt-md"> <div v-show="showCustomFee" class="row items-center no-wrap q-mt-md">
<div class="col-12"> <div class="col-12">
<q-separator class="q-mb-md"></q-separator> <q-separator class="q-mb-md"></q-separator>
<fee-rate :fee-value="feeValue" :rate.sync="feeRate" :mempool-endpoint="mempoolEndpoint"></fee-rate> <fee-rate
:fee-value="feeValue"
:rate.sync="feeRate"
:mempool-endpoint="mempoolEndpoint"
></fee-rate>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>

View file

@ -292,7 +292,7 @@ async function payment(path) {
const { const {
bitcoin: {transactions: transactionsAPI} bitcoin: {transactions: transactionsAPI}
} = mempoolJS({ } = mempoolJS({
hostname: new URL(this.mempoolEndpoint).hostname hostname: this.mempoolEndpoint
}) })
try { try {

View file

@ -2,12 +2,7 @@
<q-card> <q-card>
<div class="row items-center no-wrap q-mb-md"> <div class="row items-center no-wrap q-mb-md">
<div class="col-2 q-ml-lg"> <div class="col-2 q-ml-lg">
<q-btn <q-btn unelevated @click="show = true" color="primary" icon="settings">
unelevated
@click="config.show = true"
color="primary"
icon="settings"
>
</q-btn> </q-btn>
</div> </div>
<div class="col-8"> <div class="col-8">
@ -21,13 +16,13 @@
</div> </div>
</q-card> </q-card>
<q-dialog v-model="config.show" position="top"> <q-dialog v-model="show" 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="updateConfig" class="q-gutter-md"> <q-form @submit="updateConfig" class="q-gutter-md">
<q-input <q-input
filled filled
dense dense
v-model.trim="config.data.mempool_endpoint" v-model.trim="config.mempool_endpoint"
type="text" type="text"
label="Mempool Endpoint" label="Mempool Endpoint"
> >
@ -36,7 +31,7 @@
<q-input <q-input
filled filled
dense dense
v-model.number="config.data.receive_gap_limit" v-model.number="config.receive_gap_limit"
type="number" type="number"
min="0" min="0"
label="Receive Gap Limit" label="Receive Gap Limit"
@ -45,7 +40,7 @@
<q-input <q-input
filled filled
dense dense
v-model.number="config.data.change_gap_limit" v-model.number="config.change_gap_limit"
type="number" type="number"
min="0" min="0"
label="Change Gap Limit" label="Change Gap Limit"
@ -55,15 +50,15 @@
filled filled
dense dense
emit-value emit-value
v-model="config.data.network" v-model="config.network"
:options="networOptions" :options="networOptions"
label="Network" label="Network"
></q-select> ></q-select>
<q-toggle <q-toggle
:label="config.data.sats_denominated ? 'sats denominated' : 'BTC denominated'" :label="config.sats_denominated ? 'sats denominated' : 'BTC denominated'"
color="secodary" color="secodary"
v-model="config.data.sats_denominated" v-model="config.sats_denominated"
></q-toggle> ></q-toggle>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
@ -71,7 +66,7 @@
unelevated unelevated
color="primary" color="primary"
:disable=" :disable="
!config.data.mempool_endpoint " !config.mempool_endpoint "
type="submit" type="submit"
>Update</q-btn >Update</q-btn
> >

View file

@ -4,24 +4,51 @@ async function walletConfig(path) {
name: 'wallet-config', name: 'wallet-config',
template: t, template: t,
props: ['total', 'config', 'adminkey'], props: ['total', 'config-data', 'adminkey'],
data: function () { data: function () {
return {} return {
networOptions: ['Mainnet', 'Testnet'],
internalConfig: {
mempool_endpoint: 'https://mempool.space',
receive_gap_limit: 20,
change_gap_limit: 5
},
show: false
}
},
computed: {
config: {
get() {
console.log('### get config', this.internalConfig)
return this.internalConfig
},
set(value) {
value.isLoaded = true
console.log('### set config', this.internalConfig)
this.internalConfig = JSON.parse(JSON.stringify(value))
this.$emit(
'update:config-data',
JSON.parse(JSON.stringify(this.internalConfig))
)
}
}
}, },
methods: { methods: {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this.config.data.sats_denominated) return satOrBtc(val, showUnit, this.config.sats_denominated)
}, },
updateConfig: async function () { updateConfig: async function () {
try { try {
await LNbits.api.request( const {data} = await LNbits.api.request(
'PUT', 'PUT',
'/watchonly/api/v1/config', '/watchonly/api/v1/config',
this.adminkey, this.adminkey,
this.config.data this.config
) )
this.config.show = false this.show = false
this.config = data
} catch (error) { } catch (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
} }
@ -33,7 +60,7 @@ async function walletConfig(path) {
'/watchonly/api/v1/config', '/watchonly/api/v1/config',
this.adminkey this.adminkey
) )
this.config.data = data this.config = data
} catch (error) { } catch (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
} }

View file

@ -168,15 +168,6 @@
label="Account Extended Public Key; xpub, ypub, zpub; Bitcoin Descriptor" label="Account Extended Public Key; xpub, ypub, zpub; Bitcoin Descriptor"
></q-input> ></q-input>
<q-select
filled
dense
emit-value
v-model="formDialog.data.network"
:options="networOptions"
label="Network"
></q-select>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn <q-btn
unelevated unelevated

View file

@ -14,7 +14,6 @@ async function walletList(path) {
data: {} data: {}
}, },
filter: '', filter: '',
networOptions: ['Mainnet', 'Testnet'],
walletsTable: { walletsTable: {
columns: [ columns: [
{ {

View file

@ -31,15 +31,7 @@ const watchOnly = async () => {
tab: 'addresses', tab: 'addresses',
config: { config: {sats_denominated: true},
data: {
mempool_endpoint: 'https://mempool.space',
receive_gap_limit: 20,
change_gap_limit: 5
},
show: false
},
qrCodeDialog: { qrCodeDialog: {
show: false, show: false,
@ -58,6 +50,16 @@ const watchOnly = async () => {
fetchedUtxos: false fetchedUtxos: false
} }
}, },
computed: {
mempoolHostname() {
if (!this.config.isLoaded) return
const hostname = new URL(this.config.mempool_endpoint).hostname
if (this.config.network === 'testnet') {
hostname += '/testnet'
}
return hostname
}
},
methods: { methods: {
updateAmountForAddress: async function (addressData, amount = 0) { updateAmountForAddress: async function (addressData, amount = 0) {
@ -321,31 +323,32 @@ const watchOnly = async () => {
//################### MEMPOOL API ################### //################### MEMPOOL API ###################
getAddressTxsDelayed: async function (addrData) { getAddressTxsDelayed: async function (addrData) {
const { const fn = async () => {
bitcoin: {addresses: addressesAPI} const {
} = mempoolJS({ bitcoin: {addresses: addressesAPI}
hostname: new URL(this.config.data.mempool_endpoint).hostname } = mempoolJS({
}) hostname: this.mempoolHostname
})
const fn = async () => return addressesAPI.getAddressTxs({
addressesAPI.getAddressTxs({
address: addrData.address address: addrData.address
}) })
}
const addressTxs = await retryWithDelay(fn) const addressTxs = await retryWithDelay(fn)
return this.addressHistoryFromTxs(addrData, addressTxs) return this.addressHistoryFromTxs(addrData, addressTxs)
}, },
getAddressTxsUtxoDelayed: async function (address) { getAddressTxsUtxoDelayed: async function (address) {
const { const fn = async () => {
bitcoin: {addresses: addressesAPI} const {
} = mempoolJS({ bitcoin: {addresses: addressesAPI}
hostname: new URL(this.config.data.mempool_endpoint).hostname } = mempoolJS({
}) hostname: this.mempoolHostname
})
const fn = async () => return addressesAPI.getAddressTxsUtxo({
addressesAPI.getAddressTxsUtxo({
address address
}) })
}
return retryWithDelay(fn) return retryWithDelay(fn)
}, },

View file

@ -4,13 +4,13 @@
<div class="col-12 col-md-7 q-gutter-y-md"> <div class="col-12 col-md-7 q-gutter-y-md">
<wallet-config <wallet-config
:total="utxos.total" :total="utxos.total"
:config="config" :config-data.sync="config"
:adminkey="g.user.wallets[0].adminkey" :adminkey="g.user.wallets[0].adminkey"
> >
<template v-slot:serial> <template v-slot:serial>
<serial-signer <serial-signer
ref="serialSigner" ref="serialSigner"
:sats-denominated="config.data.sats_denominated" :sats-denominated="config.sats_denominated"
@signed:psbt="updateSignedPsbt" @signed:psbt="updateSignedPsbt"
></serial-signer> ></serial-signer>
</template> </template>
@ -19,7 +19,7 @@
<wallet-list <wallet-list
:adminkey="g.user.wallets[0].adminkey" :adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey" :inkey="g.user.wallets[0].inkey"
:sats-denominated="config.data.sats_denominated" :sats-denominated="config.sats_denominated"
:addresses="addresses" :addresses="addresses"
@accounts-update="updateAccounts" @accounts-update="updateAccounts"
@new-receive-address="showAddressDetails" @new-receive-address="showAddressDetails"
@ -76,7 +76,7 @@
</div> </div>
</q-card> </q-card>
<q-card> <q-card v-if="config.isLoaded">
<q-card-section v-show="!showPayment"> <q-card-section v-show="!showPayment">
<q-tabs v-model="tab" no-caps class="bg-dark text-white shadow-2"> <q-tabs v-model="tab" no-caps class="bg-dark text-white shadow-2">
<q-tab name="addresses" label="Addresses"></q-tab> <q-tab name="addresses" label="Addresses"></q-tab>
@ -89,8 +89,8 @@
ref="addressList" ref="addressList"
:addresses="addresses" :addresses="addresses"
:accounts="walletAccounts" :accounts="walletAccounts"
:mempool-endpoint="config.data.mempool_endpoint" :mempool-endpoint="mempoolHostname"
:sats-denominated="config.data.sats_denominated" :sats-denominated="config.sats_denominated"
@scan:address="scanAddress" @scan:address="scanAddress"
@show-address-details="showAddressDetails" @show-address-details="showAddressDetails"
@update:addresses="initUtxos" @update:addresses="initUtxos"
@ -101,29 +101,28 @@
<q-tab-panel name="history"> <q-tab-panel name="history">
<history <history
:history="history" :history="history"
:mempool-endpoint="config.data.mempool_endpoint" :mempool-endpoint="mempoolHostname"
:sats-denominated="config.data.sats_denominated" :sats-denominated="config.sats_denominated"
></history> ></history>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="utxos"> <q-tab-panel name="utxos">
<utxo-list <utxo-list
:utxos="utxos.data" :utxos="utxos.data"
:mempool-endpoint="config.data.mempool_endpoint" :mempool-endpoint="mempoolHostname"
:sats-denominated="config.data.sats_denominated" :sats-denominated="config.sats_denominated"
></utxo-list> ></utxo-list>
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</q-card-section> </q-card-section>
</q-card> </q-card>
<div class="q-pt-sm"> <div v-if="config.isLoaded" class="q-pt-sm">
{{config.data.mempool_endpoint}}
<payment <payment
ref="paymentRef" ref="paymentRef"
v-show="showPayment" v-show="showPayment"
:accounts="walletAccounts" :accounts="walletAccounts"
:addresses="addresses" :addresses="addresses"
:utxos="utxos.data" :utxos="utxos.data"
:mempool-endpoint="config.data.mempool_endpoint" :mempool-endpoint="mempoolHostname"
:adminkey="g.user.wallets[0].adminkey" :adminkey="g.user.wallets[0].adminkey"
:serial-signer-ref="$refs.serialSigner" :serial-signer-ref="$refs.serialSigner"
></payment> ></payment>
@ -168,7 +167,7 @@
size="ms" size="ms"
icon="launch" icon="launch"
type="a" type="a"
:href="config.mempool_endpoint + '/address/' + currentAddress.address" :href="mempoolHostname + '/address/' + currentAddress.address"
target="_blank" target="_blank"
></q-btn> ></q-btn>
</p> </p>

View file

@ -233,8 +233,9 @@ async def api_psbt_create(
descriptors[masterpub.fingerprint] = parse_key(masterpub.public_key) descriptors[masterpub.fingerprint] = parse_key(masterpub.public_key)
inputs_extra = [] inputs_extra = []
bip32_derivations = {}
for i, inp in enumerate(data.inputs): for i, inp in enumerate(data.inputs):
bip32_derivations = {}
descriptor = descriptors[inp.masterpub_fingerprint][0] descriptor = descriptors[inp.masterpub_fingerprint][0]
d = descriptor.derive(inp.address_index, inp.branch_index) d = descriptor.derive(inp.address_index, inp.branch_index)
for k in d.keys: for k in d.keys:
@ -291,6 +292,7 @@ async def api_psbt_extract_tx(
if not final_psbt: if not final_psbt:
raise ValueError("PSBT cannot be finalized!") raise ValueError("PSBT cannot be finalized!")
res.tx_hex = final_psbt.to_string() res.tx_hex = final_psbt.to_string()
print('### hex', res.tx_hex)
transaction = Transaction.from_string(res.tx_hex) transaction = Transaction.from_string(res.tx_hex)
tx = { tx = {