Added auto fee calculation

This commit is contained in:
sairaj mote 2023-10-23 19:36:09 +05:30
parent 062c48af1b
commit 354abe7cd6
8 changed files with 4928 additions and 4759 deletions

View File

@ -237,7 +237,7 @@ sm-input {
} }
sm-spinner { sm-spinner {
--size: 1.5rem; --size: 1.3rem;
--stroke-width: 0.1rem; --stroke-width: 0.1rem;
} }
@ -617,6 +617,7 @@ ul {
text-align: center; text-align: center;
align-items: center; align-items: center;
justify-items: center; justify-items: center;
isolation: isolate;
} }
.multi-state-button > * { .multi-state-button > * {
grid-area: 1/1/2/2; grid-area: 1/1/2/2;

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -217,7 +217,7 @@ sm-input {
} }
sm-spinner { sm-spinner {
--size: 1.5rem; --size: 1.3rem;
--stroke-width: 0.1rem; --stroke-width: 0.1rem;
} }
@ -576,6 +576,7 @@ ul {
text-align: center; text-align: center;
align-items: center; align-items: center;
justify-items: center; justify-items: center;
isolation: isolate;
& > * { & > * {
grid-area: 1/1/2/2; grid-area: 1/1/2/2;
} }

View File

@ -53,7 +53,7 @@
<div class="nav-item__indicator"></div> <div class="nav-item__indicator"></div>
</a> </a>
</li> </li>
<li> <li class="hidden">
<a href="#/convert" class="nav-item interactive"> <a href="#/convert" class="nav-item interactive">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000"> width="24px" fill="#000000">
@ -62,7 +62,8 @@
</svg> </svg>
<span class="nav-item__title"> <span class="nav-item__title">
Convert Convert
</span></a> </span>
</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -569,6 +570,60 @@
} }
} }
} }
let currentSubscriber = null;
/**
* @param {any} initialValue - initial value for the signal
* @param {function} [Optional] callback - function to be called when the signal changes
* @returns {array} - array containing getter and setter for the signal
* @example
* const [getCount, setCount] = $signal(0);
*/
function $signal(initialValue, callback) {
let value = initialValue;
const subscribers = new Set();
let hasCustomSubscriber = false;
function getter(subscriber) {
if (currentSubscriber) {
subscribers.add(currentSubscriber);
}
if (!hasCustomSubscriber && subscriber) {
subscribers.add(subscriber)
hasCustomSubscriber = true
}
return value;
}
function setter(newValue) {
if (newValue === value) return;
value = newValue;
for (const subscriber of subscribers) {
subscriber();
}
}
return [getter, setter];
}
/**
*
* @param {function} fn - function that will run if any of its dependent signals change
* @example
* $effect(() => {
* console.log(count());
* }
* @returns {void}
*/
async function $effect(fn) {
currentSubscriber = fn;
const result = fn();
try {
if (result instanceof Promise) {
await result;
}
} catch (e) {
console.error(e)
} finally {
currentSubscriber = null;
}
}
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
window.smCompConfig = { window.smCompConfig = {
@ -576,7 +631,7 @@
{ {
selector: '[data-btc-address]', selector: '[data-btc-address]',
customValidation: (value) => { customValidation: (value) => {
if (!value) return { isValid: false, errorText: 'Please enter a FLO address' } if (!value) return { isValid: false, errorText: 'Please enter a BTC address' }
return { return {
isValid: btcOperator.validateAddress(value), isValid: btcOperator.validateAddress(value),
errorText: `Invalid address.<br> It usually starts with "1", "3" or "bc1"` errorText: `Invalid address.<br> It usually starts with "1", "3" or "bc1"`
@ -631,8 +686,31 @@
renderHome(state) renderHome(state)
}) })
router.addRoute('home', renderHome) router.addRoute('home', renderHome)
const [suggestedFee, setSuggestedFee] = $signal(0);
const [suggestedFeeStatus, setSuggestedFeeStatus] = $signal(['idle'])
const [feeType, setFeeType] = $signal('suggested')
function renderHome(state) { function renderHome(state) {
console.log(state) $effect(() => {
let feeSection = ''
if (feeType() === 'suggested') {
const [status, message] = suggestedFeeStatus()
if (status === 'idle') {
feeSection = html` <p>*Fee will be calculated after you enter all the details</p> `
} else if (status === 'calculating') {
feeSection = html`<div class="flex align-center"> Calculating fee...<sm-spinner></sm-spinner> </div>`
} else if (status === 'error') {
feeSection = html`<p class="error">${message}</p>`
} else if (status === 'success') {
feeSection = html`
<sm-input id="fee_input" placeholder="Suggested fee" type="number" value=${suggestedFee()} step="0.00000001" min="0.0000001" readonly animate required></sm-input>
`
}
} else {
feeSection = html`
<sm-input id="fee_input" placeholder="Custom fee" type="number" step="0.00000001" min="0.0000001" error-text="Minimum fee is 0.0000001BTC" animate required>
</sm-input>
`
}
renderElem(getRef('page_container'), html` renderElem(getRef('page_container'), html`
<div class="flex flex-direction-column gap-1-5"> <div class="flex flex-direction-column gap-1-5">
<menu class="flex gap-0-5"> <menu class="flex gap-0-5">
@ -652,7 +730,7 @@
<h3> <h3>
Perform Transaction Perform Transaction
</h3> </h3>
<sm-form> <sm-form id="send_tx_form" onvalid=${calculateSuggestedFee} oninvalid=${handleInvalidForm} ?skip-submit=${feeType() === 'suggested'}>
<div class="flex flex-direction-column gap-0-5"> <div class="flex flex-direction-column gap-0-5">
<div class="flex space-between align-center"> <div class="flex space-between align-center">
<h4>Sender</h4> <h4>Sender</h4>
@ -660,7 +738,7 @@
Check balance Check balance
</button> </button>
</div> </div>
<sm-input id="private_key_input" placeholder="Sender's private key" data-private-key class="password-field" type="password" oninput=${handlePrivateKeyInput} required> <sm-input id="private_key_input" placeholder="Sender's private key" data-private-key class="password-field" type="password" oninput=${handlePrivateKeyInput} animate required>
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <g> <rect fill="none" height="24" width="24"></rect> </g> <g> <path d="M21,10h-8.35C11.83,7.67,9.61,6,7,6c-3.31,0-6,2.69-6,6s2.69,6,6,6c2.61,0,4.83-1.67,5.65-4H13l2,2l2-2l2,2l4-4.04L21,10z M7,15c-1.65,0-3-1.35-3-3c0-1.65,1.35-3,3-3s3,1.35,3,3C10,13.65,8.65,15,7,15z"> </path> </g> </svg> <svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <g> <rect fill="none" height="24" width="24"></rect> </g> <g> <path d="M21,10h-8.35C11.83,7.67,9.61,6,7,6c-3.31,0-6,2.69-6,6s2.69,6,6,6c2.61,0,4.83-1.67,5.65-4H13l2,2l2-2l2,2l4-4.04L21,10z M7,15c-1.65,0-3-1.35-3-3c0-1.65,1.35-3,3-3s3,1.35,3,3C10,13.65,8.65,15,7,15z"> </path> </g> </svg>
<label slot="right" class="interact"> <label slot="right" class="interact">
<input type="checkbox" class="hidden" autocomplete="off" readonly="" onchange="togglePrivateKeyVisibility(this)"> <input type="checkbox" class="hidden" autocomplete="off" readonly="" onchange="togglePrivateKeyVisibility(this)">
@ -675,8 +753,8 @@
<h4>Receiver</h4> <h4>Receiver</h4>
<ul id="receivers_container" class="grid gap-1"> <ul id="receivers_container" class="grid gap-1">
<li class="grid gap-0-5 receiver-wrapper"> <li class="grid gap-0-5 receiver-wrapper">
<sm-input class="receiver-address" placeholder="Receiver's address" data-btc-address required></sm-input> <sm-input class="receiver-address" placeholder="Receiver's address" data-btc-address animate required></sm-input>
<sm-input class="receiver-amount" placeholder="Amount" type="number" step="0.00000001" min="0.0000001" error-text="Amount should be grater than 0.0000001 BTC" required> <sm-input class="receiver-amount" placeholder="Amount" type="number" step="0.00000001" min="0.0000001" error-text="Amount should be grater than 0.0000001 BTC" animate required>
<div class="currency-symbol flex" slot="icon"> <div class="currency-symbol flex" slot="icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <g> <rect fill="none" height="24" width="24"></rect> </g> <g> <path d="M17.06,11.57C17.65,10.88,18,9.98,18,9c0-1.86-1.27-3.43-3-3.87L15,3h-2v2h-2V3H9v2H6v2h2v10H6v2h3v2h2v-2h2v2h2v-2 c2.21,0,4-1.79,4-4C19,13.55,18.22,12.27,17.06,11.57z M10,7h4c1.1,0,2,0.9,2,2s-0.9,2-2,2h-4V7z M15,17h-5v-4h5c1.1,0,2,0.9,2,2 S16.1,17,15,17z"> </path> </g> </svg> <svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <g> <rect fill="none" height="24" width="24"></rect> </g> <g> <path d="M17.06,11.57C17.65,10.88,18,9.98,18,9c0-1.86-1.27-3.43-3-3.87L15,3h-2v2h-2V3H9v2H6v2h2v10H6v2h3v2h2v-2h2v2h2v-2 c2.21,0,4-1.79,4-4C19,13.55,18.22,12.27,17.06,11.57z M10,7h4c1.1,0,2,0.9,2,2s-0.9,2-2,2h-4V7z M15,17h-5v-4h5c1.1,0,2,0.9,2,2 S16.1,17,15,17z"> </path> </g> </svg>
</div> </div>
@ -687,7 +765,16 @@
Add receiver Add receiver
</button> </button>
</div> </div>
<sm-input id="fee_input" placeholder="Fee" required></sm-input> <div class="grid gap-0-5">
<div class="flex align-center space-between gap-1">
<h4>Fee</h4>
<sm-chips onchange=${e => { setFeeType(e.target.value); calculateSuggestedFee(); }}>
<sm-chip value="suggested" selected>Suggested</sm-chip>
<sm-chip value="custom">Custom</sm-chip>
</sm-chips>
</div>
${feeSection}
</div>
<div class="multi-state-button"> <div class="multi-state-button">
<button id="send_tx_button" class="button button--primary" type="submit" disabled onclick="sendTx()">Send</button> <button id="send_tx_button" class="button button--primary" type="submit" disabled onclick="sendTx()">Send</button>
</div> </div>
@ -695,6 +782,33 @@
</sm-form> </sm-form>
</div> </div>
`) `)
})
}
async function calculateSuggestedFee() {
try {
getRef('send_tx_button').disabled = true
if (feeType() === 'custom') {
} else {
if (!getRef('send_tx_form').isFormValid) return
const { senderPrivateKey, senderAddress, receivers, receiverAddresses, receiverAmounts } = getTransactionDetails()
if (!senderPrivateKey || !senderAddress || !receiverAddresses.length || !receiverAmounts.length)
return
setSuggestedFeeStatus(['calculating'])
const { fee } = await createTx(senderPrivateKey, receiverAddresses, receiverAmounts)
setSuggestedFee(fee)
setSuggestedFeeStatus(['success'])
getRef('send_tx_button').disabled = false
}
} catch (e) {
console.error(e)
setSuggestedFeeStatus(['error', e])
}
}
function handleInvalidForm() {
setSuggestedFee(0);
setSuggestedFeeStatus(['idle']);
getRef('send_tx_button').disabled = true
} }
router.addRoute('convert', (state) => { router.addRoute('convert', (state) => {
renderElem(getRef('page_container'), html` renderElem(getRef('page_container'), html`
@ -718,20 +832,25 @@
`) `)
const { tr: { address } } = getTaprootAddress(wif) const { tr: { address } } = getTaprootAddress(wif)
btcOperator.getBalance(address).then(balance => { btcOperator.getBalance(address).then(balance => {
console.log(balance)
renderElem(getRef('sender_balance_container'), html` renderElem(getRef('sender_balance_container'), html`
<div class="grid gap-1" style="padding: 1rem; border-radius: 0.5rem; border: solid thin rgba(var(--text-color),0.3)">
<div class="grid">
<p class="label">Sender address</p>
<sm-copy value=${address}><p>${address}<p></sm-copy>
</div>
<p>
Balance: <b>${formatAmount(balance)}</b> Balance: <b>${formatAmount(balance)}</b>
</p>
</div>
`) `)
}).catch(err => { }).catch(err => {
notify(e, 'error') notify(e, 'error')
}) })
} }
function handlePrivateKeyInput(e) { function handlePrivateKeyInput(e) {
getRef('check_balance_button').disabled = !e.target.isValid
if (!e.target.isValid) { if (!e.target.isValid) {
getRef('sender_balance_container').classList.add('hidden') getRef('sender_balance_container').classList.add('hidden')
getRef('check_balance_button').disabled = true
} else {
getRef('check_balance_button').disabled = false
} }
} }
getRef('convert_to_taproot_form').addEventListener('invalid', () => { getRef('convert_to_taproot_form').addEventListener('invalid', () => {
@ -758,7 +877,7 @@
}) })
} }
function addReceiver() { function addReceiver() {
getRef('receivers_container').append(html.node` getRef('receivers_container').append(html.node/*html*/`
<div class="grid gap-0-5 receiver-wrapper"> <div class="grid gap-0-5 receiver-wrapper">
<sm-input class="receiver-address" placeholder="Receiver's address" data-btc-address <sm-input class="receiver-address" placeholder="Receiver's address" data-btc-address
required></sm-input> required></sm-input>
@ -776,8 +895,11 @@
function removeReceiver(button) { function removeReceiver(button) {
button.closest('.receiver-wrapper').remove() button.closest('.receiver-wrapper').remove()
} }
async function sendTx() { function getTransactionDetails() {
const senderPrivateKey = getRef('private_key_input').value.trim(); const senderPrivateKey = getRef('private_key_input').value.trim();
const senderAddress = getTaprootAddress(senderPrivateKey).tr.address;
if (btcOperator.validateAddress(senderAddress) !== 'bech32m')
return notify('Sender address is not a Taproot address', 'error')
const receivers = [...getRef('receivers_container').children].reduce((receivers, receiver) => { const receivers = [...getRef('receivers_container').children].reduce((receivers, receiver) => {
const receiverAddress = receiver.querySelector('.receiver-address').value.trim() const receiverAddress = receiver.querySelector('.receiver-address').value.trim()
const amount = parseFloat(receiver.querySelector('.receiver-amount').value.trim()) const amount = parseFloat(receiver.querySelector('.receiver-amount').value.trim())
@ -786,19 +908,22 @@
receivers[receiverAddress] += amount receivers[receiverAddress] += amount
return receivers return receivers
}, {}) }, {})
console.log(receivers, Object.keys(receivers), Object.values(receivers)) const receiverAddresses = Object.keys(receivers)
const fee = parseFloat(getRef('fee_input').value.trim()) const receiverAmounts = Object.values(receivers)
const senderAddress = getTaprootAddress(senderPrivateKey).tr.address const fee = parseFloat(getRef('fee_input')?.value.trim()) || 0
if (btcOperator.validateAddress(senderAddress) !== 'bech32m') return { senderPrivateKey, senderAddress, receivers, receiverAddresses, receiverAmounts, fee }
return notify('Sender address is not a Taproot address', 'error') }
async function sendTx() {
try {
const { senderPrivateKey, senderAddress, receivers, receiverAddresses, receiverAmounts, fee } = getTransactionDetails()
const confirmation = await getConfirmation('Confirm transaction', { const confirmation = await getConfirmation('Confirm transaction', {
message: html` message: html`
<div class="grid gap-1-5"> <div class="grid gap-1-5">
<div class="grid gap-0-5"> <div class="grid">
<span class="label">Sender address</span> <span class="label">Sender address</span>
<sm-copy value=${senderAddress}></sm-copy> <sm-copy value=${senderAddress}></sm-copy>
</div> </div>
<div class="grid gap-0-5"> <div class="grid">
<span class="label">Receivers</span> <span class="label">Receivers</span>
<div class="grid gap-0-3"> <div class="grid gap-0-3">
${Object.entries(receivers).map(([address, amount]) => html.node` ${Object.entries(receivers).map(([address, amount]) => html.node`
@ -809,7 +934,7 @@
`)} `)}
</div> </div>
</div> </div>
<div class="grid gap-0-5"> <div class="grid">
<span class="label">Fee</span> <span class="label">Fee</span>
<b>${formatAmount(fee)}</b> <b>${formatAmount(fee)}</b>
</div> </div>
@ -820,20 +945,19 @@
if (!confirmation) if (!confirmation)
return; return;
buttonLoader('send_tx_button', true) buttonLoader('send_tx_button', true)
createTx(senderPrivateKey, Object.keys(receivers), Object.values(receivers), fee).then(txHex => { const { txHex } = await createTx(senderPrivateKey, receiverAddresses, receiverAmounts, fee)
console.log(txHex)
btcOperator.broadcastTx(txHex).then(txid => { btcOperator.broadcastTx(txHex).then(txid => {
notify(`Transaction sent successfully. Txid: ${txid}`, 'success')
showTransactionResult(true, txid) showTransactionResult(true, txid)
}).catch(err => { }).catch(err => {
notify(err, 'error')
showTransactionResult(false, err) showTransactionResult(false, err)
}).finally(() => { }).finally(() => {
buttonLoader('send_tx_button', false) buttonLoader('send_tx_button', false)
}) })
}).catch(err => { } catch (e) {
notify(err, 'error') notify(e, 'error')
buttonLoader('send_tx_button', false) buttonLoader('send_tx_button', false)
}) }
} }
function showTransactionResult(success, result, options = {}) { function showTransactionResult(success, result, options = {}) {
let { title, description } = options let { title, description } = options
@ -889,8 +1013,20 @@
const util = {}; const util = {};
util.Sat_to_BTC = value => BigInt(parseFloat((value / SATOSHI_IN_BTC).toFixed(8))); util.Sat_to_BTC = value => parseFloat((value / SATOSHI_IN_BTC).toFixed(8));
util.BTC_to_Sat = value => BigInt(parseInt(value * SATOSHI_IN_BTC)); util.BTC_to_Sat = value => parseInt(value * SATOSHI_IN_BTC);
function get_fee_rate() {
return new Promise((resolve, reject) => {
fetch('https://api.blockchain.info/mempool/fees').then(response => {
if (response.ok)
response.json()
.then(result => resolve(util.Sat_to_BTC(result.regular)))
.catch(error => reject(error));
else
reject(response);
}).catch(error => reject(error))
})
}
const fetch_api = function (api, json_res = true) { const fetch_api = function (api, json_res = true) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -951,39 +1087,48 @@
* @param {array} array of amounts in BTC * @param {array} array of amounts in BTC
* @param {number} fee in BTC * @param {number} fee in BTC
*/ */
async function createTx(senderPrivateKey, receivers = [], amounts = [], fee) { async function createTx(senderPrivateKey, receivers = [], amounts = [], fee = 0) {
console.log(amounts)
return new Promise(async (resolve, reject) => {
try { try {
const { tr: { address, script } } = getTaprootAddress(senderPrivateKey) const { tr } = getTaprootAddress(senderPrivateKey)
const { address, script } = tr
const opts = {}; const opts = {};
const tx = new taproot.Transaction(opts); const tx = new taproot.Transaction(opts);
const totalAmount = amounts.reduce((total, amount) => total + amount, 0) const totalAmount = amounts.reduce((total, amount) => total + amount, 0)
const amountInSat = util.BTC_to_Sat(totalAmount) const amountInSat = util.BTC_to_Sat(totalAmount)
// check if sender has enough balance // check if sender has enough balance
btcOperator.getBalance(address).then(balance => { const senderBalance = await btcOperator.getBalance(address)
if (balance < totalAmount + fee) const feeRate = await get_fee_rate();
throw new Error(`Insufficient balance. Balance: ${balance}, Required: ${totalAmount + fee}`) let calculatedFee = 0
}).catch(err => { const { input_size } = await addUTXOs(tx, tr, [address], util.BTC_to_Sat(totalAmount), feeRate)
throw new Error(err) calculatedFee += input_size
})
await addUTXOs(tx, tr, [address], util.BTC_to_Sat(amount))
// add receivers // add receivers
receivers.forEach((receiver, i) => { receivers.forEach((receiver, i) => {
tx.addOutputAddress(receiver, util.BTC_to_Sat(amounts[i])) tx.addOutputAddress(receiver, BigInt(util.BTC_to_Sat(amounts[i])))
calculatedFee += _sizePerOutput(receiver)
}) })
calculatedFee += _sizePerOutput(address)
calculatedFee = parseFloat((calculatedFee * feeRate).toFixed(8)) // convert to sat
fee = fee || calculatedFee; // if fee is not provided, pass calculated fee
// add change address // add change address
tx.addOutputAddress(address, tx.inputAmount - amountInSat - util.BTC_to_Sat(fee)); const changeAmount = senderBalance - (totalAmount + fee)
if (changeAmount < 0)
tx.sign(privKey_arrayform, undefined, new Uint8Array(32)); return reject(`Insufficient balance. Required: ${totalAmount + fee} BTC, Available: ${util.Sat_to_BTC(senderBalance)} BTC`)
tx.addOutputAddress(address, BigInt(util.BTC_to_Sat(changeAmount)));
const privKey = coinjs.wif2privkey(senderPrivateKey).privkey;
const privKey_arrayForm = hex.decode(privKey);
tx.sign(privKey_arrayForm, undefined, new Uint8Array(32));
tx.finalize() tx.finalize()
return tx.hex resolve({ txHex: tx.hex, fee })
} catch (e) { } catch (e) {
console.error(e) reject(e)
} }
})
} }
const testTaproot = 'bc1p05whkacavgmh77pgsr7v5k4tyg28x3pqyjanfnjkzzdngqur4yks39w8zk' //remove this later function addUTXOs(tx, tr, senders = [], required_amount, fee_rate, rec_args = {}) {
function addUTXOs(tx, tr, senders = [testTaproot], required_amount, fee_rate, rec_args = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
required_amount = parseFloat(required_amount.toFixed(8)); required_amount = parseFloat(required_amount);
if (typeof rec_args.n === "undefined") { if (typeof rec_args.n === "undefined") {
rec_args.n = 0; rec_args.n = 0;
rec_args.input_size = 0; rec_args.input_size = 0;
@ -996,25 +1141,25 @@
change_amount: required_amount * -1 //required_amount will be -ve of change_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"); return reject(`Insufficient Balance.`);
let addr = senders[rec_args.n]; let addr = senders[rec_args.n];
let size_per_input = _sizePerInput(addr); let size_per_input = _sizePerInput(addr);
fetch_api(`unspent?active=${addr}`).then(result => { fetch_api(`unspent?active=${addr}`).then(result => {
let utxos = result.unspent_outputs; let utxos = result.unspent_outputs;
// console.debug("add-utxo", addr, required_amount, utxos); // console.debug("add-utxo", addr, required_amount, utxos);
for (let i = 0; i < utxos.length && required_amount > 0; i++) { for (let i = 0; i < utxos.length && required_amount > 0; i++) {
if (!utxos[i].confirmations) //ignore unconfirmed utxo const { tx_output_n, value, confirmations, tx_hash_big_endian } = utxos[i];
if (!confirmations) //ignore unconfirmed utxo
continue; continue;
const { tx_hash, tx_index, value } = utxos[i];
// tx.addinput(utxos[i].tx_hash_big_endian, utxos[i].tx_output_n, script, 0xfffffffd /*sequence*/); //0xfffffffd for Replace-by-fee
// changes for taproot // changes for taproot
const input = { txid: tx_hash, index: tx_index, script: tr.script, amount: value } const input = { txid: tx_hash_big_endian, index: tx_output_n, script: tr.script, amount: BigInt(value) }
tx.addInput({ ...input, ...tr, witnessUtxo: { script: input.script, amount: input.amount }, }); tx.addInput({ ...input, ...tr, witnessUtxo: { script: input.script, amount: input.amount }, });
//update track values //update track values
rec_args.input_size += size_per_input; // Adjust input size calculation rec_args.input_size += size_per_input; // Adjust input size calculation
rec_args.input_amount += util.Sat_to_BTC(utxos[i].value); rec_args.input_amount += value;
required_amount -= util.Sat_to_BTC(utxos[i].value); required_amount -= value;
if (fee_rate) //automatic fee calculation (dynamic) if (fee_rate) //automatic fee calculation (dynamic)
required_amount += size_per_input * fee_rate; required_amount += size_per_input * fee_rate;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

9
scripts/tap_combined.min.js vendored Normal file

File diff suppressed because one or more lines are too long