- Merged balance checking and transaction history into a single Transactions page. - Updated navigation links and icons for improved user experience. - Added search type selection for balance and transaction details. - Implemented URL management for sharing balance and transaction links. - Enhanced transaction search - Improved loading states and notifications for user actions.
1149 lines
45 KiB
HTML
1149 lines
45 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Tron Wallet</title>
|
|
<link rel="shortcut icon" href="favicon.svg" type="image/x-icon" />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
|
|
/>
|
|
<link rel="stylesheet" href="css/style.css" />
|
|
</head>
|
|
<body>
|
|
<header class="header">
|
|
<div class="header-content">
|
|
<div id="logo" class="app-brand">
|
|
<svg id="main_logo" class="icon" viewBox="0 0 27.25 32">
|
|
<title>RanchiMall</title>
|
|
<path
|
|
d="M27.14,30.86c-.74-2.48-3-4.36-8.25-6.94a20,20,0,0,1-4.2-2.49,6,6,0,0,1-1.25-1.67,4,4,0,0,1,0-2.26c.37-1.08.79-1.57,3.89-4.55a11.66,11.66,0,0,0,3.34-4.67,6.54,6.54,0,0,0,.05-2.82C20,3.6,18.58,2,16.16.49c-.89-.56-1.29-.64-1.3-.24a3,3,0,0,1-.3.72l-.3.55L13.42.94C13,.62,12.4.26,12.19.15c-.4-.2-.73-.18-.72.05a9.39,9.39,0,0,1-.61,1.33s-.14,0-.27-.13C8.76.09,8-.27,8,.23A11.73,11.73,0,0,1,6.76,2.6C4.81,5.87,2.83,7.49.77,7.49c-.89,0-.88,0-.61,1,.22.85.33.92,1.09.69A5.29,5.29,0,0,0,3,8.33c.23-.17.45-.29.49-.26a2,2,0,0,1,.22.63A1.31,1.31,0,0,0,4,9.34a5.62,5.62,0,0,0,2.27-.87L7,8l.13.55c.19.74.32.82,1,.65a7.06,7.06,0,0,0,3.46-2.47l.6-.71-.06.64c-.17,1.63-1.3,3.42-3.39,5.42L6.73,14c-3.21,3.06-3,5.59.6,8a46.77,46.77,0,0,0,4.6,2.41c.28.13,1,.52,1.59.87,3.31,2,4.95,3.92,4.95,5.93a2.49,2.49,0,0,0,.07.77h0c.09.09,0,.1.9-.14a2.61,2.61,0,0,0,.83-.32,3.69,3.69,0,0,0-.55-1.83A11.14,11.14,0,0,0,17,26.81a35.7,35.7,0,0,0-5.1-2.91C9.37,22.64,8.38,22,7.52,21.17a3.53,3.53,0,0,1-1.18-2.48c0-1.38.71-2.58,2.5-4.23,2.84-2.6,3.92-3.91,4.67-5.65a3.64,3.64,0,0,0,.42-2A3.37,3.37,0,0,0,13.61,5l-.32-.74.29-.48c.17-.27.37-.63.46-.8l.15-.3.44.64a5.92,5.92,0,0,1,1,2.81,5.86,5.86,0,0,1-.42,1.94c0,.12-.12.3-.15.4a9.49,9.49,0,0,1-.67,1.1,28,28,0,0,1-4,4.29C8.62,15.49,8.05,16.44,8,17.78a3.28,3.28,0,0,0,1.11,2.76c.95,1,2.07,1.74,5.25,3.32,3.64,1.82,5.22,2.9,6.41,4.38A4.78,4.78,0,0,1,21.94,31a3.21,3.21,0,0,0,.14.92,1.06,1.06,0,0,0,.43-.05l.83-.22.46-.12-.06-.46c-.21-1.53-1.62-3.25-3.94-4.8a37.57,37.57,0,0,0-5.22-2.82A13.36,13.36,0,0,1,11,21.19a3.36,3.36,0,0,1-.8-4.19c.41-.85.83-1.31,3.77-4.15,2.39-2.31,3.43-4.13,3.43-6a5.85,5.85,0,0,0-2.08-4.29c-.23-.21-.44-.43-.65-.65A2.5,2.5,0,0,1,15.27.69a10.6,10.6,0,0,1,2.91,2.78A4.16,4.16,0,0,1,19,6.16a4.91,4.91,0,0,1-.87,3c-.71,1.22-1.26,1.82-4.27,4.67a9.47,9.47,0,0,0-2.07,2.6,2.76,2.76,0,0,0-.33,1.54,2.76,2.76,0,0,0,.29,1.47c.57,1.21,2.23,2.55,4.65,3.73a32.41,32.41,0,0,1,5.82,3.24c2.16,1.6,3.2,3.16,3.2,4.8a1.94,1.94,0,0,0,.09.76,4.54,4.54,0,0,0,1.66-.4C27.29,31.42,27.29,31.37,27.14,30.86ZM6.1,7h0a3.77,3.77,0,0,1-1.46.45L4,7.51l.68-.83a25.09,25.09,0,0,0,3-4.82A12,12,0,0,1,8.28.76c.11-.12.77.32,1.53,1l.63.58-.57.84A10.34,10.34,0,0,1,6.1,7Zm5.71-1.78A9.77,9.77,0,0,1,9.24,7.18h0a5.25,5.25,0,0,1-1.17.28l-.58,0,.65-.78a21.29,21.29,0,0,0,2.1-3.12c.22-.41.42-.76.44-.79s.5.43.9,1.24L12,5ZM13.41,3a2.84,2.84,0,0,1-.45.64,11,11,0,0,1-.9-.91l-.84-.9.19-.45c.34-.79.39-.8,1-.31A9.4,9.4,0,0,1,13.8,2.33q-.18.34-.39.69Z"
|
|
/>
|
|
</svg>
|
|
<div class="app-name">
|
|
<div class="app-name__company">RanchiMall</div>
|
|
<h4 class="app-name__title">Tron Wallet</h4>
|
|
</div>
|
|
</div>
|
|
<div class="header-actions">
|
|
<button
|
|
id="themeToggle"
|
|
class="theme-toggle"
|
|
title="Toggle dark/light mode"
|
|
>
|
|
<i class="fas fa-sun" id="themeIcon"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
<div class="container">
|
|
<nav class="sidebar" id="sidebar">
|
|
<div class="sidebar-header">
|
|
<i class="fas fa-wallet"></i>
|
|
<h3>Tron Wallet</h3>
|
|
</div>
|
|
<ul class="sidebar-menu">
|
|
<li>
|
|
<a href="#" onclick="showPage('walletPage')" class="nav-link active"
|
|
><i class="fas fa-wallet"></i>Generate</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="#" onclick="showPage('sendPage')" class="nav-link"
|
|
><i class="fas fa-paper-plane"></i>Send</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="#" onclick="showPage('transactionsPage')" class="nav-link"
|
|
><i class="fas fa-arrows-rotate"></i>Transactions</a
|
|
>
|
|
</li>
|
|
<li>
|
|
<a href="#" onclick="showPage('recoverPage')" class="nav-link"
|
|
><i class="fas fa-key"></i>Recover</a
|
|
>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
<main class="main-content">
|
|
<!-- Wallet Page -->
|
|
<div id="walletPage" class="page">
|
|
<div class="page-header">
|
|
<h2>
|
|
<i class="fas fa-key"></i> Generate Multi-Blockchain Addresses
|
|
</h2>
|
|
<p>
|
|
Generate addresses for TRON, FLO, and Bitcoin from a single
|
|
private key
|
|
</p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="generate-wallet-intro">
|
|
<div class="intro-content">
|
|
<h3>One Key, Multiple Blockchains</h3>
|
|
<p>
|
|
Generate a single private key that works across TRON, FLO, and
|
|
Bitcoin networks. This creates a unified experience across
|
|
multiple blockchains.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="generate-actions">
|
|
<button
|
|
id="generateBtn"
|
|
class="btn btn-primary btn-block"
|
|
onclick="runWalletTest()"
|
|
>
|
|
<span class="btn-text"> Generate </span>
|
|
<span class="btn-loading" style="display: none">
|
|
<i class="fas fa-spinner fa-spin"></i> Generating...
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div id="walletOutput"></div>
|
|
</div>
|
|
</div>
|
|
<!-- Send Page -->
|
|
<div id="sendPage" class="page hidden">
|
|
<div class="page-header">
|
|
<h2><i class="fas fa-paper-plane"></i> Send TRX</h2>
|
|
</div>
|
|
|
|
<div class="send-intro">
|
|
<div class="intro-content">
|
|
<h3>Send TRX Transaction</h3>
|
|
<p>Enter your private key and recipient details to send TRX.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="form-group">
|
|
<label
|
|
><i class="fas fa-key"></i> Private Key (TRX/FLO/BTC):</label
|
|
>
|
|
<div class="input-with-actions">
|
|
<input
|
|
id="privKey"
|
|
class="form-input"
|
|
type="password"
|
|
placeholder="Enter your private key (Tron hex or BTC/FLO WIF)"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn password-toggle"
|
|
onclick="togglePrivateKeyVisibility('privKey')"
|
|
title="Show/Hide Password"
|
|
>
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn clear-btn"
|
|
onclick="clearInput('privKey')"
|
|
title="Clear"
|
|
>
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<small class="form-help"
|
|
>Your sender address will be automatically derived from this
|
|
private key</small
|
|
>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label><i class="fas fa-map-marker-alt"></i> To Address:</label>
|
|
<div class="input-with-actions">
|
|
<input
|
|
id="toAddr"
|
|
class="form-input"
|
|
placeholder="Enter recipient Tron address"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn clear-btn"
|
|
onclick="clearInput('toAddr')"
|
|
title="Clear"
|
|
>
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label><i class="fas fa-coins"></i> Amount (TRX):</label>
|
|
<div class="input-with-actions">
|
|
<input
|
|
id="amount"
|
|
class="form-input"
|
|
type="number"
|
|
step="0.000001"
|
|
placeholder="Enter amount in TRX"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn clear-btn"
|
|
onclick="clearInput('amount')"
|
|
title="Clear"
|
|
>
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<small class="form-help">Minimum amount: 0.000001 TRX</small>
|
|
</div>
|
|
|
|
<div class="send-actions">
|
|
<button
|
|
class="btn btn-primary btn-block"
|
|
onclick="openSendConfirm()"
|
|
id="sendBtn"
|
|
>
|
|
<span class="btn-text"
|
|
><i class="fas fa-paper-plane"></i> Send TRX</span
|
|
>
|
|
<span class="btn-loading" style="display: none">
|
|
<i class="fas fa-spinner fa-spin"></i> Sending...
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div id="sendOutput"></div>
|
|
</div>
|
|
</div>
|
|
<!-- Transactions Page (Merged Balance + History + TX Search) -->
|
|
<div id="transactionsPage" class="page hidden">
|
|
<div class="page-header">
|
|
<h2><i class="fas fa-arrows-rotate"></i> Transactions</h2>
|
|
<p>Check balance, browse history, and search by transaction hash</p>
|
|
</div>
|
|
|
|
<!-- Balance Card -->
|
|
<div class="card">
|
|
<div class="search-type-section">
|
|
<label class="search-type-label">Search Type:</label>
|
|
<div class="search-type-buttons">
|
|
<button
|
|
class="search-type-btn active"
|
|
data-type="balance"
|
|
onclick="setSearchType('balance')"
|
|
>
|
|
<i class="fas fa-wallet"></i> Balance & History
|
|
</button>
|
|
<button
|
|
class="search-type-btn"
|
|
data-type="transaction"
|
|
onclick="setSearchType('transaction')"
|
|
>
|
|
<i class="fas fa-file-alt"></i> Transaction Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label
|
|
><i class="fas fa-map-marker-alt"></i> Tron Address / Private
|
|
Key (FLO/BTC):</label
|
|
>
|
|
<div class="input-with-actions">
|
|
<input
|
|
id="balanceAddr"
|
|
class="form-input"
|
|
placeholder="Enter Tron address / Private Key"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn clear-btn"
|
|
onclick="clearInput('balanceAddr')"
|
|
title="Clear"
|
|
>
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<small class="form-help"
|
|
>Enter an address, private key (BTC/FLO), or Tron hex to check
|
|
balance.</small
|
|
>
|
|
</div>
|
|
|
|
<button
|
|
class="btn btn-primary btn-block"
|
|
onclick="runBalanceCheck()"
|
|
id="balanceBtn"
|
|
>
|
|
<span class="btn-text"
|
|
><i class="fas fa-search"></i> Check Balance</span
|
|
>
|
|
<span class="btn-loading" style="display: none">
|
|
<i class="fas fa-spinner fa-spin"></i> Loading...
|
|
</span>
|
|
</button>
|
|
<div id="balanceOutput"></div>
|
|
</div>
|
|
|
|
<!-- TX Search Card -->
|
|
<div class="card">
|
|
<div class="search-type-section">
|
|
<label class="search-type-label">Search Type:</label>
|
|
<div class="search-type-buttons">
|
|
<button
|
|
class="search-type-btn"
|
|
data-type="balance"
|
|
onclick="setSearchType('balance')"
|
|
>
|
|
<i class="fas fa-wallet"></i> Balance & History
|
|
</button>
|
|
<button
|
|
class="search-type-btn active"
|
|
data-type="transaction"
|
|
onclick="setSearchType('transaction')"
|
|
>
|
|
<i class="fas fa-file-alt"></i> Transaction Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label
|
|
><i class="fas fa-file-alt"></i> Transaction Hash (TX
|
|
ID):</label
|
|
>
|
|
<div class="input-with-actions">
|
|
<input
|
|
id="txHash"
|
|
class="form-input"
|
|
placeholder="Enter transaction hash (TX ID)"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn clear-btn"
|
|
onclick="clearInput('txHash')"
|
|
title="Clear"
|
|
>
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<small class="form-help"
|
|
>Enter a transaction hash to view transaction details.</small
|
|
>
|
|
</div>
|
|
|
|
<button
|
|
class="btn btn-primary btn-block"
|
|
onclick="runTxSearch()"
|
|
id="txSearchBtn"
|
|
>
|
|
<span class="btn-text"
|
|
><i class="fas fa-search"></i> View Transaction</span
|
|
>
|
|
<span class="btn-loading" style="display: none">
|
|
<i class="fas fa-spinner fa-spin"></i> Searching...
|
|
</span>
|
|
</button>
|
|
<div id="txOutput"></div>
|
|
</div>
|
|
|
|
<div
|
|
id="transactionSection"
|
|
class="card transaction-section"
|
|
style="display: none"
|
|
>
|
|
<div id="transactionControls" class="transaction-controls">
|
|
<div class="transaction-header">
|
|
<h3>Transactions</h3>
|
|
<div class="filter-buttons">
|
|
<button
|
|
class="filter-btn active"
|
|
data-filter="all"
|
|
onclick="setTransactionFilter('all')"
|
|
>
|
|
<i class="fas fa-list"></i> All
|
|
</button>
|
|
<button
|
|
class="filter-btn"
|
|
data-filter="received"
|
|
onclick="setTransactionFilter('received')"
|
|
>
|
|
<i class="fas fa-arrow-down"></i> Received
|
|
</button>
|
|
<button
|
|
class="filter-btn"
|
|
data-filter="sent"
|
|
onclick="setTransactionFilter('sent')"
|
|
>
|
|
<i class="fas fa-arrow-up"></i> Sent
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="txList" class="transaction-list"></div>
|
|
<div class="pagination-section">
|
|
<div class="pagination-info" id="paginationInfo">
|
|
Showing 0 - 0 of 0 transactions
|
|
</div>
|
|
<div class="pagination-controls">
|
|
<button
|
|
class="pagination-btn"
|
|
id="prevBtn"
|
|
onclick="goToPreviousPage()"
|
|
disabled
|
|
>
|
|
<i class="fas fa-chevron-left"></i>
|
|
</button>
|
|
<div class="page-numbers" id="pageNumbers"></div>
|
|
<button
|
|
class="pagination-btn"
|
|
id="nextBtn"
|
|
onclick="goToNextPage()"
|
|
disabled
|
|
>
|
|
<i class="fas fa-chevron-right"></i>
|
|
</button>
|
|
<select
|
|
id="perPageSelect"
|
|
class="pagination-btn"
|
|
style="min-width: 90px"
|
|
>
|
|
<option value="10">10 / page</option>
|
|
<option value="20">20 / page</option>
|
|
<option value="50">50 / page</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Recover Page -->
|
|
<div id="recoverPage" class="page hidden">
|
|
<div class="page-header">
|
|
<h2>
|
|
<i class="fas fa-key"></i> Recover Multi-Blockchain Addresses
|
|
</h2>
|
|
<p>
|
|
Recover all blockchain addresses (TRON, FLO, Bitcoin) from a
|
|
single private key
|
|
</p>
|
|
</div>
|
|
<div class="card">
|
|
<div class="form-group">
|
|
<label
|
|
><i class="fas fa-key"></i> Private Key (TRX/FLO/BTC):</label
|
|
>
|
|
<div class="input-with-actions">
|
|
<input
|
|
id="recoveryPrivKey"
|
|
class="form-input"
|
|
type="password"
|
|
placeholder="Enter your private key (Tron hex or BTC/FLO WIF)"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn password-toggle"
|
|
onclick="togglePrivateKeyVisibility('recoveryPrivKey')"
|
|
title="Show/Hide Password"
|
|
>
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="input-action-btn clear-btn"
|
|
onclick="clearInput('recoveryPrivKey')"
|
|
title="Clear"
|
|
>
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="recover-actions">
|
|
<button
|
|
class="btn btn-primary btn-block"
|
|
onclick="runAddressRecovery()"
|
|
id="recoverBtn"
|
|
>
|
|
<span class="btn-text"
|
|
><i class="fas fa-search"></i> Recover All Addresses</span
|
|
>
|
|
<span class="btn-loading" style="display: none">
|
|
<i class="fas fa-spinner fa-spin"></i> Recovering...
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div id="recoveryOutput"></div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
<!-- Confirmation Popup for Send TRX -->
|
|
<sm-popup id="sendConfirm">
|
|
<div class="modern-popup-container">
|
|
<div class="popup-header">
|
|
<div class="popup-icon confirm-icon">
|
|
<i class="fas fa-shield-alt"></i>
|
|
</div>
|
|
<h2 class="popup-title">Confirm Transaction</h2>
|
|
<p class="popup-subtitle">
|
|
Please review the transaction details before sending
|
|
</p>
|
|
</div>
|
|
<div class="transaction-summary">
|
|
<div class="summary-item amount-highlight">
|
|
<div class="summary-icon"><i class="fas fa-coins"></i></div>
|
|
<div class="summary-content">
|
|
<span class="summary-label">Amount to Send</span>
|
|
<span class="summary-value" id="confirmAmount">0 TRX</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon"><i class="fas fa-user-minus"></i></div>
|
|
<div class="summary-content">
|
|
<span class="summary-label">From</span>
|
|
<span class="summary-value address-text" id="confirmFrom">-</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon"><i class="fas fa-user-plus"></i></div>
|
|
<div class="summary-content">
|
|
<span class="summary-label">To</span>
|
|
<span class="summary-value address-text" id="confirmTo">-</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="summary-icon"><i class="fas fa-receipt"></i></div>
|
|
<div class="summary-content">
|
|
<span class="summary-label">Network Fee</span>
|
|
<span class="summary-value" id="confirmFee">~0.000001 TRX</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="popup-actions modern-actions">
|
|
<button onclick="closePopup('sendConfirm')" class="btn btn-cancel">
|
|
<i class="fas fa-times"></i><span>Cancel</span>
|
|
</button>
|
|
<button onclick="confirmSendTrx()" class="btn btn-confirm">
|
|
<i class="fas fa-paper-plane"></i><span>Confirm</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</sm-popup>
|
|
<!-- Success Popup -->
|
|
<sm-popup id="transactionSuccess">
|
|
<div class="modern-popup-container success-popup">
|
|
<div class="popup-header success-header">
|
|
<div class="popup-icon success-icon">
|
|
<i class="fas fa-check-circle"></i>
|
|
</div>
|
|
<h2 class="popup-title">Transaction Successful!</h2>
|
|
<p class="popup-subtitle">Your TRX has been sent successfully</p>
|
|
</div>
|
|
<div class="success-details">
|
|
<div class="success-summary">
|
|
<div class="success-item">
|
|
<span class="success-label">Amount Sent</span
|
|
><span class="success-value" id="successAmount">0 TRX</span>
|
|
</div>
|
|
<div class="success-item">
|
|
<span class="success-label">Network Fee</span
|
|
><span class="success-value" id="successFee">0 TRX</span>
|
|
</div>
|
|
</div>
|
|
<div class="transaction-details">
|
|
<div class="detail-row">
|
|
<span class="detail-label"
|
|
><i class="fas fa-hashtag"></i> Hash</span
|
|
><span class="detail-value" id="successHash">-</span>
|
|
</div>
|
|
<div class="detail-row">
|
|
<span class="detail-label"
|
|
><i class="fas fa-user-minus"></i> From</span
|
|
><span class="detail-value" id="successFrom">-</span>
|
|
</div>
|
|
<div class="detail-row">
|
|
<span class="detail-label"
|
|
><i class="fas fa-user-plus"></i> To</span
|
|
><span class="detail-value" id="successTo">-</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="popup-actions modern-actions">
|
|
<button
|
|
onclick="closePopup('transactionSuccess')"
|
|
class="btn btn-done"
|
|
>
|
|
<i class="fas fa-check"></i><span>Done</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</sm-popup>
|
|
<!-- Bottom Navigation (Mobile) -->
|
|
<div class="nav-box">
|
|
<button
|
|
onclick="showPage('walletPage')"
|
|
class="nav-btn active"
|
|
data-page="walletPage"
|
|
>
|
|
<i class="fas fa-wallet"></i><span>Generate</span>
|
|
</button>
|
|
<button
|
|
onclick="showPage('sendPage')"
|
|
class="nav-btn"
|
|
data-page="sendPage"
|
|
>
|
|
<i class="fas fa-paper-plane"></i><span>Send</span>
|
|
</button>
|
|
<button
|
|
onclick="showPage('transactionsPage')"
|
|
class="nav-btn"
|
|
data-page="transactionsPage"
|
|
>
|
|
<i class="fas fa-arrows-rotate"></i><span>Transactions</span>
|
|
</button>
|
|
<button
|
|
onclick="showPage('recoverPage')"
|
|
class="nav-btn"
|
|
data-page="recoverPage"
|
|
>
|
|
<i class="fas fa-key"></i><span>Recover</span>
|
|
</button>
|
|
</div>
|
|
<!-- Scripts -->
|
|
<script src="https://cdn.jsdelivr.net/npm/tronweb@5.3.2/dist/TronWeb.js"></script>
|
|
<script src="./scripts/btcwallet_scripts_lib.js"></script>
|
|
<script src="./scripts/btcOperator.js"></script>
|
|
<script src="./scripts/floCrypto.js"></script>
|
|
<script src="./scripts/components.min.js"></script>
|
|
<script src="./scripts/genMultichainAddress.js"></script>
|
|
<script src="./scripts/transactionHistory.js"></script>
|
|
<script src="./scripts/sendTRX.js"></script>
|
|
<script src="./scripts/recoverAddress.js"></script>
|
|
<script src="./scripts/balance.js"></script>
|
|
<script>
|
|
// Theme toggle
|
|
function initializeTheme() {
|
|
const themeToggle = document.getElementById("themeToggle");
|
|
const body = document.body;
|
|
const savedTheme = localStorage.getItem("theme");
|
|
const systemPrefersDark = window.matchMedia(
|
|
"(prefers-color-scheme: dark)"
|
|
).matches;
|
|
let currentTheme = savedTheme || (systemPrefersDark ? "dark" : "light");
|
|
body.setAttribute("data-theme", currentTheme);
|
|
updateThemeIcon(currentTheme);
|
|
if (themeToggle) {
|
|
themeToggle.addEventListener("click", () => {
|
|
currentTheme = currentTheme === "light" ? "dark" : "light";
|
|
body.setAttribute("data-theme", currentTheme);
|
|
localStorage.setItem("theme", currentTheme);
|
|
updateThemeIcon(currentTheme);
|
|
if (typeof notify === "function") {
|
|
notify(`Switched to ${currentTheme} mode`, "success");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
function updateThemeIcon(theme) {
|
|
const themeIcon = document.getElementById("themeIcon");
|
|
if (!themeIcon) return;
|
|
themeIcon.className = theme === "dark" ? "fas fa-sun" : "fas fa-moon";
|
|
}
|
|
|
|
function notify(message, type = "success", durationMs = 3000) {
|
|
const drawer = document.getElementById("notification_drawer");
|
|
if (!drawer) return;
|
|
const note = document.createElement("div");
|
|
note.className = `notification ${type}`;
|
|
note.style.animation = "slideInRight 250ms ease-out";
|
|
note.innerHTML = `<span>${message}</span>`;
|
|
drawer.appendChild(note);
|
|
const remove = () => {
|
|
note.style.animation = "slideOutRight 200ms ease-in forwards";
|
|
setTimeout(() => note.remove(), 200);
|
|
};
|
|
setTimeout(remove, durationMs);
|
|
note.addEventListener("click", remove);
|
|
}
|
|
|
|
// Send TRX confirmation flow
|
|
function openSendConfirm() {
|
|
const privateKey = document.getElementById("privKey").value.trim();
|
|
const to = document.getElementById("toAddr").value.trim();
|
|
const amount = document.getElementById("amount").value.trim();
|
|
|
|
if (!privateKey || !to || !amount) {
|
|
if (typeof notify === "function") {
|
|
notify("Please fill all required fields", "error");
|
|
} else {
|
|
alert("Please fill Private Key, To Address and Amount");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Validate private key format
|
|
if (
|
|
!/^[0-9a-fA-F]{64}$/.test(privateKey) &&
|
|
!/^[5KLc9RQ][1-9A-HJ-NP-Za-km-z]{50,}$/.test(privateKey)
|
|
) {
|
|
if (typeof notify === "function") {
|
|
notify("Invalid private key format", "error");
|
|
} else {
|
|
alert("Invalid private key format");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Derive from address from private key
|
|
let fromAddress;
|
|
try {
|
|
if (/^[5KLc9RQ][1-9A-HJ-NP-Za-km-z]{50,}$/.test(privateKey)) {
|
|
// WIF format - convert to hex first
|
|
const decoded = coinjs.wif2privkey(privateKey);
|
|
if (!decoded || !decoded.privkey) {
|
|
if (typeof notify === "function") {
|
|
notify("Invalid WIF private key", "error");
|
|
} else {
|
|
alert("Invalid WIF private key");
|
|
}
|
|
return;
|
|
}
|
|
fromAddress = tronWeb.address.fromPrivateKey(decoded.privkey);
|
|
} else {
|
|
// Hex format
|
|
fromAddress = tronWeb.address.fromPrivateKey(privateKey);
|
|
}
|
|
} catch (error) {
|
|
if (typeof notify === "function") {
|
|
notify("Error deriving address from private key", "error");
|
|
} else {
|
|
alert("Error deriving address from private key");
|
|
}
|
|
return;
|
|
}
|
|
|
|
document.getElementById("confirmFrom").textContent = fromAddress;
|
|
document.getElementById("confirmTo").textContent = to;
|
|
document.getElementById("confirmAmount").textContent = amount + " TRX";
|
|
openPopup("sendConfirm");
|
|
}
|
|
function confirmSendTrx() {
|
|
closePopup("sendConfirm");
|
|
|
|
// Set loading state
|
|
setButtonLoading("sendBtn", true);
|
|
|
|
// Call existing sender
|
|
sendTrx()
|
|
.then((receipt) => {
|
|
try {
|
|
if (receipt && typeof receipt === "object") {
|
|
const to = document.getElementById("toAddr").value.trim();
|
|
const amount = document.getElementById("amount").value.trim();
|
|
const privateKey = document
|
|
.getElementById("privKey")
|
|
.value.trim();
|
|
|
|
// Derive from address from private key for confirmation popup
|
|
let fromAddress;
|
|
if (/^[5KLc9RQ][1-9A-HJ-NP-Za-km-z]{50,}$/.test(privateKey)) {
|
|
// WIF format - convert to hex first
|
|
const decoded = coinjs.wif2privkey(privateKey);
|
|
if (decoded && decoded.privkey) {
|
|
fromAddress = tronWeb.address.fromPrivateKey(
|
|
decoded.privkey
|
|
);
|
|
}
|
|
} else if (/^[0-9a-fA-F]{64}$/.test(privateKey)) {
|
|
// Hex format
|
|
fromAddress = tronWeb.address.fromPrivateKey(privateKey);
|
|
}
|
|
|
|
document.getElementById("successAmount").textContent =
|
|
amount + " TRX";
|
|
document.getElementById("successFee").textContent = "~0 TRX";
|
|
document.getElementById("successFrom").textContent =
|
|
fromAddress || "—";
|
|
document.getElementById("successTo").textContent = to;
|
|
document.getElementById("successHash").textContent =
|
|
receipt.txid || "—";
|
|
openPopup("transactionSuccess");
|
|
if (typeof notify === "function")
|
|
notify("Transaction broadcasted", "success");
|
|
}
|
|
} catch (e) {}
|
|
})
|
|
.catch(() => {})
|
|
.finally(() => {
|
|
// Clear loading state
|
|
setButtonLoading("sendBtn", false);
|
|
});
|
|
}
|
|
function openPopup(id) {
|
|
const el = document.getElementById(id);
|
|
if (el && el.show) el.show();
|
|
else if (el && el.open) el.open();
|
|
else if (el) el.setAttribute("open", "");
|
|
}
|
|
function closePopup(id) {
|
|
const el = document.getElementById(id);
|
|
if (el && el.hide) el.hide();
|
|
else if (el && el.close) el.close();
|
|
else if (el) el.removeAttribute("open");
|
|
}
|
|
function showPage(pageId) {
|
|
document
|
|
.querySelectorAll(".page")
|
|
.forEach((page) => page.classList.add("hidden"));
|
|
document.getElementById(pageId).classList.remove("hidden");
|
|
document
|
|
.querySelectorAll(".sidebar .nav-link")
|
|
.forEach((link) => link.classList.remove("active"));
|
|
document
|
|
.querySelectorAll(".nav-btn")
|
|
.forEach((btn) => btn.classList.remove("active"));
|
|
const sidebarLink = document.querySelector(
|
|
`.sidebar .nav-link[onclick*="${pageId}"]`
|
|
);
|
|
if (sidebarLink) sidebarLink.classList.add("active");
|
|
const navBtn = document.querySelector(
|
|
`.nav-btn[data-page="${pageId}"]`
|
|
);
|
|
if (navBtn) navBtn.classList.add("active");
|
|
}
|
|
// Wallet generation
|
|
async function runWalletTest() {
|
|
const out = document.getElementById("walletOutput");
|
|
|
|
// Set loading state
|
|
setButtonLoading("generateBtn", true);
|
|
|
|
// Show notification
|
|
if (typeof notify === "function") {
|
|
notify("Generating...", "success", 1500);
|
|
}
|
|
|
|
try {
|
|
const tronWallet = await generateTronWallet();
|
|
const floWallet = generateFLOFromPrivateKey(tronWallet.privateKey);
|
|
const btcWallet = generateBTCFromPrivateKey(tronWallet.privateKey);
|
|
|
|
out.innerHTML = `
|
|
<div class="wallet-generated-success">
|
|
<div class="success-header">
|
|
<div class="success-icon">
|
|
<i class="fas fa-check-circle"></i>
|
|
</div>
|
|
<h3>Addresses Generated Successfully!</h3>
|
|
<p>Your multi-blockchain addresses have been created. All addresses are derived from the same private key.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="blockchain-section">
|
|
<div class="blockchain-header">
|
|
<h4><i class="fas fa-coins"></i> TRON (TRX)</h4>
|
|
<div class="blockchain-badge primary">Primary</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<label><i class="fas fa-map-marker-alt"></i> TRON Address</label>
|
|
<div class="value-container">
|
|
<code>${tronWallet.address}</code>
|
|
<button class="btn-icon" onclick="navigator.clipboard.writeText('${
|
|
tronWallet.address
|
|
}').then(()=>notify && notify('TRON address copied','success'))" title="Copy TRON Address">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<label><i class="fas fa-key"></i> TRON Private Key</label>
|
|
<div class="value-container">
|
|
<code>${tronWallet.privateKey}</code>
|
|
<button class="btn-icon" onclick="navigator.clipboard.writeText('${
|
|
tronWallet.privateKey
|
|
}').then(()=>notify && notify('Private key copied','success'))" title="Copy Private Key">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
${
|
|
floWallet
|
|
? `
|
|
<div class="blockchain-section">
|
|
<div class="blockchain-header">
|
|
<h4><i class="fas fa-coins"></i> FLO</h4>
|
|
<div class="blockchain-badge secondary">Secondary</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<label><i class="fas fa-map-marker-alt"></i> FLO Address</label>
|
|
<div class="value-container">
|
|
<code>${floWallet.address}</code>
|
|
<button class="btn-icon" onclick="navigator.clipboard.writeText('${floWallet.address}').then(()=>notify && notify('FLO address copied','success'))" title="Copy FLO Address">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<label><i class="fas fa-key"></i> FLO Private Key</label>
|
|
<div class="value-container">
|
|
<code>${floWallet.privateKey}</code>
|
|
<button class="btn-icon" onclick="navigator.clipboard.writeText('${floWallet.privateKey}').then(()=>notify && notify('Private key copied','success'))" title="Copy Private Key">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>`
|
|
: ""
|
|
}
|
|
|
|
${
|
|
btcWallet
|
|
? `
|
|
<div class="blockchain-section">
|
|
<div class="blockchain-header">
|
|
<h4><i class="fab fa-btc"></i> Bitcoin (BTC)</h4>
|
|
<div class="blockchain-badge secondary">Secondary</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<label><i class="fas fa-map-marker-alt"></i> BTC Address</label>
|
|
<div class="value-container">
|
|
<code>${btcWallet.address}</code>
|
|
<button class="btn-icon" onclick="navigator.clipboard.writeText('${btcWallet.address}').then(()=>notify && notify('BTC address copied','success'))" title="Copy BTC Address">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="detail-row">
|
|
<label><i class="fas fa-key"></i> BTC Private Key</label>
|
|
<div class="value-container">
|
|
<code>${btcWallet.privateKey}</code>
|
|
<button class="btn-icon" onclick="navigator.clipboard.writeText('${btcWallet.privateKey}').then(()=>notify && notify('Private key copied','success'))" title="Copy Private Key">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>`
|
|
: ""
|
|
}
|
|
|
|
<div class="wallet-security-notice">
|
|
<div class="notice-icon">
|
|
<i class="fas fa-shield-alt"></i>
|
|
</div>
|
|
<div class="notice-content">
|
|
<h4>Security Reminder</h4>
|
|
<p>Keep your private key safe and secure. Never share it with anyone. Consider backing it up in a secure location.</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Show success notification
|
|
if (typeof notify === "function") {
|
|
notify("Addresses generated successfully!", "success");
|
|
}
|
|
} catch (err) {
|
|
out.innerHTML = `
|
|
<div class="error-state">
|
|
<div class="error-icon">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
</div>
|
|
<h3>Generation Failed</h3>
|
|
<p>Error: ${err.message}</p>
|
|
<button class="btn btn-secondary" onclick="runWalletTest()">
|
|
<i class="fas fa-redo"></i> Try Again
|
|
</button>
|
|
</div>
|
|
`;
|
|
|
|
// Show error notification
|
|
if (typeof notify === "function") {
|
|
notify(err.message, "error");
|
|
}
|
|
} finally {
|
|
// Clear loading state
|
|
setButtonLoading("generateBtn", false);
|
|
}
|
|
}
|
|
// Loading state management functions
|
|
function setButtonLoading(buttonId, isLoading) {
|
|
const button = document.getElementById(buttonId);
|
|
if (!button) return;
|
|
|
|
const btnText = button.querySelector(".btn-text");
|
|
const btnLoading = button.querySelector(".btn-loading");
|
|
|
|
if (isLoading) {
|
|
button.disabled = true;
|
|
if (btnText) btnText.style.display = "none";
|
|
if (btnLoading) btnLoading.style.display = "inline";
|
|
} else {
|
|
button.disabled = false;
|
|
if (btnText) btnText.style.display = "inline";
|
|
if (btnLoading) btnLoading.style.display = "none";
|
|
}
|
|
}
|
|
|
|
// Private key visibility toggle function
|
|
function togglePrivateKeyVisibility(inputId) {
|
|
const input = document.getElementById(inputId);
|
|
const toggleBtn =
|
|
input.parentElement.querySelector(".password-toggle i");
|
|
|
|
if (input.type === "password") {
|
|
input.type = "text";
|
|
toggleBtn.className = "fas fa-eye-slash";
|
|
toggleBtn.parentElement.title = "Hide Password";
|
|
} else {
|
|
input.type = "password";
|
|
toggleBtn.className = "fas fa-eye";
|
|
toggleBtn.parentElement.title = "Show Password";
|
|
}
|
|
}
|
|
|
|
// Clear input function
|
|
function clearInput(inputId) {
|
|
const input = document.getElementById(inputId);
|
|
input.value = "";
|
|
input.focus();
|
|
|
|
// Clear corresponding output areas based on input field
|
|
switch (inputId) {
|
|
case "privKey":
|
|
case "toAddr":
|
|
case "amount":
|
|
// Clear send page output
|
|
const sendOutput = document.getElementById("sendOutput");
|
|
if (sendOutput) sendOutput.innerHTML = "";
|
|
break;
|
|
case "historyAddr":
|
|
// Clear history page output
|
|
const transactionSection =
|
|
document.getElementById("transactionSection");
|
|
if (transactionSection) transactionSection.style.display = "none";
|
|
break;
|
|
case "recoveryPrivKey":
|
|
// Clear recover page output
|
|
const recoveryOutput = document.getElementById("recoveryOutput");
|
|
if (recoveryOutput) recoveryOutput.innerHTML = "";
|
|
break;
|
|
case "balanceAddr":
|
|
// Clear balance page output
|
|
const balanceOutput = document.getElementById("balanceOutput");
|
|
if (balanceOutput) balanceOutput.innerHTML = "";
|
|
break;
|
|
case "txHash":
|
|
// Clear tx search output
|
|
const txOutput = document.getElementById("txOutput");
|
|
if (txOutput) txOutput.innerHTML = "";
|
|
break;
|
|
}
|
|
|
|
// Show notification
|
|
if (typeof notify === "function") {
|
|
notify("Input cleared", "success", 1000);
|
|
}
|
|
}
|
|
|
|
// Search type management
|
|
let __currentSearchType = "balance";
|
|
function setSearchType(type) {
|
|
__currentSearchType = type;
|
|
|
|
document.querySelectorAll(".search-type-btn").forEach((btn) => {
|
|
btn.classList.remove("active");
|
|
});
|
|
document.querySelectorAll(`[data-type="${type}"]`).forEach((btn) => {
|
|
btn.classList.add("active");
|
|
});
|
|
|
|
// Show/hide cards based on search type
|
|
const balanceCard = document
|
|
.querySelector("#balanceOutput")
|
|
.closest(".card");
|
|
const txCard = document.querySelector("#txOutput").closest(".card");
|
|
|
|
if (type === "balance") {
|
|
if (balanceCard) balanceCard.style.display = "block";
|
|
if (txCard) txCard.style.display = "none";
|
|
updateURLForPage(
|
|
"balance",
|
|
document.getElementById("balanceAddr").value.trim()
|
|
);
|
|
} else {
|
|
if (balanceCard) balanceCard.style.display = "none";
|
|
if (txCard) txCard.style.display = "block";
|
|
updateURLForPage(
|
|
"transaction",
|
|
document.getElementById("txHash").value.trim()
|
|
);
|
|
const historyOutput = document.getElementById("historyOutput");
|
|
if (historyOutput) historyOutput.innerHTML = "";
|
|
const transactionSection =
|
|
document.getElementById("transactionSection");
|
|
if (transactionSection) transactionSection.style.display = "none";
|
|
}
|
|
}
|
|
|
|
// History (auto-load after balance)
|
|
let __historyAddress = "";
|
|
function loadHistoryFor(address) {
|
|
__historyAddress = address;
|
|
const perPageSelect = document.getElementById("perPageSelect");
|
|
const limit = perPageSelect ? parseInt(perPageSelect.value, 10) : 10;
|
|
const url = `https://api.shasta.trongrid.io/v1/accounts/${address}/transactions?limit=${limit}`;
|
|
const section = document.getElementById("transactionSection");
|
|
if (section) section.style.display = "block";
|
|
resetHistoryState(limit);
|
|
transactionHistory(url, address);
|
|
}
|
|
|
|
// Init theme on load
|
|
document.addEventListener("DOMContentLoaded", initializeTheme);
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const txCard = document.querySelector("#txOutput").closest(".card");
|
|
if (txCard) txCard.style.display = "none";
|
|
});
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const page = params.get("page");
|
|
if (page === "transactions") {
|
|
showPage("transactionsPage");
|
|
const address = params.get("address");
|
|
const tx = params.get("tx");
|
|
if (tx) {
|
|
setSearchType("transaction");
|
|
const txInput = document.getElementById("txHash");
|
|
if (txInput) {
|
|
txInput.value = tx;
|
|
runTxSearch();
|
|
}
|
|
} else if (address) {
|
|
setSearchType("balance");
|
|
const input = document.getElementById("balanceAddr");
|
|
if (input) {
|
|
input.value = address;
|
|
runBalanceCheck();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
const perSel = document.getElementById("perPageSelect");
|
|
if (perSel) {
|
|
perSel.addEventListener("change", () => {
|
|
if (!__historyAddress) return;
|
|
const limit = parseInt(perSel.value, 10) || 10;
|
|
const url = `https://api.shasta.trongrid.io/v1/accounts/${__historyAddress}/transactions?limit=${limit}`;
|
|
resetHistoryState(limit);
|
|
transactionHistory(url, __historyAddress);
|
|
});
|
|
}
|
|
|
|
</script>
|
|
<div id="notification_drawer" class="notification-drawer"></div>
|
|
</body>
|
|
</html>
|