Compare commits
10 Commits
e493b67349
...
cd80c73bc7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd80c73bc7 | ||
|
|
229b7c1e93 | ||
|
|
e479233f27 | ||
|
|
7064345bc9 | ||
|
|
402f983571 | ||
|
|
32e3c45a28 | ||
|
|
a783fac9db | ||
|
|
bbb0242166 | ||
|
|
d663512ab5 | ||
|
|
8ed229b3fe |
32
.github/workflows/push-dappbundle.yml
vendored
Normal file
32
.github/workflows/push-dappbundle.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: Workflow push to Dappbundle
|
||||
on: [push]
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Executing remote command
|
||||
uses: appleboy/ssh-action@v1.0.0
|
||||
with:
|
||||
host: ${{ secrets.R_HOST }}
|
||||
username: ${{ secrets.P_USERNAME }}
|
||||
password: ${{ secrets.P_PASSWORD }}
|
||||
port: ${{ secrets.SSH_PORT }}
|
||||
script: |
|
||||
if [ -d "${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle" ]; then
|
||||
echo "Folder exists. Skipping Git clone."
|
||||
else
|
||||
echo "Folder does not exist. Cloning repository..."
|
||||
cd ${{ secrets.DEPLOYMENT_LOCATION}}/ && git clone https://github.com/ranchimall/dappbundle.git
|
||||
fi
|
||||
|
||||
if [ -d "${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/${{ github.event.repository.name }}" ]; then
|
||||
echo "Repository exists. Remove folder "
|
||||
rm -r "${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/${{ github.event.repository.name }}"
|
||||
fi
|
||||
|
||||
echo "Cloning repository..."
|
||||
cd ${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle && git clone https://github.com/ranchimall/${{ github.event.repository.name }}
|
||||
|
||||
cd "${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/${{ github.event.repository.name }}" && rm -rf .gitattributes .git .github .gitignore
|
||||
cd ${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/ && git add . && git commit -m "Workflow updating files of ${{ github.event.repository.name }}" && git push "https://ranchimalldev:${{ secrets.RM_ACCESS_TOKEN }}@github.com/ranchimall/dappbundle.git"
|
||||
41
css/main.css
41
css/main.css
@ -233,7 +233,7 @@ details[open] > summary .down-arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
fieldset {
|
||||
sm-form fieldset {
|
||||
border: none;
|
||||
}
|
||||
|
||||
@ -470,6 +470,10 @@ ul {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.fw-500 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.padding-block-1 {
|
||||
padding-block: 1rem;
|
||||
}
|
||||
@ -586,6 +590,20 @@ ul {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
padding: 0.4rem;
|
||||
background-color: rgba(var(--text-color, 17, 17, 17), 0.06);
|
||||
border-radius: var(--button-border-radius, 0.3rem);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
border-radius: 0.5rem;
|
||||
@ -1298,6 +1316,27 @@ body.loaded .nav-item__indicator {
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
#generate_script_path_address_popup fieldset {
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: solid thin rgba(var(--text-color), 0.3);
|
||||
}
|
||||
#generate_script_path_address_popup fieldset legend {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
padding: 0 0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
}
|
||||
#generate_script_path_address_popup .taproot-member sm-copy {
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
#generate_script_path_address_popup .taproot-member:not(:last-of-type) {
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 640px) {
|
||||
.hide-on-small {
|
||||
display: none;
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -212,8 +212,10 @@ details[open] {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
fieldset {
|
||||
border: none;
|
||||
sm-form {
|
||||
fieldset {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
sm-input {
|
||||
--border-radius: 0.5rem;
|
||||
@ -430,6 +432,9 @@ ul {
|
||||
.h-100 {
|
||||
height: 100%;
|
||||
}
|
||||
.fw-500 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.padding-block-1 {
|
||||
padding-block: 1rem;
|
||||
@ -536,6 +541,19 @@ ul {
|
||||
.ws-pre-line {
|
||||
white-space: pre-line;
|
||||
}
|
||||
.copy-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
padding: 0.4rem;
|
||||
background-color: rgba(var(--text-color, (17, 17, 17)), 0.06);
|
||||
border-radius: var(--button-border-radius, 0.3rem);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
@ -1203,6 +1221,30 @@ body.loaded .nav-item {
|
||||
}
|
||||
}
|
||||
}
|
||||
#generate_script_path_address_popup {
|
||||
fieldset {
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: solid thin rgba(var(--text-color), 0.3);
|
||||
legend {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
padding: 0 0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
}
|
||||
}
|
||||
.taproot-member {
|
||||
sm-copy {
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
&:not(:last-of-type) {
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
.hide-on-small {
|
||||
display: none;
|
||||
|
||||
189
index.html
189
index.html
@ -149,7 +149,7 @@
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<div id="generate_script_path_address_popup__content"></div>
|
||||
<div id="generate_script_path_address_popup__content" class="grid gap-2"></div>
|
||||
</sm-popup>
|
||||
<sm-popup id="convert_to_taproot_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
@ -277,6 +277,14 @@
|
||||
popupStack.peek().popup.hide()
|
||||
}
|
||||
|
||||
function copyToClipboard(data) {
|
||||
navigator.clipboard.writeText(data).then(() => {
|
||||
notify('Copied to clipboard', 'success')
|
||||
}).catch(() => {
|
||||
notify('Failed to copy to clipboard', 'error')
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener('popupopened', e => {
|
||||
switch (e.target.id) {
|
||||
case 'generate_key_path_address_popup': {
|
||||
@ -296,7 +304,6 @@
|
||||
case 'generate_script_path_address_popup': {
|
||||
const { wif, tr: { address } } = getTaprootAddress()
|
||||
const privateKey = coinjs.wif2privkey(wif).privkey
|
||||
console.log(wif, address)
|
||||
const scriptInputs = [1];
|
||||
const renderScriptInput = (index) => html`
|
||||
<div class="flex gap-0-5">
|
||||
@ -318,23 +325,49 @@
|
||||
}
|
||||
function generateScriptPathAddress() {
|
||||
const schnorrPublicKey = secp256k1_schnorr.getPublicKey(hex.decode(privateKey));
|
||||
const taprootTree = [...document.querySelectorAll('.member-script-input')].map(input => {
|
||||
let memberScripts = [...document.querySelectorAll('.member-script-input')].map(input => input.value.trim());
|
||||
memberScripts = [...new Set(memberScripts)] // remove duplicates
|
||||
const taprootTree = memberScripts.map(script => {
|
||||
return {
|
||||
script: input.value.trim(),
|
||||
script,
|
||||
leafVersion: 0xc0,
|
||||
}
|
||||
})
|
||||
const { address } = taproot.p2tr(
|
||||
const { address, leaves } = taproot.p2tr(
|
||||
schnorrPublicKey,
|
||||
taprootTree,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
renderElem(getRef('generate_script_path_address_popup__content'), html`
|
||||
<div class="grid gap-1">
|
||||
<h4>Generated Taproot script-path address</h4>
|
||||
<sm-copy value="${address}"></sm-copy>
|
||||
</div>
|
||||
<fieldset class="grid gap-0-5">
|
||||
<legend>Taproot script-path address</legend>
|
||||
<b class="wrap-around fw-500" style="font-size:0.9rem">${address}</b>
|
||||
</fieldset>
|
||||
<fieldset class="grid gap-0-5">
|
||||
<legend>Members</legend>
|
||||
<ul class="grid gap-0-5">
|
||||
${leaves.map((leaf, index) => html`
|
||||
<li class="grid gap-1 taproot-member">
|
||||
<div class="flex align-center space-between">
|
||||
<h5>Member #${index + 1}</h5>
|
||||
<button class="copy-button" onclick=${() => copyToClipboard(`Member #${index + 1}\n\nScript: ${hex.encode(leaf.script)}\n\nControl block: ${hex.encode(leaf.controlBlock)}`)}>
|
||||
COPY
|
||||
</button>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<p class="label">Script</p>
|
||||
<b class="wrap-around" style="font-size:0.9rem">${hex.encode(leaf.script)}</b>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<p class="label">Control block</p>
|
||||
<b class="wrap-around" style="font-size:0.9rem">${hex.encode(leaf.controlBlock)}</b>
|
||||
</div>
|
||||
</li>
|
||||
`)}
|
||||
</ul>
|
||||
</fieldset>
|
||||
`);
|
||||
}
|
||||
function renderScriptInputList() {
|
||||
@ -501,7 +534,7 @@
|
||||
.then(() => {
|
||||
selectedCurrency = localStorage.getItem('taproot-wallet-currency') || 'btc'
|
||||
setTimeout(() => {
|
||||
document.getElementById('currency_selector').value = selectedCurrency
|
||||
getRef('currency_selector').value = selectedCurrency
|
||||
}, 100)
|
||||
})
|
||||
.catch(e => {
|
||||
@ -1338,8 +1371,8 @@
|
||||
const [suggestedFeeStatus, setSuggestedFeeStatus] = $signal(['idle'])
|
||||
const [feeType, setFeeType] = $signal('suggested')
|
||||
const [atTaprootStep, setAtTaprootStep] = $signal(1);
|
||||
const [spendingType, setSpendingType] = $signal('key-path');
|
||||
router.addRoute('send', (state) => {
|
||||
let { params: { type = 'key-path' } } = state
|
||||
const [isSignRequired, setIsSignRequired] = $signal(false)
|
||||
const renderSendPage = () => {
|
||||
let feeSection = ''
|
||||
@ -1363,7 +1396,7 @@
|
||||
`
|
||||
}
|
||||
let form = '';
|
||||
if (spendingType() === 'script-path') {
|
||||
if (type === 'script-path') {
|
||||
switch (atTaprootStep()) {
|
||||
case 1:
|
||||
form = html`
|
||||
@ -1511,12 +1544,12 @@
|
||||
<h3>
|
||||
Perform Transaction
|
||||
</h3>
|
||||
<sm-chips onchange=${e => setSpendingType(e.target.value)}>
|
||||
<sm-chip value="key-path" ?selected=${spendingType() === 'key-path'}>Key-path</sm-chip>
|
||||
<sm-chip value="script-path" ?selected=${spendingType() === 'script-path'}>Script-path</sm-chip>
|
||||
<sm-chips onchange=${e => location.hash = `/send?type=${e.target.value}`}>
|
||||
<sm-chip value="key-path" ?selected=${type === 'key-path'}>Key-path</sm-chip>
|
||||
<sm-chip value="script-path" ?selected=${type === 'script-path'}>Script-path</sm-chip>
|
||||
</sm-chips>
|
||||
</div>
|
||||
${spendingType() === 'script-path' ? html`
|
||||
${type === 'script-path' ? html`
|
||||
<ul id="taproot_steps" class="steps">
|
||||
${[1, 2].map(step => html`
|
||||
<li class=${`step ${atTaprootStep() === step ? 'active' : ''} ${atTaprootStep() > step ? 'done' : ''}`}></li>
|
||||
@ -1815,7 +1848,7 @@
|
||||
convertedTo = 'BTC'
|
||||
break;
|
||||
case 'btc':
|
||||
convertedAddress = floCrypto.getFloID(addressToConvert);
|
||||
convertedAddress = floCrypto.toFloID(addressToConvert);
|
||||
convertedTo = 'FLO'
|
||||
break;
|
||||
}
|
||||
@ -2105,15 +2138,13 @@
|
||||
<svg class="icon visible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <title>Show password</title> <path d="M0 0h24v24H0z" fill="none"></path> <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"> </path> </svg>
|
||||
</label>
|
||||
</sm-input>
|
||||
</div>
|
||||
<div class="grid gap-0-5">
|
||||
${finalScriptWitness.length > 3 ? html`
|
||||
<sm-input id="signature_place_input" placeholder="Position of signature. (1, 2, ...)" type="number" min="1" max=${requiredSolutions + 1} error-text=${`Value must be between 1 and ${requiredSolutions + 1}`} animate required></sm-input>
|
||||
` : html`
|
||||
<sm-input id="signature_place_input" placeholder="Position of signature" type="number" value="1" readonly animate required></sm-input>
|
||||
`}
|
||||
<p>*The generated signature will be used as one of the solutions.</p>
|
||||
</div>
|
||||
${finalScriptWitness.length > 3 ? html`
|
||||
<sm-input id="signature_place_input" placeholder="Position of signature. (1, 2, ...)" type="number" min="1" max=${requiredSolutions + 1} error-text=${`Value must be between 1 and ${requiredSolutions + 1}`} animate required></sm-input>
|
||||
` : html`
|
||||
<sm-input id="signature_place_input" placeholder="Position of signature" class="hidden" type="number" value="1" readonly animate required></sm-input>
|
||||
`}
|
||||
` : ''}
|
||||
<div class="grid gap-0-5">
|
||||
<p>
|
||||
@ -2124,7 +2155,7 @@
|
||||
</sm-input>
|
||||
</div>
|
||||
<div class="multi-state-button">
|
||||
<button id="increase_fee" class="button button--primary" onclick=${increaseFee} type="submit" disabled>Increase fee</button>
|
||||
<button id="increase_fee" class="button button--primary" onclick=${() => increaseFee('script-path')} type="submit" disabled>Increase fee</button>
|
||||
</div>
|
||||
</sm-form>
|
||||
`)
|
||||
@ -2174,12 +2205,12 @@
|
||||
</sm-input>
|
||||
</div>
|
||||
<div class="multi-state-button">
|
||||
<button id="increase_fee" class="button button--primary" onclick=${increaseFee} type="submit" disabled>Increase fee</button>
|
||||
<button id="increase_fee" class="button button--primary" onclick=${() => increaseFee('key-path')} type="submit" disabled>Increase fee</button>
|
||||
</div>
|
||||
</sm-form>
|
||||
`)
|
||||
}
|
||||
document.getElementById('new_fee').querySelector('.currency-symbol').innerHTML = currencyIcons[selectedCurrency]
|
||||
getRef('new_fee').querySelector('.currency-symbol').innerHTML = currencyIcons[selectedCurrency]
|
||||
openPopup('increase_fee_popup')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
@ -2187,39 +2218,54 @@
|
||||
buttonLoader(button, false)
|
||||
}
|
||||
}
|
||||
async function increaseFee() {
|
||||
buttonLoader(document.getElementById('increase_fee'), true)
|
||||
const newFee = parseFloat((parseFloat(document.getElementById('new_fee').value.trim()) / (globalExchangeRate[selectedCurrency] || 1)).toFixed(8))
|
||||
const privateKeys = []
|
||||
document.querySelectorAll('.increase-fee-sender').forEach(sender => {
|
||||
const address = sender.querySelector('.sender__address').textContent.trim()
|
||||
const privateKey = sender.querySelector('.sender__private-key').value.trim()
|
||||
if (!btcOperator.verifyKey(address, privateKey))
|
||||
return notify(`Invalid private key for address ${address}`, 'error')
|
||||
if (privateKey) {
|
||||
privateKeys.push(privateKey)
|
||||
}
|
||||
})
|
||||
console.log(changingFeeOf, newFee, privateKeys)
|
||||
async function increaseFee(type = 'key-path') {
|
||||
try {
|
||||
let signedTxHex = await taprootEditFee({
|
||||
txId: changingFeeOf,
|
||||
new_fee: newFee,
|
||||
private_keys: privateKeys
|
||||
})
|
||||
btcOperator.broadcastTx(signedTxHex).then(txId => {
|
||||
buttonLoader(getRef('increase_fee'), true)
|
||||
const newFee = parseFloat((parseFloat(getRef('new_fee').value.trim()) / (globalExchangeRate[selectedCurrency] || 1)).toFixed(8))
|
||||
let txHex
|
||||
if (type === 'key-path') {
|
||||
const privateKeys = []
|
||||
document.querySelectorAll('.increase-fee-sender').forEach(sender => {
|
||||
const address = sender.querySelector('.sender__address').textContent.trim()
|
||||
const privateKey = sender.querySelector('.sender__private-key').value.trim()
|
||||
if (!btcOperator.verifyKey(address, privateKey))
|
||||
return notify(`Invalid private key for address ${address}`, 'error')
|
||||
if (privateKey) {
|
||||
privateKeys.push(privateKey)
|
||||
}
|
||||
})
|
||||
txHex = await taprootEditFee({
|
||||
txId: changingFeeOf,
|
||||
newFee: newFee,
|
||||
privateKeys
|
||||
})
|
||||
} else {
|
||||
const providedSolutions = [...document.querySelectorAll('.solution-input')].map(input => input.value.trim())
|
||||
const signaturePlace = parseInt(getRef('signature_place_input').value.trim())
|
||||
const signerPrivateKey = getRef('signer_input') ? getRef('signer_input').value.trim() : null;
|
||||
const editParams = {
|
||||
txId: changingFeeOf,
|
||||
newFee,
|
||||
providedSolutions,
|
||||
signaturePlace,
|
||||
}
|
||||
if (signerPrivateKey)
|
||||
editParams.signerSecretKey = hex.decode(coinjs.wif2privkey(signerPrivateKey).privkey)
|
||||
txHex = await taprootEditFee(editParams)
|
||||
}
|
||||
btcOperator.broadcastTx(txHex).then(txId => {
|
||||
console.log(txId)
|
||||
closePopup()
|
||||
showTransactionResult('success', txId)
|
||||
}).catch(e => {
|
||||
notify(e, 'error')
|
||||
}).finally(_ => {
|
||||
buttonLoader(document.getElementById('increase_fee'), false)
|
||||
buttonLoader(getRef('increase_fee'), false)
|
||||
changingFeeOf = null
|
||||
})
|
||||
} catch (err) {
|
||||
notify(e, 'error')
|
||||
buttonLoader(document.getElementById('increase_fee'), false)
|
||||
buttonLoader(getRef('increase_fee'), false)
|
||||
}
|
||||
}
|
||||
router.addRoute('create', state => {
|
||||
@ -2487,29 +2533,27 @@
|
||||
})
|
||||
}
|
||||
|
||||
const taprootEditFee = function ({ txId, new_fee, private_keys, change_only = true }) {
|
||||
const taprootEditFee = function ({ txId, newFee, privateKeys, changeOnly = true, signerSecretKey, providedSolutions, signaturePlace }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!Array.isArray(private_keys))
|
||||
private_keys = [private_keys];
|
||||
getTaprootTx(txId).then(({ tx, rawTx }) => {
|
||||
const isScriptPath = tx.inputs[0].finalScriptWitness && tx.inputs[0].finalScriptWitness.length > 1;
|
||||
const parsedTx = parseTransaction(rawTx)
|
||||
if (parsedTx.fee >= new_fee)
|
||||
if (parsedTx.fee >= newFee)
|
||||
return reject("Fees can only be increased");
|
||||
|
||||
//editable addresses in output values (for fee increase)
|
||||
parsedTx edit_output_address = new Set();
|
||||
if (change_only === true) //allow only change values (ie, sender address) to be edited to inc fee
|
||||
const edit_output_address = new Set();
|
||||
if (changeOnly === true) //allow only change values (ie, sender address) to be edited to inc fee
|
||||
parsedTx.inputs.forEach(inp => edit_output_address.add(inp.address));
|
||||
else if (change_only === false) //allow all output values to be edited
|
||||
else if (changeOnly === false) //allow all output values to be edited
|
||||
parsedTx.outputs.forEach(out => edit_output_address.add(out.address));
|
||||
else if (typeof change_only == 'string') // allow only given receiver id output to be edited
|
||||
edit_output_address.add(change_only);
|
||||
else if (Array.isArray(change_only)) //allow only given set of receiver id outputs to be edited
|
||||
change_only.forEach(id => edit_output_address.add(id));
|
||||
else if (typeof changeOnly == 'string') // allow only given receiver id output to be edited
|
||||
edit_output_address.add(changeOnly);
|
||||
else if (Array.isArray(changeOnly)) //allow only given set of receiver id outputs to be edited
|
||||
changeOnly.forEach(id => edit_output_address.add(id));
|
||||
|
||||
//edit output values to increase fee
|
||||
let inc_fee = btcOperator.util.BTC_to_Sat(new_fee - parsedTx.fee);
|
||||
let inc_fee = btcOperator.util.BTC_to_Sat(newFee - parsedTx.fee);
|
||||
if (inc_fee < MIN_FEE_UPDATE)
|
||||
return reject(`Insufficient additional fee. Minimum increment: ${MIN_FEE_UPDATE}`);
|
||||
for (let i = tx.outs.length - 1; i >= 0 && inc_fee > 0; i--) //reduce in reverse order
|
||||
@ -2527,19 +2571,36 @@
|
||||
}
|
||||
}
|
||||
if (inc_fee > 0) {
|
||||
let max_possible_fee = btcOperator.util.BTC_to_Sat(new_fee) - inc_fee; //in satoshi
|
||||
let max_possible_fee = btcOperator.util.BTC_to_Sat(newFee) - inc_fee; //in satoshi
|
||||
return reject(`Insufficient output values to increase fee. Maximum fee possible: ${btcOperator.util.Sat_to_BTC(max_possible_fee)}`);
|
||||
}
|
||||
tx.outs = tx.outs.filter(o => o.value >= DUST_AMT); //remove all output with value less than DUST amount
|
||||
if (isScriptPath) {
|
||||
|
||||
tx.inputs.forEach((input, index) => {
|
||||
// remove every element from the finalScriptWitness except the last two
|
||||
const scriptWitness = input.finalScriptWitness.slice(-2)
|
||||
const [userScript, controlBlock] = scriptWitness;
|
||||
const controlBlockVersion = taproot.TaprootControlBlock.decode(controlBlock).version
|
||||
const providedSolutions = scriptWitness.slice(0, -1)
|
||||
if (providedSolutions && providedSolutions.length)
|
||||
scriptWitness.unshift(...providedSolutions)
|
||||
if (signerSecretKey) {
|
||||
const { amount } = consumedUtxos[index]
|
||||
const hash = tx.preimageWitnessV1(index, [script], 0, [amount], undefined, userScript, controlBlockVersion)
|
||||
const sig = secp.schnorr.signSync(hash, signerSecretKey, new Uint8Array(32))
|
||||
scriptWitness.splice((signaturePlace - 1), 0, sig)
|
||||
}
|
||||
input.finalScriptWitness = scriptWitness
|
||||
})
|
||||
} else {
|
||||
//remove existing signatures and reset the scripts
|
||||
if (!Array.isArray(privateKeys))
|
||||
privateKeys = [privateKeys];
|
||||
let wif_keys = [];
|
||||
for (let i in tx.ins) {
|
||||
const addr = parsedTx.inputs[i].address;
|
||||
//find the correct key for addr
|
||||
const privKey = private_keys.find(pk => btcOperator.verifyKey(addr, pk));
|
||||
const privKey = privateKeys.find(pk => btcOperator.verifyKey(addr, pk));
|
||||
if (!privKey)
|
||||
return reject(`Private key missing for ${addr}`);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
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