| |
|
|
| class Web3Simulator { |
| constructor() { |
| this.isConnected = false; |
| this.walletAddress = ''; |
| this.network = 'Ethereum'; |
| this.balance = 12.75; |
| this.transactions = []; |
| this.initElements(); |
| this.bindEvents(); |
| this.createBackgroundElements(); |
| } |
|
|
| initElements() { |
| |
| this.connectBtn = document.getElementById('connect-btn'); |
| this.simulateBtn = document.getElementById('simulate-btn'); |
| this.disconnectBtn = document.getElementById('disconnect-btn'); |
| this.clearTxBtn = document.getElementById('clear-tx'); |
| this.sendBtn = document.getElementById('send-btn'); |
| this.executeBtn = document.getElementById('execute-btn'); |
|
|
| |
| this.connectText = document.getElementById('connect-text'); |
| this.walletStatus = document.getElementById('wallet-status'); |
| this.walletAddressEl = document.getElementById('wallet-address'); |
| this.connectionIndicator = document.getElementById('connection-indicator'); |
| this.statusMessage = document.getElementById('status-message'); |
| this.networkName = document.getElementById('network-name'); |
| this.balanceEl = document.getElementById('balance'); |
| this.txCount = document.getElementById('tx-count'); |
| this.transactionsContainer = document.getElementById('transactions-container'); |
| this.contractAction = document.getElementById('contract-action'); |
| this.contractDetails = document.getElementById('contract-details'); |
| } |
|
|
| bindEvents() { |
| this.connectBtn.addEventListener('click', () => this.toggleConnection()); |
| this.simulateBtn.addEventListener('click', () => this.simulateTransaction()); |
| this.disconnectBtn.addEventListener('click', () => this.disconnectWallet()); |
| this.clearTxBtn.addEventListener('click', () => this.clearTransactions()); |
| this.sendBtn.addEventListener('click', () => this.sendTransaction()); |
| this.executeBtn.addEventListener('click', () => this.executeContractCall()); |
| this.contractAction.addEventListener('change', (e) => this.updateContractDetails(e.target.value)); |
| } |
|
|
| createBackgroundElements() { |
| const bgContainer = document.createElement('div'); |
| bgContainer.className = 'bg-elements'; |
| |
| for (let i = 0; i < 3; i++) { |
| const element = document.createElement('div'); |
| element.className = 'bg-element'; |
| bgContainer.appendChild(element); |
| } |
| |
| document.body.appendChild(bgContainer); |
| } |
|
|
| generateWalletAddress() { |
| const chars = '0123456789abcdef'; |
| let address = '0x'; |
| for (let i = 0; i < 40; i++) { |
| address += chars[Math.floor(Math.random() * 16)]; |
| } |
| return address; |
| } |
|
|
| toggleConnection() { |
| if (this.isConnected) { |
| this.disconnectWallet(); |
| } else { |
| this.connectWallet(); |
| } |
| } |
|
|
| connectWallet() { |
| |
| this.connectBtn.disabled = true; |
| this.connectText.textContent = 'Connecting...'; |
| |
| setTimeout(() => { |
| this.walletAddress = this.generateWalletAddress(); |
| this.isConnected = true; |
| |
| |
| this.connectText.textContent = 'Connected'; |
| this.connectBtn.classList.remove('bg-indigo-600', 'hover:bg-indigo-700'); |
| this.connectBtn.classList.add('bg-green-600', 'hover:bg-green-700'); |
| this.walletStatus.classList.remove('hidden'); |
| this.walletAddressEl.textContent = `${this.walletAddress.substring(0, 6)}...${this.walletAddress.substring(38)}`; |
| this.connectionIndicator.classList.remove('bg-red-500'); |
| this.connectionIndicator.classList.add('bg-green-500', 'pulse'); |
| this.statusMessage.textContent = 'Wallet successfully connected to the blockchain.'; |
| this.networkName.textContent = this.network; |
| this.balanceEl.textContent = `${this.balance.toFixed(4)} ETH`; |
| this.disconnectBtn.classList.remove('hidden'); |
| this.simulateBtn.disabled = false; |
| |
| |
| document.querySelectorAll('#send-btn, #execute-btn').forEach(btn => { |
| btn.disabled = false; |
| }); |
| |
| this.connectBtn.disabled = false; |
| }, 1500); |
| } |
|
|
| disconnectWallet() { |
| this.isConnected = false; |
| |
| |
| this.connectText.textContent = 'Connect Wallet'; |
| this.connectBtn.classList.remove('bg-green-600', 'hover:bg-green-700'); |
| this.connectBtn.classList.add('bg-indigo-600', 'hover:bg-indigo-700'); |
| this.walletStatus.classList.add('hidden'); |
| this.connectionIndicator.classList.remove('bg-green-500', 'pulse'); |
| this.connectionIndicator.classList.add('bg-red-500'); |
| this.statusMessage.textContent = 'Wallet disconnected. Please connect to interact with the blockchain.'; |
| this.networkName.textContent = 'Not Connected'; |
| this.balanceEl.textContent = '0.00 ETH'; |
| this.disconnectBtn.classList.add('hidden'); |
| this.simulateBtn.disabled = true; |
| |
| |
| document.querySelectorAll('#send-btn, #execute-btn').forEach(btn => { |
| btn.disabled = true; |
| }); |
| } |
|
|
| simulateTransaction() { |
| if (!this.isConnected) return; |
| |
| const txTypes = [ |
| { type: 'Transfer', amount: (Math.random() * 5).toFixed(4), symbol: 'ETH' }, |
| { type: 'NFT Mint', amount: '1', symbol: 'NFT' }, |
| { type: 'Token Swap', amount: (Math.random() * 1000).toFixed(2), symbol: 'USDC' }, |
| { type: 'Staking', amount: (Math.random() * 10).toFixed(2), symbol: 'TOKEN' } |
| ]; |
| |
| const randomTx = txTypes[Math.floor(Math.random() * txTypes.length)]; |
| this.addTransaction(randomTx.type, randomTx.amount, randomTx.symbol); |
| } |
|
|
| sendTransaction() { |
| if (!this.isConnected) return; |
| |
| const amount = document.getElementById('send-amount').value; |
| const recipient = document.getElementById('recipient-address').value; |
| |
| if (!amount || !recipient) { |
| alert('Please enter both amount and recipient address'); |
| return; |
| } |
| |
| if (!recipient.startsWith('0x') || recipient.length !== 42) { |
| alert('Invalid recipient address'); |
| return; |
| } |
| |
| this.addTransaction('Transfer', amount, 'ETH', recipient); |
| document.getElementById('send-amount').value = ''; |
| document.getElementById('recipient-address').value = ''; |
| } |
|
|
| executeContractCall() { |
| if (!this.isConnected) return; |
| |
| const action = this.contractAction.value; |
| if (!action) { |
| alert('Please select a contract action'); |
| return; |
| } |
| |
| let txType, amount, symbol; |
| switch(action) { |
| case 'mint': |
| txType = 'NFT Mint'; |
| amount = '1'; |
| symbol = 'NFT'; |
| break; |
| case 'stake': |
| txType = 'Token Stake'; |
| amount = (Math.random() * 100).toFixed(2); |
| symbol = 'TOKEN'; |
| break; |
| case 'claim': |
| txType = 'Reward Claim'; |
| amount = (Math.random() * 50).toFixed(4); |
| symbol = 'TOKEN'; |
| break; |
| case 'swap': |
| txType = 'Token Swap'; |
| amount = (Math.random() * 1000).toFixed(2); |
| symbol = 'USDC'; |
| break; |
| } |
| |
| this.addTransaction(txType, amount, symbol); |
| this.contractAction.value = ''; |
| this.contractDetails.innerHTML = '<p class="text-gray-400 text-sm">Select an action to see details...</p>'; |
| } |
|
|
| updateContractDetails(action) { |
| let details = ''; |
| switch(action) { |
| case 'mint': |
| details = ` |
| <p class="mb-2"><strong>Mint NFT Collection</strong></p> |
| <p class="text-sm text-gray-400">Gas Estimate: 250,000 Gwei</p> |
| <p class="text-sm text-gray-400">Fee: ~0.008 ETH</p> |
| `; |
| break; |
| case 'stake': |
| details = ` |
| <p class="mb-2"><strong>Stake Tokens in Pool</strong></p> |
| <p class="text-sm text-gray-400">APR: 12.5%</p> |
| <p class="text-sm text-gray-400">Lock Period: 30 days</p> |
| `; |
| break; |
| case 'claim': |
| details = ` |
| <p class="mb-2"><strong>Claim Staking Rewards</strong></p> |
| <p class="text-sm text-gray-400">Available: ${(Math.random() * 50).toFixed(4)} TOKEN</p> |
| <p class="text-sm text-gray-400">Gas Fee: ~0.003 ETH</p> |
| `; |
| break; |
| case 'swap': |
| details = ` |
| <p class="mb-2"><strong>Swap Tokens</strong></p> |
| <p class="text-sm text-gray-400">Route: ETH → USDC</p> |
| <p class="text-sm text-gray-400">Slippage: 0.5%</p> |
| `; |
| break; |
| default: |
| details = '<p class="text-gray-400 text-sm">Select an action to see details...</p>'; |
| } |
| this.contractDetails.innerHTML = details; |
| } |
|
|
| addTransaction(type, amount, symbol, recipient = null) { |
| const tx = { |
| id: Date.now(), |
| type, |
| amount, |
| symbol, |
| recipient, |
| timestamp: new Date(), |
| hash: '0x' + Array.from({length: 64}, () => Math.floor(Math.random() * 16).toString(16)).join(''), |
| status: 'success' |
| }; |
| |
| this.transactions.unshift(tx); |
| this.updateTransactionsList(); |
| this.updateBalance(type, amount, symbol); |
| this.txCount.textContent = this.transactions.length; |
| } |
|
|
| updateTransactionsList() { |
| if (this.transactions.length === 0) { |
| this.transactionsContainer.innerHTML = ` |
| <div class="text-center py-12 text-gray-500"> |
| <i data-feather="inbox" class="mx-auto h-12 w-12 mb-4"></i> |
| <p>No transactions yet</p> |
| <p class="text-sm mt-1">Connect wallet to view transaction history</p> |
| </div> |
| `; |
| return; |
| } |
| |
| let txHtml = ''; |
| this.transactions.slice(0, 5).forEach(tx => { |
| const timeString = tx.timestamp.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); |
| const date = tx.timestamp.toLocaleDateString(); |
| |
| txHtml += ` |
| <div class="transaction-item rounded-lg p-4 flex flex-col md:flex-row md:items-center justify-between"> |
| <div class="tx-details mb-3 md:mb-0"> |
| <div class="flex items-center mb-1"> |
| <span class="font-medium">${tx.type}</span> |
| <span class="ml-2 status-badge bg-green-900 text-green-300">Success</span> |
| </div> |
| <p class="text-gray-400 text-sm">${date} at ${timeString}</p> |
| <p class="tx-hash text-gray-500 mt-1">${tx.hash.substring(0, 12)}...${tx.hash.substring(58)}</p> |
| </div> |
| <div class="tx-amount text-right"> |
| <p class="font-medium">${tx.amount} ${tx.symbol}</p> |
| ${tx.recipient ? `<p class="text-gray-400 text-sm mt-1">To: ${tx.recipient.substring(0, 8)}...${tx.recipient.substring(36)}</p>` : ''} |
| </div> |
| </div> |
| `; |
| }); |
| |
| this.transactionsContainer.innerHTML = txHtml; |
| feather.replace(); |
| } |
|
|
| updateBalance(type, amount, symbol) { |
| if (type === 'Transfer' && symbol === 'ETH') { |
| this.balance -= parseFloat(amount); |
| if (this.balance < 0) this.balance = 0; |
| this.balanceEl.textContent = `${this.balance.toFixed(4)} ETH`; |
| } else if (type === 'Reward Claim' || type === 'Token Swap') { |
| |
| |
| } |
| } |
|
|
| clearTransactions() { |
| this.transactions = []; |
| this.updateTransactionsList(); |
| this.txCount.textContent = '0'; |
| } |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| window.web3Sim = new Web3Simulator(); |
| |
| |
| feather.replace(); |
| }); |