fix: psbt generation

This commit is contained in:
Vlad Stan 2022-07-26 18:40:35 +03:00
parent b0216bff75
commit 4e9cfc0f74
4 changed files with 53 additions and 40 deletions

View file

@ -1,6 +1,5 @@
<div> <div>
<q-form @submit="createPsbt" class="q-gutter-md"> <q-form @submit="checkAndSend" class="q-gutter-md">
<!-- {{addresses}} -->
<q-tabs v-model="paymentTab" no-caps class="bg-dark text-white shadow-2"> <q-tabs v-model="paymentTab" no-caps class="bg-dark text-white shadow-2">
<q-tab name="destination" label="Send To"></q-tab> <q-tab name="destination" label="Send To"></q-tab>
<q-tab name="coinControl" label="Coin Select"></q-tab> <q-tab name="coinControl" label="Coin Select"></q-tab>
@ -17,7 +16,6 @@
:sats-denominated="sats_denominated" :sats-denominated="sats_denominated"
@update:outputs="handleOutputsChange" @update:outputs="handleOutputsChange"
></send-to> ></send-to>
</q-card-section> </q-card-section>
</q-card> </q-card>
@ -178,11 +176,13 @@
<q-btn <q-btn
unelevated unelevated
:disabled="changeAmount < 0" :disabled="changeAmount < 0"
label="Check & Send"
color="green" color="green"
type="submit" type="submit"
class="btn-full" class="btn-full"
>Check & Send</q-btn
> >
<q-spinner v-if="showChecking" color="primary"></q-spinner
></q-btn>
</div> </div>
<div class="col-9"> <div class="col-9">
<q-badge <q-badge

View file

@ -9,7 +9,8 @@ async function payment(path) {
'addresses', 'addresses',
'utxos', 'utxos',
'mempool_endpoint', 'mempool_endpoint',
'sats_denominated' 'sats_denominated',
'adminkey'
], ],
watch: { watch: {
immediate: true, immediate: true,
@ -24,12 +25,15 @@ async function payment(path) {
data: function () { data: function () {
return { return {
DUST_LIMIT: 546, DUST_LIMIT: 546,
tx: null,
psbtBase64: null,
paymentTab: 'destination', paymentTab: 'destination',
sendToList: [{address: '', amount: undefined}], sendToList: [{address: '', amount: undefined}],
changeWallet: null, changeWallet: null,
changeAddress: {}, changeAddress: {},
showCustomFee: false, showCustomFee: false,
showCoinSelect: false, showCoinSelect: false,
showChecking: false,
showChange: false, showChange: false,
feeRate: 1 feeRate: 1
} }
@ -71,25 +75,35 @@ async function payment(path) {
satBtc(val, showUnit = true) { satBtc(val, showUnit = true) {
return satOrBtc(val, showUnit, this['sats_denominated']) return satOrBtc(val, showUnit, this['sats_denominated'])
}, },
createPsbt: async function () { checkAndSend: async function () {
const wallet = this.g.user.wallets[0]
try { try {
// this.computeFee(this.feeRate) console.log('### this.checkAndSend')
const tx = this.createTx() this.showChecking = true
// txSize(tx) await this.createPsbt()
for (const input of tx.inputs) { } catch (error) {
} finally {
this.showChecking = false
}
},
createPsbt: async function () {
try {
console.log('### this.createPsbt')
this.tx = this.createTx()
for (const input of this.tx.inputs) {
input.tx_hex = await this.fetchTxHex(input.tx_id) input.tx_hex = await this.fetchTxHex(input.tx_id)
} }
this.payment.tx = tx const changeOutput = this.tx.outputs.find(o => o.branch_index === 1)
if (changeOutput) changeOutput.amount = this.changeAmount
const {data} = await LNbits.api.request( const {data} = await LNbits.api.request(
'POST', 'POST',
'/watchonly/api/v1/psbt', '/watchonly/api/v1/psbt',
wallet.adminkey, this.adminkey,
tx this.tx
) )
this.payment.psbtBase64 = data this.psbtBase64 = data
} catch (err) { } catch (err) {
LNbits.utils.notifyApiError(err) LNbits.utils.notifyApiError(err)
} }
@ -97,7 +111,6 @@ async function payment(path) {
createTx: function (excludeChange = false) { createTx: function (excludeChange = false) {
const tx = { const tx = {
fee_rate: this.feeRate, fee_rate: this.feeRate,
// tx_size: this.payment.txSize, ???
masterpubs: this.accounts.map(w => ({ masterpubs: this.accounts.map(w => ({
public_key: w.masterpub, public_key: w.masterpub,
fingerprint: w.fingerprint fingerprint: w.fingerprint
@ -121,10 +134,9 @@ async function payment(path) {
tx.outputs.push(change) tx.outputs.push(change)
} }
} }
// Only sort by amount on UI level (no lib for address decode) tx.tx_size = Math.round(txSize(tx))
// Should sort by scriptPubKey (as byte array) on the backend tx.inputs = _.shuffle(tx.inputs)
// todo: just shuffle tx.outputs = _.shuffle(tx.outputs)
tx.outputs.sort((a, b) => a.amount - b.amount)
return tx return tx
}, },
@ -135,8 +147,8 @@ async function payment(path) {
return { return {
address: change.address, address: change.address,
addressIndex: change.addressIndex, address_index: change.addressIndex,
addressIndex: change.addressIndex, branch_index: change.isChange ? 1 : 0,
masterpub_fingerprint: walletAcount.fingerprint masterpub_fingerprint: walletAcount.fingerprint
} }
}, },
@ -161,6 +173,24 @@ async function payment(path) {
} }
this.selectChangeAddress(this.changeWallet) this.selectChangeAddress(this.changeWallet)
}, },
fetchTxHex: async function (txId) {
const {
bitcoin: {transactions: transactionsAPI}
} = mempoolJS() // todo: hostname
try {
const response = await transactionsAPI.getTxHex({txid: txId})
return response
} catch (error) {
this.$q.notify({
type: 'warning',
message: `Failed to fetch transaction details for tx id: '${txId}'`,
timeout: 10000
})
LNbits.utils.notifyApiError(error)
throw error
}
},
handleOutputsChange: function () { handleOutputsChange: function () {
this.$refs.utxoList.refreshUtxoSelection(this.totalPayedAmount) this.$refs.utxoList.refreshUtxoSelection(this.totalPayedAmount)
}, },

View file

@ -784,24 +784,6 @@ const watchOnly = async () => {
}) })
return retryWithDelay(fn) return retryWithDelay(fn)
}, },
fetchTxHex: async function (txId) {
const {
bitcoin: {transactions: transactionsAPI}
} = mempoolJS()
try {
const response = await transactionsAPI.getTxHex({txid: txId})
return response
} catch (error) {
this.$q.notify({
type: 'warning',
message: `Failed to fetch transaction details for tx id: '${txId}'`,
timeout: 10000
})
LNbits.utils.notifyApiError(error)
throw error
}
},
//################### OTHER ################### //################### OTHER ###################

View file

@ -498,6 +498,7 @@
:accounts="walletAccounts" :accounts="walletAccounts"
:addresses="addresses" :addresses="addresses"
:utxos="utxos.data" :utxos="utxos.data"
:adminkey="g.user.wallets[0].adminkey"
></payment> ></payment>
<!-- todo: no more utxos.data --> <!-- todo: no more utxos.data -->
</q-card-section> </q-card-section>