Feature update
-- added approximate transaction fees for BTC transactions -- updated form component
This commit is contained in:
parent
ea6b9f5cb9
commit
afd5f7af53
27
css/main.css
27
css/main.css
@ -52,9 +52,6 @@ body[data-theme=dark] {
|
|||||||
--green: #00e676;
|
--green: #00e676;
|
||||||
--yellow: rgb(255, 213, 5);
|
--yellow: rgb(255, 213, 5);
|
||||||
}
|
}
|
||||||
body[data-theme=dark] sm-popup::part(popup) {
|
|
||||||
background-color: rgba(var(--foreground-color), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
p,
|
p,
|
||||||
strong {
|
strong {
|
||||||
@ -172,6 +169,9 @@ details[open] > summary .down-arrow {
|
|||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sm-popup::part(popup) {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
}
|
||||||
sm-popup::part(backdrop) {
|
sm-popup::part(backdrop) {
|
||||||
-webkit-backdrop-filter: blur(0.5rem);
|
-webkit-backdrop-filter: blur(0.5rem);
|
||||||
backdrop-filter: blur(0.5rem);
|
backdrop-filter: blur(0.5rem);
|
||||||
@ -1015,16 +1015,31 @@ ol li::before {
|
|||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#selected_fee_tip {
|
#selected_fee_tip,
|
||||||
|
#error_section {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
#selected_fee_tip.error {
|
|
||||||
|
.error {
|
||||||
color: var(--danger-color);
|
color: var(--danger-color);
|
||||||
}
|
}
|
||||||
#selected_fee_tip.error .icon {
|
.error .icon {
|
||||||
fill: var(--danger-color);
|
fill: var(--danger-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#send_fee_wrapper {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
#send_fee_wrapper > * {
|
||||||
|
grid-area: 1/1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#send_fee_loader {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.receiver-card {
|
.receiver-card {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.5rem;
|
gap: 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
@ -50,9 +50,6 @@ body[data-theme="dark"] {
|
|||||||
--danger-color: rgb(255, 106, 106);
|
--danger-color: rgb(255, 106, 106);
|
||||||
--green: #00e676;
|
--green: #00e676;
|
||||||
--yellow: rgb(255, 213, 5);
|
--yellow: rgb(255, 213, 5);
|
||||||
sm-popup::part(popup) {
|
|
||||||
background-color: rgba(var(--foreground-color), 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p,
|
p,
|
||||||
@ -160,6 +157,9 @@ details[open] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sm-popup {
|
sm-popup {
|
||||||
|
&::part(popup) {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
}
|
||||||
&::part(backdrop) {
|
&::part(backdrop) {
|
||||||
backdrop-filter: blur(0.5rem);
|
backdrop-filter: blur(0.5rem);
|
||||||
}
|
}
|
||||||
@ -930,15 +930,27 @@ ol {
|
|||||||
.remove-card-wrapper {
|
.remove-card-wrapper {
|
||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
}
|
}
|
||||||
#selected_fee_tip {
|
#selected_fee_tip,
|
||||||
|
#error_section {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
&.error {
|
}
|
||||||
color: var(--danger-color);
|
.error {
|
||||||
.icon {
|
color: var(--danger-color);
|
||||||
fill: var(--danger-color);
|
.icon {
|
||||||
}
|
fill: var(--danger-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#send_fee_wrapper {
|
||||||
|
display: grid;
|
||||||
|
& > * {
|
||||||
|
grid-area: 1/1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#send_fee_loader {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
.receiver-card {
|
.receiver-card {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
|||||||
304
index.html
304
index.html
@ -1194,7 +1194,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<h3>Send BTC</h3>
|
<h3>Send BTC</h3>
|
||||||
</header>
|
</header>
|
||||||
<sm-form id="send_tx">
|
<sm-form id="send_tx" skip-submit>
|
||||||
<div>
|
<div>
|
||||||
<h4 class="margin-bottom-0-5">Receivers</h4>
|
<h4 class="margin-bottom-0-5">Receivers</h4>
|
||||||
<div id="receiver_container">
|
<div id="receiver_container">
|
||||||
@ -1238,23 +1238,29 @@
|
|||||||
<sm-chip value="custom">Custom</sm-chip>
|
<sm-chip value="custom">Custom</sm-chip>
|
||||||
</sm-chips>
|
</sm-chips>
|
||||||
</div>
|
</div>
|
||||||
<p id="selected_fee_tip">Estimated time of confirmation is 1hr</p>
|
<p id="selected_fee_tip"></p>
|
||||||
<sm-input type="number" id="send_fee" placeholder="Fee" min="0.00000001" step="0.00000001"
|
<div id="send_fee_wrapper">
|
||||||
error-text="Please enter valid fees" readonly animate required>
|
<sm-input type="number" id="send_fee" placeholder="Fee" min="0.00000001" step="0.00000001"
|
||||||
<div class="currency-symbol flex" slot="icon">
|
error-text="Please enter valid fees" readonly animate required>
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
<div class="currency-symbol flex" slot="icon">
|
||||||
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
||||||
<g>
|
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<rect fill="none" height="24" width="24"></rect>
|
<g>
|
||||||
</g>
|
<rect fill="none" height="24" width="24"></rect>
|
||||||
<g>
|
</g>
|
||||||
<path
|
<g>
|
||||||
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
|
||||||
</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">
|
||||||
</g>
|
</path>
|
||||||
</svg>
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</sm-input>
|
||||||
|
<div id="send_fee_loader" class="hidden flex align-center gap-0-5">
|
||||||
|
<sm-spinner></sm-spinner>
|
||||||
|
<span>Calculating fees...</span>
|
||||||
</div>
|
</div>
|
||||||
</sm-input>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="error_section" class="hidden"></div>
|
<div id="error_section" class="hidden"></div>
|
||||||
<div class="multi-state-button">
|
<div class="multi-state-button">
|
||||||
@ -1565,6 +1571,11 @@
|
|||||||
}
|
}
|
||||||
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
||||||
refreshBalance()
|
refreshBalance()
|
||||||
|
getExchangeRate().then(rate => {
|
||||||
|
getRef('conversion_rate').textContent = `1BTC = ${formatAmount(rate.inr)}`;
|
||||||
|
}).catch(error => {
|
||||||
|
console.error(error)
|
||||||
|
})
|
||||||
if (floGlobals.isSubAdmin) {
|
if (floGlobals.isSubAdmin) {
|
||||||
cashierUI.renderRequests(Cashier.Requests);
|
cashierUI.renderRequests(Cashier.Requests);
|
||||||
Cashier.init().then(result => {
|
Cashier.init().then(result => {
|
||||||
@ -1704,6 +1715,9 @@
|
|||||||
getRef('select_withdraw_upi_id').parentNode.classList.remove('hidden')
|
getRef('select_withdraw_upi_id').parentNode.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'send_btc_popup':
|
||||||
|
calculateFees()
|
||||||
|
break;
|
||||||
case 'profile_popup':
|
case 'profile_popup':
|
||||||
renderElem(getRef('profile_popup__content'), render.profile())
|
renderElem(getRef('profile_popup__content'), render.profile())
|
||||||
renderSavedUpiIds('saved_upi_ids_list')
|
renderSavedUpiIds('saved_upi_ids_list')
|
||||||
@ -2013,9 +2027,6 @@
|
|||||||
})
|
})
|
||||||
render.savedIds()
|
render.savedIds()
|
||||||
}
|
}
|
||||||
getExchangeRate().then(rate => {
|
|
||||||
getRef('conversion_rate').textContent = `1BTC = ${formatAmount(rate.inr)}`;
|
|
||||||
})
|
|
||||||
break;
|
break;
|
||||||
case 'contacts':
|
case 'contacts':
|
||||||
render.savedIds()
|
render.savedIds()
|
||||||
@ -2405,6 +2416,23 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const fadeIn = [
|
||||||
|
{
|
||||||
|
opacity: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const fadeOut = [
|
||||||
|
{
|
||||||
|
opacity: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
function showChildElement(id, index, options = {}) {
|
function showChildElement(id, index, options = {}) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@ -2485,59 +2513,57 @@
|
|||||||
});
|
});
|
||||||
floGlobals.prefersReducedMotion = reduceMotionQuery.matches
|
floGlobals.prefersReducedMotion = reduceMotionQuery.matches
|
||||||
|
|
||||||
const generateKeys = document.createElement('template')
|
|
||||||
generateKeys.innerHTML = `
|
|
||||||
<style>
|
|
||||||
:host{
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.generated-keys-wrapper {
|
|
||||||
padding: 1rem;
|
|
||||||
background-color: rgba(var(--foreground-color), 1);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
}
|
|
||||||
#flo_id_warning{
|
|
||||||
padding-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
#flo_id_warning .icon {
|
|
||||||
height: 3rem;
|
|
||||||
width: 3rem;
|
|
||||||
padding: 0.8rem;
|
|
||||||
overflow: visible;
|
|
||||||
background-color: #ffc107;
|
|
||||||
border-radius: 3rem;
|
|
||||||
fill: rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<section class="grid gap-1-5">
|
|
||||||
<div id="flo_id_warning" class="flex gap-1">
|
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <path d="M0 0h24v24H0z" fill="none" /> <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" /> </svg>
|
|
||||||
<div class="grid gap-0-5">
|
|
||||||
<strong>
|
|
||||||
<h3> Keep your keys safe! </h3>
|
|
||||||
</strong>
|
|
||||||
<p>Don't share with anyone. Once lost private key can't be recovered.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-1-5 generated-keys-wrapper">
|
|
||||||
<div class="grid gap-0-5">
|
|
||||||
<h5>FLO address</h5>
|
|
||||||
<sm-copy id="generated_flo_address"></sm-copy>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-0-5">
|
|
||||||
<h5>Private key</h5>
|
|
||||||
<sm-copy id="generated_private_key"></sm-copy>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button id="sign_up_button" class="button button--primary w-100">Sign in with these credentials</button>
|
|
||||||
<p class="margin-top-1">You can use these FLO credentials with other RanchiMall apps too. </p>
|
|
||||||
</section>
|
|
||||||
`
|
|
||||||
window.customElements.define('keys-generator', class extends HTMLElement {
|
window.customElements.define('keys-generator', class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.appendChild(generateKeys.content.cloneNode(true));
|
this.innerHTML = `
|
||||||
|
<style>
|
||||||
|
:host{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.generated-keys-wrapper {
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
#flo_id_warning{
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
#flo_id_warning .icon {
|
||||||
|
height: 3rem;
|
||||||
|
width: 3rem;
|
||||||
|
padding: 0.8rem;
|
||||||
|
overflow: visible;
|
||||||
|
background-color: #ffc107;
|
||||||
|
border-radius: 3rem;
|
||||||
|
fill: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section class="grid gap-1-5">
|
||||||
|
<div id="flo_id_warning" class="flex gap-1">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <path d="M0 0h24v24H0z" fill="none" /> <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" /> </svg>
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<strong>
|
||||||
|
<h3> Keep your keys safe! </h3>
|
||||||
|
</strong>
|
||||||
|
<p>Don't share with anyone. Once lost private key can't be recovered.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-1-5 generated-keys-wrapper">
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<h5>FLO address</h5>
|
||||||
|
<sm-copy id="generated_flo_address"></sm-copy>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<h5>Private key</h5>
|
||||||
|
<sm-copy id="generated_private_key"></sm-copy>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="sign_up_button" class="button button--primary w-100">Sign in with these credentials</button>
|
||||||
|
<p class="margin-top-1">You can use these FLO credentials with other RanchiMall apps too. </p>
|
||||||
|
</section>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
get keys() {
|
get keys() {
|
||||||
return {
|
return {
|
||||||
@ -2616,8 +2642,7 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M4.47 21h15.06c1.54 0 2.5-1.67 1.73-3L13.73 4.99c-.77-1.33-2.69-1.33-3.46 0L2.74 18c-.77 1.33.19 3 1.73 3zM12 14c-.55 0-1-.45-1-1v-2c0-.55.45-1 1-1s1 .45 1 1v2c0 .55-.45 1-1 1zm1 4h-2v-2h2v2z"/></svg>
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M4.47 21h15.06c1.54 0 2.5-1.67 1.73-3L13.73 4.99c-.77-1.33-2.69-1.33-3.46 0L2.74 18c-.77 1.33.19 3 1.73 3zM12 14c-.55 0-1-.45-1-1v-2c0-.55.45-1 1-1s1 .45 1 1v2c0 .55-.45 1-1 1zm1 4h-2v-2h2v2z"/></svg>
|
||||||
<h1>Ad-Blocker Detected!</h1>
|
<h1>Ad-Blocker Detected!</h1>
|
||||||
<p>
|
<p>
|
||||||
It seems like you are using an ad-blocker. Please disable it and reload the page.
|
Please disable your ad-blocker for optimal experience. Our app doesn't show ads or track activity.
|
||||||
We don't show any ads on this app and we don't track you.
|
|
||||||
</p>
|
</p>
|
||||||
${isBrave ? `<strong>If you have enabled Brave shield then disable it also.</strong>` : ''}
|
${isBrave ? `<strong>If you have enabled Brave shield then disable it also.</strong>` : ''}
|
||||||
`;
|
`;
|
||||||
@ -3694,12 +3719,19 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getAddressDetails(floGlobals.myBtcID).then(({ txs }) => {
|
getAddressDetails(floGlobals.myBtcID).then(({ txs }) => {
|
||||||
|
console.log(txs)
|
||||||
let allTransactions = []
|
let allTransactions = []
|
||||||
const propToCheck = type === 'sent' ? 'out' : 'in';
|
let propToCheck = false
|
||||||
|
if (type === 'sent')
|
||||||
|
propToCheck = 'out';
|
||||||
|
else if (type === 'received')
|
||||||
|
propToCheck = 'in';
|
||||||
|
else if (type === 'self')
|
||||||
|
propToCheck = 'self';
|
||||||
for (let i = 0; i < txs.length; i++) {
|
for (let i = 0; i < txs.length; i++) {
|
||||||
const tx = txs[i];
|
const tx = txs[i];
|
||||||
tx.asset = 'btc';
|
tx.asset = 'btc';
|
||||||
if (type !== 'all')
|
if (propToCheck)
|
||||||
if (tx.type !== propToCheck)
|
if (tx.type !== propToCheck)
|
||||||
continue;
|
continue;
|
||||||
allTransactions.push(tx)
|
allTransactions.push(tx)
|
||||||
@ -4136,7 +4168,7 @@
|
|||||||
let d = {
|
let d = {
|
||||||
txid: tx.txid,
|
txid: tx.txid,
|
||||||
time: tx.time,
|
time: tx.time,
|
||||||
block: tx.block_no
|
block: tx.block
|
||||||
}
|
}
|
||||||
if (tx.outgoing) {
|
if (tx.outgoing) {
|
||||||
d.type = "out";
|
d.type = "out";
|
||||||
@ -4173,30 +4205,10 @@
|
|||||||
async function calculateBtcFees() {
|
async function calculateBtcFees() {
|
||||||
const [senders, privKeys, receivers, amounts] = await getTransactionInputs().catch(e => {
|
const [senders, privKeys, receivers, amounts] = await getTransactionInputs().catch(e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return [[], [], [], []]
|
return
|
||||||
});
|
});
|
||||||
if (!senders.length || !privKeys.length || !receivers.length || !amounts.length) return;
|
// if (!senders.length || !privKeys.length || !receivers.length || !amounts.length) return;
|
||||||
getRef('send_transaction').disabled = true;
|
return btcOperator.createSignedTx(senders, privKeys, receivers, amounts)
|
||||||
getRef('fees_section').classList.add('hidden')
|
|
||||||
getRef('error_section').classList.remove('hidden')
|
|
||||||
renderElem(getRef('error_section'), html`<div class="flex align-center gap-0-5" style="font-size:0.9rem"><sm-spinner></sm-spinner> Calculating fees...</div>`)
|
|
||||||
btcOperator.createSignedTx(senders, privKeys, receivers, amounts).then(({ fee }) => {
|
|
||||||
getRef('send_fee').value = fee.toFixed(8);
|
|
||||||
getRef('fees_section').classList.remove('hidden')
|
|
||||||
getRef('error_section').classList.add('hidden')
|
|
||||||
getRef('send_transaction').disabled = false;
|
|
||||||
}).catch(e => {
|
|
||||||
getRef('fees_section').classList.add('hidden')
|
|
||||||
getRef('error_section').classList.remove('hidden')
|
|
||||||
renderElem(getRef('error_section'), html`
|
|
||||||
<p id="selected_fee_tip" class="error flex align-center gap-0-5">
|
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M11 15h2v2h-2v-2zm0-8h2v6h-2V7zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></svg>
|
|
||||||
${e}
|
|
||||||
</p>
|
|
||||||
`)
|
|
||||||
getRef('send_transaction').disabled = true;
|
|
||||||
console.error(e)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
const txParticipantsObserver = new MutationObserver(mutations => {
|
const txParticipantsObserver = new MutationObserver(mutations => {
|
||||||
mutations.forEach(mutation => {
|
mutations.forEach(mutation => {
|
||||||
@ -4227,7 +4239,10 @@
|
|||||||
txParticipantsObserver.observe(getRef('receiver_container'), {
|
txParticipantsObserver.observe(getRef('receiver_container'), {
|
||||||
childList: true
|
childList: true
|
||||||
})
|
})
|
||||||
let globalExchangeRate = {}
|
let globalExchangeRate = {
|
||||||
|
btc: 1,
|
||||||
|
inr: 1
|
||||||
|
}
|
||||||
async function getExchangeRate() {
|
async function getExchangeRate() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
Promise.all(['usd', 'inr'].map(cur => fetch(`https://bitpay.com/api/rates/btc/${cur}`))).then(responses => {
|
Promise.all(['usd', 'inr'].map(cur => fetch(`https://bitpay.com/api/rates/btc/${cur}`))).then(responses => {
|
||||||
@ -4257,21 +4272,37 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
getRef('fees_selector').addEventListener('change', e => {
|
getRef('fees_selector').addEventListener('change', e => {
|
||||||
if (e.target.value !== 'custom') {
|
|
||||||
getRef('send_fee').readOnly = true;
|
|
||||||
}
|
|
||||||
switch (e.target.value) {
|
switch (e.target.value) {
|
||||||
case 'custom':
|
case 'custom':
|
||||||
getRef('send_fee').readOnly = false;
|
getRef('send_fee').readOnly = false;
|
||||||
|
getRef('send_fee').placeholder = 'Fee';
|
||||||
getRef('send_fee').focusIn();
|
getRef('send_fee').focusIn();
|
||||||
getRef('selected_fee_tip').textContent = 'Set custom fee';
|
renderElem(getRef('selected_fee_tip'), html`Set custom fee`)
|
||||||
break;
|
break;
|
||||||
case 'suggested':
|
case 'suggested':
|
||||||
getRef('selected_fee_tip').textContent = 'Estimated time of confirmation is 1hr'
|
calculateFees();
|
||||||
calculateBtcFees();
|
getRef('send_fee').readOnly = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
function calculateApproxFee() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch('https://bitcoiner.live/api/fees/estimates/latest')
|
||||||
|
.then(res => {
|
||||||
|
res.json()
|
||||||
|
.then(data => {
|
||||||
|
const satPerByte = data.estimates['60'].sat_per_vbyte;
|
||||||
|
const legacyBytes = 200;
|
||||||
|
const segwitBytes = 77;
|
||||||
|
resolve((legacyBytes * satPerByte + (0.25 * satPerByte) * segwitBytes) / Math.pow(10, 8));
|
||||||
|
}).catch(e => {
|
||||||
|
reject(e)
|
||||||
|
})
|
||||||
|
}).catch(e => {
|
||||||
|
reject(e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
async function getTransactionInputs() {
|
async function getTransactionInputs() {
|
||||||
const privateKey = await floDapps.user.private.catch(err => console.log(err));
|
const privateKey = await floDapps.user.private.catch(err => console.log(err));
|
||||||
const privKeys = btcOperator.convert.wif(privateKey);
|
const privKeys = btcOperator.convert.wif(privateKey);
|
||||||
@ -4283,14 +4314,58 @@
|
|||||||
return [senders, privKeys, receivers, amounts]
|
return [senders, privKeys, receivers, amounts]
|
||||||
}
|
}
|
||||||
|
|
||||||
getRef('receiver_container').addEventListener('input', debounce(e => {
|
getRef('receiver_container').addEventListener('input', debounce(calculateFees, 300))
|
||||||
|
|
||||||
|
function calculateFees() {
|
||||||
|
getRef('fees_selector').children[0].click();
|
||||||
|
getRef('fees_selector').classList.remove('hidden')
|
||||||
|
getRef('send_transaction').disabled = true;
|
||||||
|
getRef('send_fee').value = '';
|
||||||
|
getRef('send_fee_loader').classList.remove('hidden')
|
||||||
|
const animOptions = {
|
||||||
|
duration: 200,
|
||||||
|
easing: 'ease',
|
||||||
|
fill: 'forwards'
|
||||||
|
}
|
||||||
|
getRef('send_fee_loader').animate(fadeIn, animOptions)
|
||||||
|
getRef('fees_section').classList.remove('hidden')
|
||||||
|
getRef('error_section').classList.add('hidden')
|
||||||
const allValid = [...getRef('receiver_container').querySelectorAll('sm-input')].every(input => input.isValid)
|
const allValid = [...getRef('receiver_container').querySelectorAll('sm-input')].every(input => input.isValid)
|
||||||
if (allValid) {
|
if (allValid) {
|
||||||
calculateBtcFees()
|
getRef('send_fee').placeholder = 'Fee'
|
||||||
|
calculateBtcFees().then(({ fee }) => {
|
||||||
|
getRef('send_fee').value = fee.toFixed(8);
|
||||||
|
renderElem(getRef('selected_fee_tip'), html``)
|
||||||
|
getRef('send_transaction').disabled = false;
|
||||||
|
}).catch(e => {
|
||||||
|
getRef('fees_section').classList.add('hidden')
|
||||||
|
getRef('error_section').classList.remove('hidden')
|
||||||
|
renderElem(getRef('error_section'), html`
|
||||||
|
<p class="error flex align-center gap-0-5">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M11 15h2v2h-2v-2zm0-8h2v6h-2V7zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></svg>
|
||||||
|
${e}
|
||||||
|
</p>
|
||||||
|
`)
|
||||||
|
console.error(e)
|
||||||
|
}).finally(_ => {
|
||||||
|
getRef('send_fee_loader').animate(fadeOut, animOptions).onfinish = _ =>
|
||||||
|
getRef('send_fee_loader').classList.add('hidden')
|
||||||
|
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
getRef('send_transaction').disabled = true;
|
getRef('send_fee').placeholder = 'Approximate fee'
|
||||||
|
renderElem(getRef('selected_fee_tip'), html` <p style="opacity: 0.8;">*Fill out all fields for exact fee!</p> `)
|
||||||
|
calculateApproxFee().then(fee => {
|
||||||
|
getRef('send_fee').value = fee.toFixed(8);
|
||||||
|
}).catch(e => {
|
||||||
|
getRef('fees_selector').children[1].click();
|
||||||
|
getRef('fees_selector').classList.add('hidden')
|
||||||
|
}).finally(_ => {
|
||||||
|
getRef('send_fee_loader').animate(fadeOut, animOptions).onfinish = _ =>
|
||||||
|
getRef('send_fee_loader').classList.add('hidden')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, 300))
|
}
|
||||||
|
|
||||||
getRef('send_transaction').onclick = evt => {
|
getRef('send_transaction').onclick = evt => {
|
||||||
buttonLoader('send_transaction', true)
|
buttonLoader('send_transaction', true)
|
||||||
@ -4298,17 +4373,12 @@
|
|||||||
const [senders, privKeys, receivers, amounts] = await getTransactionInputs().catch(err => console.log(err));
|
const [senders, privKeys, receivers, amounts] = await getTransactionInputs().catch(err => console.log(err));
|
||||||
const fee = parseFloat(getRef('send_fee').value.trim());
|
const fee = parseFloat(getRef('send_fee').value.trim());
|
||||||
console.debug(senders, receivers, amounts, fee);
|
console.debug(senders, receivers, amounts, fee);
|
||||||
btcOperator.sendTx(senders, privKeys, receivers, amounts, fee).then(result => {
|
btcOperator.sendTx(senders, privKeys, receivers, amounts, fee).then(txid => {
|
||||||
console.log(result);
|
console.log(txid);
|
||||||
closePopup();
|
closePopup();
|
||||||
getRef('txid').value = result.txid;
|
getRef('txid').value = txid;
|
||||||
openPopup('txid_popup');
|
openPopup('txid_popup');
|
||||||
getRef('send_tx').reset()
|
getRef('send_tx').reset()
|
||||||
getExchangeRate().then(() => {
|
|
||||||
calculateBtcFees()
|
|
||||||
}).catch(e => {
|
|
||||||
console.error(e)
|
|
||||||
})
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
notify(`Error sending transaction \n ${error}`, 'error');
|
notify(`Error sending transaction \n ${error}`, 'error');
|
||||||
}).finally(_ => {
|
}).finally(_ => {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user