Обновить серверный UI под recovery key

This commit is contained in:
AidarKC 2026-06-23 13:44:18 +04:00
parent 365b22d778
commit 95daa230bb
6 changed files with 70 additions and 17 deletions

View File

@ -1,2 +1,2 @@
client.version=1.2.238 client.version=1.2.240
server.version=1.2.224 server.version=1.2.225

View File

@ -653,6 +653,28 @@ function parseHex32(value) {
return out; return out;
} }
async function attachSolanaLogs(error, connection) {
if (!error || typeof error.getLogs !== 'function' || !connection) {
return error;
}
try {
const logs = await error.getLogs(connection);
if (Array.isArray(logs) && logs.length) {
error.logs = logs;
error.transactionLogs = logs;
error.simulationLogs = logs;
if (!String(error.message || '').includes('Logs:')) {
error.message = `${String(error.message || 'Solana transaction failed')} :: Logs: ${logs.join(' | ')}`;
}
}
} catch {
// Если RPC не вернул логи, оставляем исходную ошибку как есть.
}
return error;
}
async function buildCreateContext({ login, keyBundle, solanaEndpoint }) { async function buildCreateContext({ login, keyBundle, solanaEndpoint }) {
const cleanLogin = normalizeLogin(login); const cleanLogin = normalizeLogin(login);
const endpoint = String(solanaEndpoint || '').trim(); const endpoint = String(solanaEndpoint || '').trim();
@ -816,12 +838,17 @@ async function createShineUserPdaOnSolana({
data: ixData, data: ixData,
}); });
const signature = await ctx.solana.sendAndConfirmTransaction( let signature;
try {
signature = await ctx.solana.sendAndConfirmTransaction(
ctx.connection, ctx.connection,
new ctx.solana.Transaction().add(ed25519RootIx, ed25519BchIx, createIx), new ctx.solana.Transaction().add(ed25519RootIx, ed25519BchIx, createIx),
[ctx.clientKeypair], [ctx.clientKeypair],
{ commitment: 'confirmed' }, { commitment: 'confirmed' },
); );
} catch (error) {
throw await attachSolanaLogs(error, ctx.connection);
}
return { return {
signature, signature,
@ -1030,12 +1057,17 @@ export async function updateShineUserPdaOnSolana({
const computeIx = solana.ComputeBudgetProgram.setComputeUnitLimit({ units: 800_000 }); const computeIx = solana.ComputeBudgetProgram.setComputeUnitLimit({ units: 800_000 });
const heapIx = solana.ComputeBudgetProgram.requestHeapFrame({ bytes: 262_144 }); const heapIx = solana.ComputeBudgetProgram.requestHeapFrame({ bytes: 262_144 });
const signature = await solana.sendAndConfirmTransaction( let signature;
try {
signature = await solana.sendAndConfirmTransaction(
connection, connection,
new solana.Transaction().add(computeIx, heapIx, edIxRoot, edIxBch, updateIx), new solana.Transaction().add(computeIx, heapIx, edIxRoot, edIxBch, updateIx),
[clientKeypair], [clientKeypair],
{ commitment: 'confirmed' }, { commitment: 'confirmed' },
); );
} catch (error) {
throw await attachSolanaLogs(error, connection);
}
return { return {
signature, signature,

View File

@ -61,7 +61,7 @@
</div> </div>
<div class="field"> <div class="field">
<label>Адрес сервера (URL)</label> <label>Адрес сервера (URL)</label>
<input type="text" id="serverAddress" placeholder="https://shineup.me/ws" /> <input type="text" id="serverAddress" placeholder="shineup.me" />
</div> </div>
<div class="field"> <div class="field">
<label>Серверы синхронизации (sync_servers)</label> <label>Серверы синхронизации (sync_servers)</label>
@ -97,6 +97,11 @@
<div class="sec-lbl">Ключевые пары (base58)</div> <div class="sec-lbl">Ключевые пары (base58)</div>
<div class="kp-block">
<div class="kp-title">Recovery Key — восстановление аккаунта</div>
<div class="kp-row"><span class="kp-lbl">Публичный</span><input class="kp-inp" type="text" id="recoveryPub" placeholder="base58, ~44 символа" /></div>
<div class="kp-row"><span class="kp-lbl">Приватный</span><input class="kp-inp" type="text" id="recoveryPriv" placeholder="seed base58, ~44 символа" /></div>
</div>
<div class="kp-block"> <div class="kp-block">
<div class="kp-title">Root Key — подпись PDA-записи</div> <div class="kp-title">Root Key — подпись PDA-записи</div>
<div class="kp-row"><span class="kp-lbl">Публичный</span><input class="kp-inp" type="text" id="rootPub" placeholder="base58, ~44 символа" /></div> <div class="kp-row"><span class="kp-lbl">Публичный</span><input class="kp-inp" type="text" id="rootPub" placeholder="base58, ~44 символа" /></div>

View File

@ -19,6 +19,8 @@ import {
const fieldMap = { const fieldMap = {
masterSecret: 'masterSecret', masterSecret: 'masterSecret',
recoveryPub: 'recoveryPub',
recoveryPriv: 'recoveryPriv',
rootPub: 'rootPub', rootPub: 'rootPub',
rootPriv: 'rootPriv', rootPriv: 'rootPriv',
bchPub: 'bchPub', bchPub: 'bchPub',

View File

@ -25,6 +25,8 @@ import {
const fieldMap = { const fieldMap = {
masterSecret: 'masterSecret', masterSecret: 'masterSecret',
recoveryPub: 'recoveryPub',
recoveryPriv: 'recoveryPriv',
rootPub: 'rootPub', rootPub: 'rootPub',
rootPriv: 'rootPriv', rootPriv: 'rootPriv',
bchPub: 'bchPub', bchPub: 'bchPub',
@ -39,6 +41,7 @@ let currentPda = null;
function resetExpectedKeysUi() { function resetExpectedKeysUi() {
$('expectedKeysBox').style.display = 'none'; $('expectedKeysBox').style.display = 'none';
setText('expectedRecoveryPub', '');
setText('expectedRootPub', ''); setText('expectedRootPub', '');
setText('expectedBchPub', ''); setText('expectedBchPub', '');
setText('expectedDevPub', ''); setText('expectedDevPub', '');
@ -48,6 +51,7 @@ function resetExpectedKeysUi() {
function renderExpectedKeys(parsed) { function renderExpectedKeys(parsed) {
$('expectedKeysBox').style.display = 'block'; $('expectedKeysBox').style.display = 'block';
setText('expectedRecoveryPub', publicKeyBytesToBase58(parsed.recoveryKey));
setText('expectedRootPub', publicKeyBytesToBase58(parsed.rootKey)); setText('expectedRootPub', publicKeyBytesToBase58(parsed.rootKey));
setText('expectedBchPub', publicKeyBytesToBase58(parsed.blockchain.blockchainPublicKey)); setText('expectedBchPub', publicKeyBytesToBase58(parsed.blockchain.blockchainPublicKey));
setText('expectedDevPub', publicKeyBytesToBase58(parsed.clientKey)); setText('expectedDevPub', publicKeyBytesToBase58(parsed.clientKey));
@ -59,6 +63,7 @@ function compareCurrentFormKeysWithPda() {
const blockchainActual = String($('bchPub').value || '').trim(); const blockchainActual = String($('bchPub').value || '').trim();
return { return {
resultMap: { resultMap: {
recovery: compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.recoveryKey), $('recoveryPub').value),
root: compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.rootKey), $('rootPub').value), root: compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.rootKey), $('rootPub').value),
blockchain: blockchainActual blockchain: blockchainActual
? compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.blockchain.blockchainPublicKey), blockchainActual) ? compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.blockchain.blockchainPublicKey), blockchainActual)

View File

@ -86,7 +86,7 @@
<h2>Новые параметры сервера</h2> <h2>Новые параметры сервера</h2>
<div class="field"> <div class="field">
<label>Новый адрес сервера (URL)</label> <label>Новый адрес сервера (URL)</label>
<input type="text" id="serverAddress" placeholder="https://shineup.me/ws" /> <input type="text" id="serverAddress" placeholder="shineup.me" />
</div> </div>
<div class="field"> <div class="field">
<label>Новые серверы синхронизации (sync_servers)</label> <label>Новые серверы синхронизации (sync_servers)</label>
@ -118,6 +118,11 @@
<div class="sec-lbl">Ключевые пары (base58)</div> <div class="sec-lbl">Ключевые пары (base58)</div>
<div class="kp-block">
<div class="kp-title">Recovery Key — восстановление аккаунта</div>
<div class="kp-row"><span class="kp-lbl">Публичный</span><input class="kp-inp" type="text" id="recoveryPub" placeholder="base58, ~44 символа" /></div>
<div class="kp-row"><span class="kp-lbl">Приватный</span><input class="kp-inp" type="text" id="recoveryPriv" placeholder="seed base58, ~44 символа" /></div>
</div>
<div class="kp-block"> <div class="kp-block">
<div class="kp-title">Root Key — подпись PDA-записи</div> <div class="kp-title">Root Key — подпись PDA-записи</div>
<div class="kp-row"><span class="kp-lbl">Публичный</span><input class="kp-inp" type="text" id="rootPub" placeholder="base58, ~44 символа" /></div> <div class="kp-row"><span class="kp-lbl">Публичный</span><input class="kp-inp" type="text" id="rootPub" placeholder="base58, ~44 символа" /></div>
@ -144,6 +149,10 @@
<div class="expected-card" id="expectedKeysBox" style="display:none"> <div class="expected-card" id="expectedKeysBox" style="display:none">
<div class="expected-ttl">Какие ключи ожидаются по уже загруженной PDA</div> <div class="expected-ttl">Какие ключи ожидаются по уже загруженной PDA</div>
<div class="expected-row">
<div class="expected-lbl">Ожидаемый recovery public key</div>
<div class="expected-val" id="expectedRecoveryPub"></div>
</div>
<div class="expected-row"> <div class="expected-row">
<div class="expected-lbl">Ожидаемый root public key</div> <div class="expected-lbl">Ожидаемый root public key</div>
<div class="expected-val" id="expectedRootPub"></div> <div class="expected-val" id="expectedRootPub"></div>