import { renderHeader } from '../components/header.js'; import { formatSol, getBalanceSol, transferSol, createSolanaWalletFromPrivateBase58 } from '../services/solana-wallet-service.js'; import { state } from '../state.js'; export const pageMeta = { id: 'devnet-topup-view', title: 'Пополнение DEVNET', showAppChrome: false }; const SENDER_PRIVATE_32_BASE58 = '6xqAuKYvA8qrCdAkcw7Y8aMgvBnYk8JLxWLma5BzbAvu'; const TRANSFER_AMOUNT_SOL = 0.02; function readWalletFromUrl() { try { const url = new URL(window.location.href); return String(url.searchParams.get('wallet') || '').trim(); } catch { return ''; } } export function render({ navigate }) { const screen = document.createElement('section'); screen.className = 'stack'; screen.style.width = '100%'; screen.style.justifyItems = 'center'; const targetWallet = readWalletFromUrl(); const senderBox = document.createElement('div'); senderBox.className = 'card stack'; senderBox.style.width = 'min(100%, 320px)'; senderBox.innerHTML = ` Тестовый DEVNET-кошелёк
`; const targetBox = document.createElement('div'); targetBox.className = 'card stack'; targetBox.style.width = 'min(100%, 320px)'; targetBox.innerHTML = ` Кошелёк получателя `; const status = document.createElement('p'); status.className = 'meta-muted'; status.style.width = 'min(100%, 320px)'; status.style.overflowWrap = 'anywhere'; status.style.wordBreak = 'break-word'; status.style.whiteSpace = 'pre-wrap'; status.textContent = 'Готово к пополнению.'; const successHint = document.createElement('p'); successHint.style.width = 'min(100%, 320px)'; successHint.style.display = 'none'; successHint.style.margin = '0'; successHint.style.padding = '14px 16px'; successHint.style.borderRadius = '16px'; successHint.style.background = 'rgba(15, 159, 99, 0.14)'; successHint.style.border = '2px solid rgba(15, 159, 99, 0.32)'; successHint.style.fontSize = '24px'; successHint.style.fontWeight = '800'; successHint.style.lineHeight = '1.25'; successHint.style.color = '#0f9f63'; successHint.style.textAlign = 'center'; successHint.style.whiteSpace = 'pre-wrap'; successHint.textContent = ''; const fillBtn = document.createElement('button'); fillBtn.className = 'primary-btn'; fillBtn.type = 'button'; fillBtn.textContent = `Пополнить на ${TRANSFER_AMOUNT_SOL} SOL`; const actions = document.createElement('div'); actions.className = 'auth-footer-actions'; actions.style.width = 'min(100%, 320px)'; actions.style.justifySelf = 'center'; actions.append(fillBtn); let senderAddress = ''; let senderKeypair = null; const updateSenderBalance = async () => { if (!senderAddress) return; const endpoint = state.entrySettings.solanaServer; const balance = await getBalanceSol({ endpoint, address: senderAddress }); const senderBalanceEl = senderBox.querySelector('#devnet-topup-sender-balance'); if (senderBalanceEl) senderBalanceEl.textContent = `Баланс: ${formatSol(balance.sol, 6)} SOL`; }; const updateTargetBalance = async () => { if (!targetWallet) return null; const endpoint = state.entrySettings.solanaServer; const balance = await getBalanceSol({ endpoint, address: targetWallet }); const targetBalanceEl = targetBox.querySelector('#devnet-topup-target-balance'); if (targetBalanceEl) targetBalanceEl.textContent = `Баланс: ${formatSol(balance.sol, 6)} SOL`; return balance.sol; }; fillBtn.addEventListener('click', async () => { if (!targetWallet) { status.textContent = 'Ошибка: в URL не передан параметр wallet.'; return; } if (!senderKeypair) { status.textContent = 'Ошибка: кошелёк отправителя не инициализирован.'; return; } fillBtn.disabled = true; status.textContent = 'Отправляем перевод...'; successHint.style.display = 'none'; try { const endpoint = state.entrySettings.solanaServer; const tx = await transferSol({ endpoint, fromKeypair: senderKeypair, toAddress: targetWallet, amountSol: TRANSFER_AMOUNT_SOL, }); await updateSenderBalance(); const targetBalanceSol = await updateTargetBalance(); status.textContent = `Транзакция прошла.\nSignature: ${tx.signature}`; status.style.fontSize = '18px'; status.style.fontWeight = '700'; status.style.color = '#0f9f63'; fillBtn.style.display = 'none'; actions.style.display = 'none'; successHint.style.display = ''; successHint.textContent = `Кошелёк пополнен на ${TRANSFER_AMOUNT_SOL} SOL.\nНовый баланс: ${formatSol(targetBalanceSol || 0, 6)} SOL.\nМожете закрыть эту страницу и продолжить регистрацию.`; } catch (error) { status.textContent = `Ошибка перевода: ${error?.message || 'unknown'}`; status.style.fontSize = ''; status.style.fontWeight = ''; status.style.color = ''; successHint.style.display = 'none'; } finally { fillBtn.disabled = false; } }); (async () => { try { const sender = await createSolanaWalletFromPrivateBase58(SENDER_PRIVATE_32_BASE58); senderAddress = sender.address; senderKeypair = sender.keypair; const senderAddressEl = senderBox.querySelector('#devnet-topup-sender-address'); if (senderAddressEl) senderAddressEl.textContent = `Адрес: ${senderAddress}`; await updateSenderBalance(); await updateTargetBalance(); if (!targetWallet) { fillBtn.disabled = true; status.textContent = 'Передайте адрес получателя в параметре wallet.'; } } catch (error) { fillBtn.disabled = true; status.textContent = `Ошибка инициализации отправителя: ${error?.message || 'unknown'}`; } })(); screen.append( renderHeader({ title: 'DEVNET пополнение', }), senderBox, targetBox, status, successHint, actions, ); return screen; }