SHA256
Синхронизировать изменения проекта
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Тех. инструменты — Shine Payments Devnet</title>
|
||||
<title>Тех. инструменты — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -43,7 +43,7 @@
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>Техническая страница (Devnet)</h1>
|
||||
<h1>Техническая страница (Mainnet)</h1>
|
||||
<div class="muted">Программа: <code id="programId"></code></div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -112,7 +112,7 @@
|
||||
<script>
|
||||
const PROGRAM_ID = new solanaWeb3.PublicKey("SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v");
|
||||
const USERS_PROGRAM_ID = new solanaWeb3.PublicKey("SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6");
|
||||
const RPC_URL = "https://api.mainnet-beta.solana.com";
|
||||
const RPC_URL = "https://solana-rpc.publicnode.com";
|
||||
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
|
||||
const SEEDS = {
|
||||
config: "shine_payments_config",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Покупка билета — Shine Payments Devnet</title>
|
||||
<title>Покупка билета — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -40,7 +40,7 @@
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>Покупка билета (Devnet)</h1>
|
||||
<h1>Покупка билета (Mainnet)</h1>
|
||||
<div class="muted">Программа: <code id="programId"></code></div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -80,7 +80,7 @@
|
||||
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
|
||||
<script>
|
||||
const PROGRAM_ID = new solanaWeb3.PublicKey("SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v");
|
||||
const RPC_URL = "https://api.mainnet-beta.solana.com";
|
||||
const RPC_URL = "https://solana-rpc.publicnode.com";
|
||||
const ORACLE_ACCOUNT = new solanaWeb3.PublicKey("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE");
|
||||
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>DAO revoke vote — Shine Payments Devnet</title>
|
||||
<title>DAO revoke vote — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -39,7 +39,7 @@
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div style="margin-bottom: 12px;"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>DAO: голосование на revoke/burn membership token (Devnet)</h1>
|
||||
<h1>DAO: голосование на revoke/burn membership token (Mainnet)</h1>
|
||||
<div class="muted">Governance program: <code id="govPid"></code></div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -97,8 +97,7 @@
|
||||
import {
|
||||
Connection,
|
||||
PublicKey,
|
||||
Transaction,
|
||||
clusterApiUrl
|
||||
Transaction
|
||||
} from "https://esm.sh/@solana/web3.js@1.95.3";
|
||||
import {
|
||||
PROGRAM_VERSION_V3,
|
||||
@@ -117,7 +116,7 @@
|
||||
} from "https://esm.sh/@solana/spl-governance@0.3.28";
|
||||
|
||||
const GOVERNANCE_PROGRAM_ID = new PublicKey("GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw");
|
||||
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
|
||||
const connection = new Connection("https://solana-rpc.publicnode.com", "confirmed");
|
||||
document.getElementById("govPid").textContent = GOVERNANCE_PROGRAM_ID.toBase58();
|
||||
|
||||
let wallet = null;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>DAO-права менеджеров — Shine Payments Devnet</title>
|
||||
<title>DAO-права менеджеров — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -39,7 +39,7 @@
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>DAO: права менеджеров (Devnet)</h1>
|
||||
<h1>DAO: права менеджеров (Mainnet)</h1>
|
||||
<div class="muted">Программа: <code id="programId"></code></div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -85,7 +85,7 @@
|
||||
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
|
||||
<script>
|
||||
const PROGRAM_ID = new solanaWeb3.PublicKey("SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v");
|
||||
const RPC_URL = "https://api.mainnet-beta.solana.com";
|
||||
const RPC_URL = "https://solana-rpc.publicnode.com";
|
||||
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
|
||||
const SEEDS = {
|
||||
config: "shine_payments_config",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Главная — Shine Payments Devnet</title>
|
||||
<title>Главная — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -36,7 +36,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<h1>Shine Payments Devnet</h1>
|
||||
<h1>Shine Payments Mainnet</h1>
|
||||
<div class="panel">
|
||||
<div>Выберите страницу:</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Логика работы — Shine Payments Devnet</title>
|
||||
<title>Логика работы — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>Логика работы Shine Payments (тестовый этап)</h1>
|
||||
<div class="panel">
|
||||
<p>Система работает в <b>Devnet</b>. Экономика хранится в <b>USD-центах</b>, а реальные переводы происходят в SOL.</p>
|
||||
<p>Система работает в <b>Mainnet</b>. Экономика хранится в <b>USD-центах</b>, а реальные переводы происходят в SOL.</p>
|
||||
<p>Курс SOL/USD берётся из Pyth прямо в контракте при покупке и при шаге выплаты. Цена проверяется на актуальность (не старше 120 секунд).</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Менеджерские билеты — Shine Payments Devnet</title>
|
||||
<title>Менеджерские билеты — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -33,13 +33,25 @@
|
||||
.ok { color: var(--ok); }
|
||||
.warn { color: var(--warn); }
|
||||
.err { color: var(--err); white-space: pre-wrap; }
|
||||
.err-box {
|
||||
margin-top: 10px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #4c2730;
|
||||
border-radius: 8px;
|
||||
background: #23151a;
|
||||
color: var(--err);
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.45;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
code { background: var(--code); padding: 2px 4px; border-radius: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>Менеджер: создание билетов (Devnet)</h1>
|
||||
<h1>Менеджер: создание билетов (Mainnet)</h1>
|
||||
<div class="muted">Программа: <code id="programId"></code></div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -78,7 +90,7 @@
|
||||
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
|
||||
<script>
|
||||
const PROGRAM_ID = new solanaWeb3.PublicKey("SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v");
|
||||
const RPC_URL = "https://api.mainnet-beta.solana.com";
|
||||
const RPC_URL = "https://solana-rpc.publicnode.com";
|
||||
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
|
||||
const SEEDS = {
|
||||
managerAllowance: "shine_p_manager_allow",
|
||||
@@ -130,6 +142,55 @@
|
||||
return s.includes("managerlimitexceeded") || s.includes("invalidmanagerwallet");
|
||||
}
|
||||
|
||||
function safeJson(value) {
|
||||
try {
|
||||
return JSON.stringify(value, null, 2);
|
||||
} catch {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function formatSolanaErrorDetails(error) {
|
||||
const parts = [];
|
||||
const msg = String(error?.message || error || "").trim();
|
||||
if (msg) parts.push(msg);
|
||||
|
||||
const logs = error?.logs || error?.transactionLogs || error?.simulationLogs || error?.data?.logs;
|
||||
if (Array.isArray(logs) && logs.length) {
|
||||
parts.push(`Logs:\n${logs.join("\n")}`);
|
||||
}
|
||||
|
||||
const errObj = error?.value?.err || error?.err || error?.data?.err;
|
||||
if (errObj) {
|
||||
parts.push(`Err:\n${safeJson(errObj)}`);
|
||||
}
|
||||
|
||||
if (error?.signature) {
|
||||
parts.push(`Signature: ${error.signature}`);
|
||||
}
|
||||
|
||||
return parts.length ? parts.join("\n\n") : "unknown";
|
||||
}
|
||||
|
||||
async function attachSolanaLogs(error) {
|
||||
if (!error) return error;
|
||||
|
||||
if (typeof error.getLogs === "function") {
|
||||
try {
|
||||
const logs = await error.getLogs(connection);
|
||||
if (Array.isArray(logs) && logs.length) {
|
||||
error.logs = logs;
|
||||
error.transactionLogs = logs;
|
||||
error.simulationLogs = logs;
|
||||
}
|
||||
} catch {
|
||||
// Игнорируем: часть RPC не умеет отдавать логи для expired/confirm ошибок.
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
function parseManagerAllowance(data) {
|
||||
let o = 0;
|
||||
const version = data[o++];
|
||||
@@ -183,8 +244,29 @@
|
||||
tx.recentBlockhash = bh.blockhash;
|
||||
const signed = await provider.signTransaction(tx);
|
||||
const sig = await connection.sendRawTransaction(signed.serialize(), { skipPreflight: false });
|
||||
await connection.confirmTransaction({ signature: sig, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight }, "confirmed");
|
||||
return sig;
|
||||
try {
|
||||
await connection.confirmTransaction(
|
||||
{ signature: sig, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight },
|
||||
"confirmed",
|
||||
);
|
||||
return { signature: sig, confirmed: true };
|
||||
} catch (confirmError) {
|
||||
confirmError.signature = sig;
|
||||
const txInfo = await connection.getTransaction(sig, {
|
||||
commitment: "confirmed",
|
||||
maxSupportedTransactionVersion: 0,
|
||||
});
|
||||
if (txInfo?.meta?.logMessages?.length) {
|
||||
confirmError.logs = txInfo.meta.logMessages;
|
||||
confirmError.transactionLogs = txInfo.meta.logMessages;
|
||||
}
|
||||
await attachSolanaLogs(confirmError);
|
||||
const postCheck = await Promise.resolve(typeof ix._postCheck === "function" ? ix._postCheck(sig) : null);
|
||||
if (postCheck?.success) {
|
||||
return { signature: sig, confirmed: false, postCheck };
|
||||
}
|
||||
throw confirmError;
|
||||
}
|
||||
}
|
||||
|
||||
function deriveManagerAllowancePda(managerWallet) {
|
||||
@@ -272,8 +354,17 @@
|
||||
{ pubkey: solanaWeb3.SystemProgram.programId, isSigner: false, isWritable: false },
|
||||
];
|
||||
const ix = new solanaWeb3.TransactionInstruction({ programId: PROGRAM_ID, keys, data });
|
||||
const sig = await sendInstruction(ix);
|
||||
out.innerHTML = `<span class="ok">Билет создан. Tx: <code>${sig}</code></span>`;
|
||||
ix._postCheck = async () => {
|
||||
const ai = await connection.getAccountInfo(ticketPda, "confirmed");
|
||||
if (!ai) return { success: false };
|
||||
return { success: true, ticketPda: ticketPda.toBase58() };
|
||||
};
|
||||
const result = await sendInstruction(ix);
|
||||
if (result.confirmed) {
|
||||
out.innerHTML = `<span class="ok">Билет создан. Tx: <code>${result.signature}</code></span>`;
|
||||
} else {
|
||||
out.innerHTML = `<span class="warn">Транзакция подтверждалась с задержкой, но билет создан on-chain. Tx: <code>${result.signature}</code></span>`;
|
||||
}
|
||||
await refresh();
|
||||
} catch (e) {
|
||||
const raw = String(e.message || e);
|
||||
@@ -281,7 +372,7 @@
|
||||
out.innerHTML = `<span class="warn">Операция отклонена: лимит менеджера недостаточен или кошелек не имеет прав менеджера.</span>`;
|
||||
return;
|
||||
}
|
||||
out.innerHTML = `<span class="err">${raw}</span>`;
|
||||
out.innerHTML = `<span class="err">Ошибка создания билета:</span><div class="err-box">${formatSolanaErrorDetails(e)}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Что ещё нужно до DAO — Shine Payments Devnet</title>
|
||||
<title>Что ещё нужно до DAO — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -25,7 +25,7 @@
|
||||
<h1>Что ещё нужно до реального DAO</h1>
|
||||
|
||||
<div class="panel">
|
||||
<p>Сейчас роль DAO выполняет обычный кошелёк (тестовый режим Devnet).</p>
|
||||
<p>Сейчас роль DAO выполняет обычный кошелёк, а полное on-chain управление через DAO ещё не включено.</p>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Сценарий тестирования — Shine Payments Devnet</title>
|
||||
<title>Сценарий тестирования — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -22,7 +22,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>Сценарий тестирования Shine Payments (Devnet)</h1>
|
||||
<h1>Сценарий тестирования Shine Payments (Mainnet)</h1>
|
||||
|
||||
<div class="panel">
|
||||
<h3>Вариант А: один кошелёк</h3>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Отслеживание билета — Shine Payments Devnet</title>
|
||||
<title>Отслеживание билета — Shine Payments Mainnet</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
@@ -42,7 +42,7 @@
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="topbar"><a class="back" href="./index.html">← На главную</a></div>
|
||||
<h1>Отслеживание билета (Devnet)</h1>
|
||||
<h1>Отслеживание билета (Mainnet)</h1>
|
||||
<div class="muted">Программа: <code id="programId"></code></div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -78,7 +78,7 @@
|
||||
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
|
||||
<script>
|
||||
const PROGRAM_ID = new solanaWeb3.PublicKey("SHiPmXbM9Fs9khzRUW3TGKsS2W84aqaXTxs3ZkajW9v");
|
||||
const RPC_URL = "https://api.mainnet-beta.solana.com";
|
||||
const RPC_URL = "https://solana-rpc.publicnode.com";
|
||||
const ORACLE_ACCOUNT = new solanaWeb3.PublicKey("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE");
|
||||
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user