SHA256
UI: показать пополнение при нехватке rent
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
||||
client.version=1.2.358
|
||||
client.version=1.2.359
|
||||
server.version=1.2.341
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { renderHeader } from '../components/header.js';
|
||||
import { authService, state } from '../state.js';
|
||||
import { base64ToBytes } from '../services/crypto-utils.js';
|
||||
import { base64ToBytes, bytesToBase58, publicKeyB64FromPkcs8Ed25519 } from '../services/crypto-utils.js';
|
||||
import { loadEncryptedUserSecrets } from '../services/key-vault.js';
|
||||
import { resolveShineServerByServerLogin } from '../services/shine-server-resolver.js';
|
||||
import { readShineUserPda, updateShineUserPdaOnSolana } from '../services/shine-user-pda-service.js';
|
||||
import { getTopupSiteUrl } from '../services/solana-wallet-service.js';
|
||||
|
||||
export const pageMeta = { id: 'access-servers-view', title: 'Серверы доступа' };
|
||||
|
||||
@@ -48,6 +49,27 @@ function shortenSignature(value) {
|
||||
return `${text.slice(0, 8)}...${text.slice(-8)}`;
|
||||
}
|
||||
|
||||
function isInsufficientFundsForRentError(error) {
|
||||
const text = [
|
||||
error?.message,
|
||||
error?.transactionMessage,
|
||||
Array.isArray(error?.logs) ? error.logs.join('\n') : '',
|
||||
Array.isArray(error?.transactionLogs) ? error.transactionLogs.join('\n') : '',
|
||||
Array.isArray(error?.simulationLogs) ? error.simulationLogs.join('\n') : '',
|
||||
].filter(Boolean).join('\n').toLowerCase();
|
||||
return text.includes('insufficient funds') && text.includes('rent');
|
||||
}
|
||||
|
||||
function clientAddressFromPublicB64(publicKeyB64) {
|
||||
const bytes = base64ToBytes(publicKeyB64);
|
||||
if (bytes.length !== 32) throw new Error('client public key должен быть 32 байта');
|
||||
return bytesToBase58(bytes);
|
||||
}
|
||||
|
||||
async function clientAddressFromPrivatePkcs8(privatePkcs8B64) {
|
||||
return clientAddressFromPublicB64(await publicKeyB64FromPkcs8Ed25519(privatePkcs8B64));
|
||||
}
|
||||
|
||||
function createConfirmModal() {
|
||||
const root = document.getElementById('modal-root');
|
||||
if (!(root instanceof HTMLElement)) return null;
|
||||
@@ -460,6 +482,18 @@ export function render({ navigate }) {
|
||||
)).join('');
|
||||
};
|
||||
|
||||
const showTopupRequiredStatus = (target, clientAddress) => {
|
||||
const address = String(clientAddress || '').trim();
|
||||
const topupUrl = address ? getTopupSiteUrl(address) : '/devnet-topup';
|
||||
target.innerHTML = `
|
||||
<span style="display:block; margin-bottom:0.55rem;">
|
||||
Не хватает SOL на client key для оплаты Solana rent/fee при обновлении user PDA.
|
||||
</span>
|
||||
${address ? `<span style="display:block; overflow-wrap:anywhere; margin-bottom:0.55rem;">Кошелёк: ${escapeHtml(address)}</span>` : ''}
|
||||
<a class="primary-btn" href="${escapeHtml(topupUrl)}" target="_blank" rel="noopener" style="display:inline-flex; text-decoration:none;">Пополнить DEVNET кошелёк</a>
|
||||
`;
|
||||
};
|
||||
|
||||
const loadSuggestions = async () => {
|
||||
const prefix = normalizeLogin(addInput.value);
|
||||
if (suggestionsLoading || prefix.length < 2 || operationBusy) {
|
||||
@@ -508,6 +542,7 @@ export function render({ navigate }) {
|
||||
return {
|
||||
rootPrivatePkcs8B64: savedRoot,
|
||||
clientPrivatePkcs8B64: savedClient,
|
||||
clientAddress: await clientAddressFromPrivatePkcs8(savedClient),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -542,6 +577,7 @@ export function render({ navigate }) {
|
||||
return {
|
||||
rootPrivatePkcs8B64: keyBundle.rootPair.privatePkcs8B64,
|
||||
clientPrivatePkcs8B64: keyBundle.clientPair.privatePkcs8B64,
|
||||
clientAddress: clientAddressFromPublicB64(keyBundle.clientPair.publicKeyB64),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -558,9 +594,10 @@ export function render({ navigate }) {
|
||||
const normalizedList = uniqueLogins(nextLogins);
|
||||
setOperationBusy(true);
|
||||
target.textContent = String(inFlightText || 'Обновляем список серверов доступа...');
|
||||
let signingMaterial = null;
|
||||
try {
|
||||
const currentPda = await readShineUserPda({ login: sessionLogin, solanaEndpoint });
|
||||
const signingMaterial = await resolveAccessServerSigningMaterial(currentPda);
|
||||
signingMaterial = await resolveAccessServerSigningMaterial(currentPda);
|
||||
const tx = await updateShineUserPdaOnSolana({
|
||||
login: sessionLogin,
|
||||
solanaEndpoint,
|
||||
@@ -575,7 +612,11 @@ export function render({ navigate }) {
|
||||
suggestEl.innerHTML = '';
|
||||
refreshAddButton();
|
||||
} catch (error) {
|
||||
target.textContent = error?.message || 'Не удалось обновить список серверов доступа.';
|
||||
if (isInsufficientFundsForRentError(error)) {
|
||||
showTopupRequiredStatus(target, signingMaterial?.clientAddress);
|
||||
} else {
|
||||
target.textContent = error?.message || 'Не удалось обновить список серверов доступа.';
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
setOperationBusy(false);
|
||||
|
||||
Reference in New Issue
Block a user