feature and bug fixes
-- added option to allow unconfirmed UTXOs while creating transaction
This commit is contained in:
parent
dc0e199d58
commit
ba549b787f
17
css/main.css
17
css/main.css
@ -929,7 +929,15 @@ ol li::before {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
.transaction .pending-badge {
|
||||
.transaction__amount {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.transaction__id {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.pending-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
@ -938,13 +946,6 @@ ol li::before {
|
||||
font-weight: 500;
|
||||
justify-self: flex-start;
|
||||
}
|
||||
.transaction__amount {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.transaction__id {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tx-participant:not(:last-of-type) {
|
||||
margin-right: 0.5rem;
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -868,15 +868,6 @@ ol {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
.pending-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--yellow);
|
||||
color: rgba(0 0 0/ 0.8);
|
||||
font-weight: 500;
|
||||
justify-self: flex-start;
|
||||
}
|
||||
&__amount {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
@ -885,6 +876,15 @@ ol {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
.pending-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--yellow);
|
||||
color: rgba(0 0 0/ 0.8);
|
||||
font-weight: 500;
|
||||
justify-self: flex-start;
|
||||
}
|
||||
.tx-participant {
|
||||
&:not(:last-of-type) {
|
||||
&::after {
|
||||
|
||||
47
index.html
47
index.html
@ -957,13 +957,16 @@
|
||||
|
||||
function buttonLoader(id, show) {
|
||||
const button = typeof id === 'string' ? document.getElementById(id) : id;
|
||||
button.disabled = show;
|
||||
if (!button) return
|
||||
if (!button.dataset.hasOwnProperty('wasDisabled'))
|
||||
button.dataset.wasDisabled = button.disabled
|
||||
const animOptions = {
|
||||
duration: 200,
|
||||
fill: 'both',
|
||||
fill: 'forwards',
|
||||
easing: 'ease'
|
||||
}
|
||||
if (show) {
|
||||
button.disabled = true
|
||||
button.parentNode.append(document.createElement('sm-spinner'))
|
||||
button.animate([
|
||||
{
|
||||
@ -974,11 +977,22 @@
|
||||
},
|
||||
], animOptions)
|
||||
} else {
|
||||
button.getAnimations().forEach(anim => anim.cancel())
|
||||
button.disabled = button.dataset.wasDisabled === 'true';
|
||||
button.animate([
|
||||
{
|
||||
clipPath: 'circle(0)',
|
||||
},
|
||||
{
|
||||
clipPath: 'circle(100%)',
|
||||
},
|
||||
], animOptions).onfinish = (e) => {
|
||||
button.removeAttribute('data-original-state')
|
||||
}
|
||||
const potentialTarget = button.parentNode.querySelector('sm-spinner')
|
||||
if (potentialTarget) potentialTarget.remove();
|
||||
}
|
||||
}
|
||||
|
||||
let isMobileView = false
|
||||
const mobileQuery = window.matchMedia('(max-width: 40rem)')
|
||||
function handleMobileChange(e) {
|
||||
@ -1166,7 +1180,7 @@
|
||||
const queriedAddress = pagesData.params?.query || getRef('search_query_input').value.trim()
|
||||
const isSender = type === 'out' || type === 'self'
|
||||
const className = `transaction grid ${type} ${block === null ? 'unconfirmed-tx' : ''}`
|
||||
return html.node`
|
||||
return html.node/*html*/`
|
||||
<li class="${className}" data-txid="${txid}" data-transacting-addresses=${transactingAddresses.slice(2)}>
|
||||
<div class="transaction__icon">${icon}</div>
|
||||
<div class="grid gap-0-5">
|
||||
@ -1185,7 +1199,7 @@
|
||||
</a>
|
||||
${isSender && !block ? html`
|
||||
<div class="multi-state-button">
|
||||
<button class="button button--small gap-0-3" onclick=${initFeeChange} title="Resend transaction with greater fees to reduce confirmation time">
|
||||
<button class="button button--small gap-0-3" onclick=${(e) => initFeeChange(e, txid)} title="Resend transaction with greater fees to reduce confirmation time">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>
|
||||
Increase fee
|
||||
</button>
|
||||
@ -1261,6 +1275,22 @@
|
||||
Unconfirmed
|
||||
</h4> ` : ''}
|
||||
</div>
|
||||
${!block ? html`
|
||||
<div class="flex flex-direction-column gap-0-5" style="padding: 1rem;border-radius:0.5rem; border: solid thin rgba(var(--text-color),0.3); background-color: rgba(var(--text-color),0.02)">
|
||||
<h3>
|
||||
Taking too long to confirm?
|
||||
</h3>
|
||||
<p>
|
||||
You can increase the fee to speed up confirmation.
|
||||
</p>
|
||||
<div class="multi-state-button margin-right-auto">
|
||||
<button class="button gap-0-3 button--primary" onclick=${e => initFeeChange(e, txid)} title="Resend transaction with greater fees to reduce confirmation time">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>
|
||||
Increase fee
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
<div id="tx_technicals" class="justify-self-center details-wrapper">
|
||||
<div class="tx-detail">
|
||||
<div class="flex align-center gap-0-3">
|
||||
@ -1988,10 +2018,9 @@
|
||||
}
|
||||
|
||||
let changingFeeOf = null
|
||||
async function initFeeChange(e) {
|
||||
async function initFeeChange(e, txid) {
|
||||
const button = e.target.closest('button')
|
||||
buttonLoader(button, true)
|
||||
const txid = button.closest('li').dataset.txid
|
||||
changingFeeOf = txid
|
||||
try {
|
||||
const { inputs, outputs, fee: previousFee } = await btcOperator.getTx(txid)
|
||||
@ -2020,7 +2049,7 @@
|
||||
const amounts = outputs.map(output => 0.00000005)
|
||||
let recommendedFee = null
|
||||
if (!isMultisig) {
|
||||
const { fee } = await btcOperator.createTx(senders, receivers, amounts)
|
||||
const { fee } = await btcOperator.createTx(senders, receivers, amounts, null, { allowUnconfirmedUtxos: true })
|
||||
if (fee > previousFee)
|
||||
recommendedFee = fee
|
||||
}
|
||||
@ -2076,7 +2105,7 @@
|
||||
document.getElementById('new_fee').querySelector('.currency-symbol').innerHTML = currencyIcons[selectedCurrency]
|
||||
openPopup('increase_fee_popup')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
notify(e, 'error')
|
||||
} finally {
|
||||
buttonLoader(button, false)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
(function (EXPORTS) { //btcOperator v1.1.3d
|
||||
(function (EXPORTS) { //btcOperator v1.1.4
|
||||
/* BTC Crypto and API Operator */
|
||||
const btcOperator = EXPORTS;
|
||||
|
||||
@ -400,12 +400,12 @@
|
||||
}
|
||||
btcOperator.validateTxParameters = validateTxParameters;
|
||||
|
||||
function createTransaction(senders, redeemScripts, receivers, amounts, fee, change_address, fee_from_receiver) {
|
||||
function createTransaction(senders, redeemScripts, receivers, amounts, fee, change_address, fee_from_receiver, allowUnconfirmedUtxos = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let total_amount = parseFloat(amounts.reduce((t, a) => t + a, 0).toFixed(8));
|
||||
const tx = coinjs.transaction();
|
||||
let output_size = addOutputs(tx, receivers, amounts, change_address);
|
||||
addInputs(tx, senders, redeemScripts, total_amount, fee, output_size, fee_from_receiver).then(result => {
|
||||
addInputs(tx, senders, redeemScripts, total_amount, fee, output_size, fee_from_receiver, allowUnconfirmedUtxos).then(result => {
|
||||
if (result.change_amount > 0 && result.change_amount > result.fee) //add change amount if any (ignore dust change)
|
||||
tx.outs[tx.outs.length - 1].value = util.BTC_to_Sat(result.change_amount); //values are in satoshi
|
||||
if (fee_from_receiver) { //deduce fee from receivers if fee_from_receiver
|
||||
@ -439,10 +439,10 @@
|
||||
}
|
||||
btcOperator.createTransaction = createTransaction;
|
||||
|
||||
function addInputs(tx, senders, redeemScripts, total_amount, fee, output_size, fee_from_receiver) {
|
||||
function addInputs(tx, senders, redeemScripts, total_amount, fee, output_size, fee_from_receiver, allowUnconfirmedUtxos = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (fee !== null) {
|
||||
addUTXOs(tx, senders, redeemScripts, fee_from_receiver ? total_amount : total_amount + fee, false).then(result => {
|
||||
addUTXOs(tx, senders, redeemScripts, fee_from_receiver ? total_amount : total_amount + fee, false, { allowUnconfirmedUtxos }).then(result => {
|
||||
result.fee = fee;
|
||||
resolve(result);
|
||||
}).catch(error => reject(error))
|
||||
@ -451,8 +451,8 @@
|
||||
let net_fee = BASE_TX_SIZE * fee_rate;
|
||||
net_fee += (output_size * fee_rate);
|
||||
(fee_from_receiver ?
|
||||
addUTXOs(tx, senders, redeemScripts, total_amount, false) :
|
||||
addUTXOs(tx, senders, redeemScripts, total_amount + net_fee, fee_rate)
|
||||
addUTXOs(tx, senders, redeemScripts, total_amount, false, { allowUnconfirmedUtxos }) :
|
||||
addUTXOs(tx, senders, redeemScripts, total_amount + net_fee, fee_rate, { allowUnconfirmedUtxos })
|
||||
).then(result => {
|
||||
result.fee = parseFloat((net_fee + (result.input_size * fee_rate)).toFixed(8));
|
||||
result.fee_rate = fee_rate;
|
||||
@ -464,7 +464,7 @@
|
||||
}
|
||||
btcOperator.addInputs = addInputs;
|
||||
|
||||
function addUTXOs(tx, senders, redeemScripts, required_amount, fee_rate, rec_args = {}) {
|
||||
function addUTXOs(tx, senders, redeemScripts, required_amount, fee_rate, rec_args = { allowUnconfirmedUtxos: false }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
required_amount = parseFloat(required_amount.toFixed(8));
|
||||
if (typeof rec_args.n === "undefined") {
|
||||
@ -478,8 +478,9 @@
|
||||
input_amount: rec_args.input_amount,
|
||||
change_amount: required_amount * -1 //required_amount will be -ve of change_amount
|
||||
});
|
||||
else if (rec_args.n >= senders.length)
|
||||
else if (rec_args.n >= senders.length) {
|
||||
return reject("Insufficient Balance");
|
||||
}
|
||||
let addr = senders[rec_args.n],
|
||||
rs = redeemScripts[rec_args.n];
|
||||
let addr_type = coinjs.addressDecode(addr).type;
|
||||
@ -488,7 +489,9 @@
|
||||
let utxos = result.unspent_outputs;
|
||||
//console.debug("add-utxo", addr, rs, required_amount, utxos);
|
||||
for (let i = 0; i < utxos.length && required_amount > 0; i++) {
|
||||
if (!utxos[i].confirmations) //ignore unconfirmed utxo
|
||||
if (utxos.length === 1 && rec_args.allowUnconfirmedUtxos) {
|
||||
console.log('allowing unconfirmed utxos')
|
||||
} else if (!utxos[i].confirmations) //ignore unconfirmed utxo
|
||||
continue;
|
||||
var script;
|
||||
if (!rs || !rs.length) //legacy script
|
||||
@ -838,7 +841,9 @@
|
||||
})
|
||||
}
|
||||
|
||||
btcOperator.createTx = function (senders, receivers, amounts, fee = null, options = {}) {
|
||||
btcOperator.createTx = function (senders, receivers, amounts, fee = null, options = {
|
||||
allowUnconfirmedUtxos: false
|
||||
}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
({
|
||||
@ -859,7 +864,7 @@
|
||||
if (redeemScripts.includes(null)) //TODO: segwit
|
||||
return reject("Unable to get redeem-script");
|
||||
//create transaction
|
||||
createTransaction(senders, redeemScripts, receivers, amounts, fee, options.change_address || senders[0], options.fee_from_receiver).then(result => {
|
||||
createTransaction(senders, redeemScripts, receivers, amounts, fee, options.change_address || senders[0], options.fee_from_receiver, options.allowUnconfirmedUtxos).then(result => {
|
||||
result.tx_hex = result.transaction.serialize();
|
||||
delete result.transaction;
|
||||
resolve(result);
|
||||
|
||||
2
scripts/btcOperator.min.js
vendored
2
scripts/btcOperator.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user