feat: partial payment redesign

This commit is contained in:
Vlad Stan 2022-07-25 19:37:16 +03:00
parent 799fb99661
commit e98e3504ad
6 changed files with 164 additions and 104 deletions

View File

@ -0,0 +1,63 @@
<div>
<div class="row items-center no-wrap q-mb-md">
<div class="col-2 q-pr-lg">Fee Rate:</div>
<div class="col-3 q-pr-lg">
<q-input
filled
dense
v-model.number="feeRate"
:rules="[val => !!val || 'Field is required']"
type="number"
label="sats/vbyte"
@input="feeRateChanged"
></q-input>
</div>
<div class="col-7">
<q-slider
v-model="feeRate"
color="orange"
markers
snap
label
label-always
:label-value="getFeeRateLabel(feeRate)"
:min="1"
:max="recommededFees.fastestFee"
@input="feeRateChanged"
/>
</div>
</div>
<div
v-if="feeRate < recommededFees.hourFee || feeRate > recommededFees.fastestFee"
class="row items-center no-wrap q-mb-md"
>
<div class="col-2 q-pr-lg"></div>
<div class="col-10 q-pr-lg">
<q-badge v-if="feeRate < recommededFees.hourFee" color="pink" size="lg">
Warning! The fee is too low. The transaction might take a long time to
confirm.
</q-badge>
<q-badge v-if="feeRate > recommededFees.fastestFee" color="pink">
Warning! The fee is too high. You might be overpaying for this
transaction.
</q-badge>
</div>
</div>
<div class="row items-center no-wrap q-mb-md">
<div class="col-2 q-pr-lg">Fee:</div>
<div class="col-3 q-pr-lg">{{totalfee}} sats</div>
<div class="col-7">
<q-btn
outline
dense
size="md"
icon="refresh"
color="grey"
class="float-right"
@click="refreshRecommendedFees()"
>Refresh Fee Rates</q-btn
>
</div>
</div>
</div>

View File

@ -0,0 +1,62 @@
async function fees(path) {
const template = await loadTemplateAsync(path)
Vue.component('fees', {
name: 'fees',
template,
props: ['totalfee', 'sats_denominated'],
watch: {
immediate: true,
'totalfee': function(newVal, oldVal) {
console.log('### ', newVal, oldVal)
}
},
data: function () {
return {
feeRate: 1,
recommededFees: {
fastestFee: 1,
halfHourFee: 1,
hourFee: 1,
economyFee: 1,
minimumFee: 1
}
}
},
methods: {
satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated'])
},
feeRateChanged: function (newFeeRate) {
console.log('### value', newFeeRate)
this.$emit('update:fee-rate', +newFeeRate)
},
refreshRecommendedFees: async function () {
const {
bitcoin: {fees: feesAPI}
} = mempoolJS()
const fn = async () => feesAPI.getFeesRecommended()
this.recommededFees = await retryWithDelay(fn)
},
getFeeRateLabel: function (feeRate) {
const fees = this.recommededFees
if (feeRate >= fees.fastestFee)
return `High Priority (${feeRate} sat/vB)`
if (feeRate >= fees.halfHourFee)
return `Medium Priority (${feeRate} sat/vB)`
if (feeRate >= fees.hourFee) return `Low Priority (${feeRate} sat/vB)`
return `No Priority (${feeRate} sat/vB)`
}
},
created: async function () {
console.log('### created fees ')
await this.refreshRecommendedFees()
this.feeRate = this.recommededFees.halfHourFee
this.feeRateChanged(this.recommededFees.halfHourFee)
}
})
}

View File

