From 50da3e868d4da18c9fa552bcdec072dd49ee83f5adccf3283dba6d213f258e71 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Mon, 27 Apr 2026 01:44:07 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20Solana:=20=D0=BF=D1=80=D0=BE=D0=BC?= =?UTF-8?q?=D0=BE-topup=20URL=20=D1=81=20wallet(base58)=20=D0=B8=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=80=D0=BE=D0=B3=200.01=20SOL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VERSION.properties | 4 +- .../js/pages/registration-payment-view.js | 56 +++++++++++++++---- shine-UI/js/pages/topup-view.js | 9 ++- shine-UI/js/pages/wallet-view.js | 2 +- shine-UI/js/services/solana-wallet-service.js | 14 ++++- 5 files changed, 65 insertions(+), 20 deletions(-) diff --git a/VERSION.properties b/VERSION.properties index 4bf4549..c6a44b3 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.17 -server.version=1.2.17 +client.version=1.2.18 +server.version=1.2.18 diff --git a/shine-UI/js/pages/registration-payment-view.js b/shine-UI/js/pages/registration-payment-view.js index a6632a1..d3b5fbb 100644 --- a/shine-UI/js/pages/registration-payment-view.js +++ b/shine-UI/js/pages/registration-payment-view.js @@ -6,9 +6,15 @@ import { state, } from '../state.js'; import { toUserMessage } from '../services/ui-error-texts.js'; -import { deriveWalletFromPassword, formatSol, getBalanceSol } from '../services/solana-wallet-service.js'; +import { + deriveWalletFromPassword, + formatSol, + getBalanceSol, + getTopupSiteUrl, +} from '../services/solana-wallet-service.js'; export const pageMeta = { id: 'registration-payment-view', title: 'Оплата регистрации', showAppChrome: false }; +const MIN_REQUIRED_SOL = 0.01; function parseBalanceSol(value) { const parsed = Number.parseFloat(String(value || '').replace(',', '.')); @@ -77,9 +83,9 @@ export function render({ navigate }) { refreshButton.textContent = '↻'; refreshButton.title = 'Обновить'; - const refreshBalance = async () => { + const refreshBalance = async ({ showError = true } = {}) => { const address = String(walletValue.value || '').trim(); - if (!address) return; + if (!address) return null; refreshButton.disabled = true; try { const balance = await getBalanceSol({ @@ -88,10 +94,14 @@ export function render({ navigate }) { }); state.registrationPayment.balanceSOL = String(balance.sol); balanceValue.textContent = `${formatSol(balance.sol, 6)} SOL`; + return Number(balance.sol) || 0; } catch (error) { - status.className = 'status-line is-unavailable'; - status.textContent = `Не удалось обновить баланс: ${error?.message || 'unknown'}`; - status.style.display = ''; + if (showError) { + status.className = 'status-line is-unavailable'; + status.textContent = `Не удалось обновить баланс: ${error?.message || 'unknown'}`; + status.style.display = ''; + } + return null; } finally { refreshButton.disabled = false; } @@ -106,8 +116,11 @@ export function render({ navigate }) { const topupButton = document.createElement('button'); topupButton.className = 'ghost-btn'; topupButton.type = 'button'; - topupButton.textContent = 'Пополнить счет'; - topupButton.addEventListener('click', () => navigate('topup-view')); + topupButton.textContent = 'Пополнить кошелёк'; + topupButton.addEventListener('click', () => { + const walletAddress = String(walletValue.value || '').trim(); + window.open(getTopupSiteUrl(walletAddress), '_blank', 'noopener,noreferrer'); + }); const submitButton = document.createElement('button'); submitButton.className = 'primary-btn'; @@ -116,8 +129,8 @@ export function render({ navigate }) { submitButton.addEventListener('click', async () => { status.style.display = 'none'; - const cryptoState = getCryptoRuntimeState(); - if (!cryptoState.hasCrypto || !cryptoState.hasGetRandomValues || !cryptoState.hasSubtle) { + const cryptoState = getCryptoRuntimeState(); + if (!cryptoState.hasCrypto || !cryptoState.hasGetRandomValues || !cryptoState.hasSubtle) { status.className = 'status-line is-unavailable'; status.textContent = 'Криптография браузера недоступна. Откройте приложение через HTTPS tunnel или localhost и повторите регистрацию.'; status.style.display = ''; @@ -128,6 +141,27 @@ export function render({ navigate }) { submitButton.disabled = true; submitButton.textContent = 'Регистрация...'; + const walletAddress = String(walletValue.value || '').trim(); + if (!walletAddress) { + status.className = 'status-line is-unavailable'; + status.textContent = 'Кошелёк не подготовлен. Нажмите «Обновить» и попробуйте снова.'; + status.style.display = ''; + return; + } + + const currentBalance = await refreshBalance({ showError: true }); + if (currentBalance == null) return; + if (currentBalance < MIN_REQUIRED_SOL) { + status.className = 'status-line is-unavailable'; + status.textContent = `Для регистрации нужно минимум ${MIN_REQUIRED_SOL} SOL. Сейчас на кошельке ${formatSol(currentBalance, 6)} SOL. Пополните на промо-странице или попросите перевод у знакомого с тестовыми SOL.`; + status.style.display = ''; + const openTopup = window.confirm('Открыть страницу пополнения с вашим кошельком?'); + if (openTopup) { + window.open(getTopupSiteUrl(walletAddress), '_blank', 'noopener,noreferrer'); + } + return; + } + await authService.reconnect(state.entrySettings.shineServer); const result = await authService.registerUser(state.registrationDraft.login, state.registrationDraft.password); state.registrationDraft.flowType = 'registration'; @@ -151,7 +185,7 @@ export function render({ navigate }) { }); card.innerHTML = ` -

Для регистрации в Solana нужно заплатить 0,01 SOL (примерно 1 доллар).

+

Для регистрации в тестовой Solana нужно минимум 0,01 SOL на вашем кошельке.

Баланс (Solana) diff --git a/shine-UI/js/pages/topup-view.js b/shine-UI/js/pages/topup-view.js index 9ef9ca6..2c4a2eb 100644 --- a/shine-UI/js/pages/topup-view.js +++ b/shine-UI/js/pages/topup-view.js @@ -50,10 +50,10 @@ export function render({ navigate }) { card.innerHTML = `

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

-

1. Вы можете открыть сайт для покупки SOL.

+

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

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

- Открыть сайт пополнения + Открыть сайт пополнения
Кошелёк для пополнения (wallet.key)
@@ -107,6 +107,10 @@ export function render({ navigate }) { state.registrationPayment.walletAddress = wallet.address; walletValue.value = wallet.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, @@ -130,4 +134,3 @@ export function render({ navigate }) { return screen; } - diff --git a/shine-UI/js/pages/wallet-view.js b/shine-UI/js/pages/wallet-view.js index 7604624..f8fc00e 100644 --- a/shine-UI/js/pages/wallet-view.js +++ b/shine-UI/js/pages/wallet-view.js @@ -242,7 +242,7 @@ export function render({ navigate }) { 'Кнопка будет переводить на отдельный сайт пополнения.\n\nНажмите OK, чтобы открыть сайт.\nНажмите Отмена, чтобы выполнить тестовое пополнение (airdrop 1 SOL на DevNet).', ); if (openSite) { - window.open(getTopupSiteUrl(), '_blank', 'noopener,noreferrer'); + window.open(getTopupSiteUrl(walletAddress), '_blank', 'noopener,noreferrer'); setStatus('Открыт сайт пополнения. Пока также доступно тестовое пополнение.'); return; } diff --git a/shine-UI/js/services/solana-wallet-service.js b/shine-UI/js/services/solana-wallet-service.js index b8991ac..f8731fd 100644 --- a/shine-UI/js/services/solana-wallet-service.js +++ b/shine-UI/js/services/solana-wallet-service.js @@ -3,7 +3,7 @@ import { extractDeviceKey32FromStoredValue } from './device-key-utils.js'; import { loadEncryptedUserSecrets } from './key-vault.js'; const DEFAULT_SOLANA_ENDPOINT = 'https://api.devnet.solana.com'; -const TOPUP_SITE_URL = 'https://www.moonpay.com/buy/sol'; +const TOPUP_SITE_URL = 'https://shine-promo-solana-devnet.shineup.me/'; let solanaLibPromise = null; @@ -115,6 +115,14 @@ export function formatSol(value, digits = 6) { }); } -export function getTopupSiteUrl() { - return TOPUP_SITE_URL; +export function getTopupSiteUrl(walletAddress = '') { + const cleanWallet = String(walletAddress || '').trim(); + if (!cleanWallet) return TOPUP_SITE_URL; + try { + const url = new URL(TOPUP_SITE_URL); + url.searchParams.set('wallet', cleanWallet); + return url.toString(); + } catch { + return `${TOPUP_SITE_URL}?wallet=${encodeURIComponent(cleanWallet)}`; + } }