import { renderHeader } from '../components/header.js'; import { state } from '../state.js'; import { formatSol, getBalanceSol, getTopupSiteUrl, requestAirdropSol, } from '../services/solana-wallet-service.js'; export const pageMeta = { id: 'topup-view', title: 'Пополнение счета', showAppChrome: false }; // Канонический Solana-адрес пополнения = публичный device-ключ из сгенерированного набора ключей. // Тот же путь, что в registration-payment-view (deriveUserWalletAddress); не выводим адрес // напрямую из пароля, иначе он расходится с device-ключом регистрации. async function clientWalletAddressFromBundle() { const keyBundle = state.registrationDraft.preGeneratedKeyBundle; if (!keyBundle || !keyBundle.clientPair) { throw new Error('Ключи ещё не сгенерированы. Вернитесь на экран регистрации.'); } const raw = atob(keyBundle.clientPair.publicKeyB64); const bytes = new Uint8Array(raw.length); for (let i = 0; i < raw.length; i += 1) bytes[i] = raw.charCodeAt(i); const { PublicKey } = await import('https://esm.sh/@solana/web3.js@1.98.4'); return new PublicKey(bytes).toBase58(); } export function render({ navigate }) { const screen = document.createElement('section'); screen.className = 'stack'; const walletValue = document.createElement('input'); walletValue.className = 'input'; walletValue.type = 'text'; walletValue.value = state.registrationPayment.walletAddress || ''; walletValue.readOnly = true; walletValue.style.fontSize = '13px'; const status = document.createElement('p'); status.className = 'meta-muted'; status.textContent = 'Проверяем кошелек...'; const copyButton = document.createElement('button'); copyButton.className = 'ghost-btn'; copyButton.type = 'button'; copyButton.textContent = 'Скопировать'; copyButton.addEventListener('click', async () => { try { await navigator.clipboard.writeText(walletValue.value); copyButton.textContent = 'Скопировано'; window.setTimeout(() => { copyButton.textContent = 'Скопировать'; }, 1500); } catch { window.alert('Не удалось скопировать номер кошелька.'); } }); const walletRow = document.createElement('div'); walletRow.className = 'inline-input-row'; walletRow.append(walletValue, copyButton); const card = document.createElement('div'); card.className = 'card stack'; card.innerHTML = `

Кнопка «Пополнить» в кошельке будет переводить на отдельный сайт. Пока доступно тестовое пополнение.

1. Вы можете открыть промо-сайт пополнения с подставленным кошельком.

2. Либо нажать «Тестовое пополнение» и получить 1 SOL через DevNet airdrop.

Открыть сайт пополнения
Кошелёк для пополнения (client key = Solana wallet)
`; card.children[3].append(walletRow); const testButton = document.createElement('button'); testButton.className = 'ghost-btn'; testButton.type = 'button'; testButton.textContent = 'Тестовое пополнение (1 SOL)'; testButton.addEventListener('click', async () => { const address = String(walletValue.value || '').trim(); if (!address) { window.alert('Адрес кошелька не найден.'); return; } testButton.disabled = true; try { const drop = await requestAirdropSol({ endpoint: state.entrySettings.solanaServer, address, amountSol: 1, }); const bal = await getBalanceSol({ endpoint: state.entrySettings.solanaServer, address, }); state.registrationPayment.balanceSOL = String(bal.sol); status.textContent = `Тестовое пополнение выполнено. Новый баланс: ${formatSol(bal.sol, 6)} SOL. Signature: ${drop.signature}`; } catch (error) { status.textContent = `Ошибка тестового пополнения: ${error?.message || 'unknown'}`; } finally { testButton.disabled = false; } }); const backButton = document.createElement('button'); backButton.className = 'primary-btn'; backButton.type = 'button'; backButton.textContent = 'Назад'; backButton.addEventListener('click', () => navigate('registration-payment-view')); const actions = document.createElement('div'); actions.className = 'auth-footer-actions'; actions.append(testButton, backButton); (async () => { try { if (!walletValue.value) { const address = await clientWalletAddressFromBundle(); state.registrationPayment.walletAddress = address; walletValue.value = address; } const topupSiteLink = card.querySelector('#topup-site-link'); if (topupSiteLink instanceof HTMLAnchorElement) { topupSiteLink.href = getTopupSiteUrl(walletValue.value); } const balance = await getBalanceSol({ endpoint: state.entrySettings.solanaServer, address: walletValue.value, }); state.registrationPayment.balanceSOL = String(balance.sol); status.textContent = `Текущий баланс: ${formatSol(balance.sol, 6)} SOL`; } catch (error) { status.textContent = `Не удалось получить баланс: ${error?.message || 'unknown'}`; } })(); screen.append( renderHeader({ title: 'Пополнение счета', leftAction: { label: '←', onClick: () => navigate('registration-payment-view') }, }), card, status, actions, ); return screen; }