@ -80,8 +80,10 @@ async function utxoList(path) {
},
computed: {
columns: function() {
return this.utxosTable.columns.filter(c => c.selectable ? this.selectable : true)
columns: function () {
return this.utxosTable.columns.filter(c =>
c.selectable ? this.selectable : true
)
}
},

View File

@ -6,6 +6,7 @@ const watchOnly = async () => {
await addressList('static/components/address-list/address-list.html')
await history('static/components/history/history.html')
await utxoList('static/components/utxo-list/utxo-list.html')
await fees('static/components/fees/fees.html')
await payment('static/components/payment/payment.html')
Vue.filter('reverse', function (value) {
@ -82,7 +83,9 @@ const watchOnly = async () => {
showAddress: false,
addressNote: '',
showPayment: false
showPayment: false,
showCustomFee: false,
feeValue: 0
}
},
@ -238,10 +241,10 @@ const watchOnly = async () => {
masterpub_fingerprint: walletAcount.fingerprint
}
},
computeFee: function () {
computeFee: function (feeRate) {
const tx = this.createTx()
this.payment.txSize = Math.round(txSize(tx))
return this.payment.feeRate * this.payment.txSize
return feeRate * this.payment.txSize
},
deletePaymentAddress: function (v) {
const index = this.payment.data.indexOf(v)
@ -257,18 +260,9 @@ const watchOnly = async () => {
this.payment.changeWallet = this.walletAccounts[0]
this.selectChangeAddress(this.payment.changeWallet)
await this.refreshRecommendedFees()
this.payment.feeRate = this.payment.recommededFees.halfHourFee
},
getFeeRateLabel: function (feeRate) {
const fees = this.payment.recommededFees
if (feeRate >= fees.fastestFee)
return `High Priority (${feeRate} sat/vB)`
if (feeRate >= fees.halfHourFee)
return `Medium Priority (${feeRate} sat/vB)`
if (feeRate >= fees.hourFee) return `Low Priority (${feeRate} sat/vB)`
return `No Priority (${feeRate} sat/vB)`
},
addPaymentAddress: function () {
this.payment.data.push({address: '', amount: undefined})
},
@ -300,7 +294,7 @@ const watchOnly = async () => {
createPsbt: async function () {
const wallet = this.g.user.wallets[0]
try {
this.computeFee()
this.computeFee(this.payment.feeRate)
const tx = this.createTx()
txSize(tx)
for (const input of tx.inputs) {
@ -824,7 +818,6 @@ const watchOnly = async () => {
h => h.address !== addrData.address
)
console.log('### addressHistory', addressHistory)
// add new entries
this.history.push(...addressHistory)
this.history.sort((a, b) => (!a.height ? -1 : b.height - a.height))
@ -899,14 +892,6 @@ const watchOnly = async () => {
return this.addressHistoryFromTxs(addrData, addressTxs)
},
refreshRecommendedFees: async function () {
const {
bitcoin: {fees: feesAPI}
} = mempoolJS()
const fn = async () => feesAPI.getFeesRecommended()
this.payment.recommededFees = await retryWithDelay(fn)
},
getAddressTxsUtxoDelayed: async function (address) {
const {
bitcoin: {addresses: addressesAPI}
@ -974,6 +959,10 @@ const watchOnly = async () => {
handleAddressesUpdated: async function (addresses) {
this.addresses = addresses
await this.scanAddressWithAmount()
},
handleFeeRateChanged: function (newFeeRate) {
console.log('### newFeeRate', newFeeRate)
this.feeValue = this.computeFee(newFeeRate)
}
},
created: async function () {

View File

@ -48,14 +48,6 @@ const tableData = {
changeAddress: {},
changeAmount: 0,
feeRate: 1,
recommededFees: {
fastestFee: 1,
halfHourFee: 1,
hourFee: 1,
economyFee: 1,
minimumFee: 1
},
fee: 0,
txSize: 0,
tx: null,

View File

@ -500,7 +500,6 @@
class="bg-dark text-white shadow-2"
>
<q-tab name="destination" label="Send To"></q-tab>
<q-tab name="fees" label="Fees"></q-tab>
<q-tab name="coinControl" label="Coin Control"></q-tab>
</q-tabs>
<q-tab-panels v-model="paymentTab">
@ -596,6 +595,7 @@
</q-table>
</div>
</div>
<!-- <div class="row items-center no-wrap q-mb-md">
<div class="col-12">
<q-table
@ -660,78 +660,29 @@
-->
</q-card-section>
</q-card>
<div class="row items-center no-wrap q-mb-md q-pt-lg">
<div class="col-12">
<q-toggle
label="Custom Fee"
color="secodary"
v-model="showCustomFee"
></q-toggle>
</div>
</div>
<q-card v-show="showCustomFee">
<q-card-section>
<div class="row items-center no-wrap q-mb-md q-pt-md">
<div class="col-12">
<fees
:totalfee="feeValue"
@update:fee-rate="handleFeeRateChanged"
></fees>
</div>
</div>
</q-card-section>
</q-card>
</q-tab-panel>
<q-tab-panel name="fees">
<q-card
><q-card-section>
<div class="row items-center no-wrap q-mb-md">
<div class="col-2 q-pr-lg">Fee Rate:</div>
<div class="col-3 q-pr-lg">
<q-input
filled
dense
v-model.number="payment.feeRate"
:rules="[val => !!val || 'Field is required']"
type="number"
label="sats/vbyte"
></q-input>
</div>
<div class="col-7">
<q-slider
v-model="payment.feeRate"
color="orange"
markers
snap
label
label-always
:label-value="getFeeRateLabel(payment.feeRate)"
:min="1"
:max="payment.recommededFees.fastestFee"
/>
</div>
</div>
<div
v-if="payment.feeRate < payment.recommededFees.hourFee || payment.feeRate > payment.recommededFees.fastestFee"
class="row items-center no-wrap q-mb-md"
>
<div class="col-2 q-pr-lg"></div>
<div class="col-10 q-pr-lg">
<q-badge
v-if="payment.feeRate < payment.recommededFees.hourFee"
color="pink"
size="lg"
>
Warning! The fee is too low. The transaction might take
a long time to confirm.
</q-badge>
<q-badge
v-if="payment.feeRate > payment.recommededFees.fastestFee"
color="pink"
>
Warning! The fee is too high. You might be overpaying
for this transaction.
</q-badge>
</div>
</div>
<div class="row items-center no-wrap q-mb-md">
<div class="col-2 q-pr-lg">Fee:</div>
<div class="col-3 q-pr-lg">{{computeFee()}} sats</div>
<div class="col-7 q-pr-lg">
<q-btn
outline
dense
size="md"
icon="refresh"
color="grey"
@click="refreshRecommendedFees()"
>Refresh Fee Rates</q-btn
>
</div>
</div>
</q-card-section></q-card
>
</q-tab-panel>
<q-tab-panel name="coinControl">
<utxo-list
:utxos="utxos.data"
@ -998,6 +949,7 @@
<script src="{{ url_for('watchonly_static', path='components/address-list/address-list.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/history/history.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/utxo-list/utxo-list.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/fees/fees.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/payment/payment.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='js/index.js') }}"></script>
{% endblock %}