feature and bug fixes

-- added option to allow unconfirmed UTXOs while creating transaction
This commit is contained in:
sairaj mote 2023-12-01 20:55:24 +05:30
parent dc0e199d58
commit ba549b787f
6 changed files with 75 additions and 40 deletions

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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 {

View File

@ -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)
}

View File

@ -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);

File diff suppressed because one or more lines are too long