Переписать shine_payments и обновить тестовый UI с известным багом state

This commit is contained in:
AidarKC
2026-06-06 16:58:57 +04:00
parent c5ec32f87a
commit 89d06d317b
18 changed files with 1550 additions and 6578 deletions
@@ -62,6 +62,7 @@
<select id="queueId">
<option value="1">Очередь 1</option>
<option value="2">Очередь 2</option>
<option value="3">Очередь 3</option>
</select>
</label>
<label>Получатель: <input id="recipient" placeholder="Base58 адрес" /></label>
@@ -80,11 +81,13 @@
const RPC_URL = "https://api.devnet.solana.com";
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
const SEEDS = {
managerAllowance: "shine_p_v3_manager_allow",
queues: "shine_payments_v3_queues",
ticketQ1: "shine_payments_v3_q1_ticket",
ticketQ2: "shine_payments_v3_q2_ticket",
managerAllowance: "shine_p_manager_allow",
queues: "shine_payments_queues",
ticketQ1: "shine_payments_q1_ticket",
ticketQ2: "shine_payments_q2_ticket",
ticketQ3: "shine_payments_q3_ticket",
};
const IX = { managerAddTicket: 7 };
let walletPubkey = null;
let queuesCache = null;
document.getElementById("programId").textContent = PROGRAM_ID.toBase58();
@@ -119,10 +122,8 @@
if (!Number.isFinite(v) || v <= 0) throw new Error("Некорректная сумма USD");
return BigInt(Math.round(v * 100));
}
async function ixDiscriminator(name) {
const msg = utf8("global:" + name);
const hash = await crypto.subtle.digest("SHA-256", msg);
return new Uint8Array(hash).slice(0, 8);
function ixData(tag, ...parts) {
return concat(new Uint8Array([tag]), ...parts);
}
function isManagerErrors(msg) {
const s = String(msg || "").toLowerCase();
@@ -135,7 +136,8 @@
const manager = new solanaWeb3.PublicKey(data.slice(o, o + 32)); o += 32;
const q1 = readU64(data, o); o += 8;
const q2 = readU64(data, o); o += 8;
return { version, manager, q1, q2 };
const q3 = readU64(data, o); o += 8;
return { version, manager, q1, q2, q3 };
}
function parseQueues(data) {
let o = 0;
@@ -148,7 +150,11 @@
const q2Paid = readU64(data, o); o += 8;
const q2SumTotal = readU64(data, o); o += 8;
const q2SumPaid = readU64(data, o); o += 8;
return { version, q1Total, q1Paid, q1SumTotal, q1SumPaid, q2Total, q2Paid, q2SumTotal, q2SumPaid };
const q3Total = readU64(data, o); o += 8;
const q3Paid = readU64(data, o); o += 8;
const q3SumTotal = readU64(data, o); o += 8;
const q3SumPaid = readU64(data, o); o += 8;
return { version, q1Total, q1Paid, q1SumTotal, q1SumPaid, q2Total, q2Paid, q2SumTotal, q2SumPaid, q3Total, q3Paid, q3SumTotal, q3SumPaid };
}
function getProvider() {
@@ -187,7 +193,7 @@
return pda;
}
function deriveTicketPda(queueId, index) {
const seed = queueId === 1 ? SEEDS.ticketQ1 : SEEDS.ticketQ2;
const seed = queueId === 1 ? SEEDS.ticketQ1 : (queueId === 2 ? SEEDS.ticketQ2 : SEEDS.ticketQ3);
const [pda] = solanaWeb3.PublicKey.findProgramAddressSync([utf8(seed), u64ToBytes(index)], PROGRAM_ID);
return pda;
}
@@ -223,6 +229,7 @@
<div>PDA лимитов: <code>${core.allowancePda.toBase58()}</code></div>
<div>Доступно Q1: <b>${centsToUsdStr(core.allowance.q1)} USD</b></div>
<div>Доступно Q2: <b>${centsToUsdStr(core.allowance.q2)} USD</b></div>
<div>Доступно Q3: <b>${centsToUsdStr(core.allowance.q3)} USD</b></div>
`;
} catch (e) {
el.innerHTML = `<span class="err">${String(e.message || e)}</span>`;
@@ -241,15 +248,16 @@
if (!core.allowance) throw new Error("Для этого кошелька лимиты менеджера не выданы.");
const queueId = Number(document.getElementById("queueId").value);
if (queueId !== 1 && queueId !== 2) throw new Error("Очередь должна быть 1 или 2");
if (![1, 2, 3].includes(queueId)) throw new Error("Очередь должна быть 1, 2 или 3");
const recipient = new solanaWeb3.PublicKey(document.getElementById("recipient").value.trim());
const payout = usdToCents(document.getElementById("payoutUsd").value.trim());
const nextIndex = queueId === 1 ? (core.queues.q1Total + 1n) : (core.queues.q2Total + 1n);
const nextIndex = queueId === 1
? (core.queues.q1Total + 1n)
: (queueId === 2 ? (core.queues.q2Total + 1n) : (core.queues.q3Total + 1n));
const ticketPda = deriveTicketPda(queueId, nextIndex);
const disc = await ixDiscriminator("manager_add_ticket");
const data = concat(disc, new Uint8Array([queueId]), recipient.toBytes(), u64ToBytes(payout));
const data = ixData(IX.managerAddTicket, new Uint8Array([queueId]), recipient.toBytes(), u64ToBytes(payout));
const keys = [
{ pubkey: walletPubkey, isSigner: true, isWritable: true },
{ pubkey: core.allowancePda, isSigner: false, isWritable: true },