Files
pump-game-ops/tools/tie-refund-accept.cjs
subochev b8a1f8dc39 docs(sec): SEC-9 закрыт — возврат залога при ничьей
Сводка: открыто 8 (было 9), закрыто 8. SEC-9 перенесён в закрытые с полной
историей: причина (close_bet.rs:66), замер доли ничьих (33.6%), решение
владельца (правка контракта), состав правок, собственная мутационная приёмка,
деплой и живой эффект (залипшие #0/#1 закрылись сами, ваулт −1000).
Хвост SEC-8 о «вечном залипании» помечен как устранённый.

Инструменты приёмки:
- tie-refund-accept.cjs — ставки циклом, проверка статуса на цепи
  (живой прогон: 6 возвратов из 25 ставок)
- tie-distribution.cjs, policy-economics.cjs — выбор политики ничьей
- vault-check.cjs — разбор Bet-аккаунтов сырыми байтами
2026-09-14 02:19:28 +03:00

85 lines
3.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Приёмка возврата при ничьей на ЖИВОМ стенде.
// Цикл: новый кошелёк → фаусет → ставка → ожидание авто-закрытия → чтение статуса.
// Победа = увидеть status=3 (REFUNDED) с exit==entry на НОВОЙ ставке.
const GW = process.env.GW || 'https://testfront.binom.pw/api';
const RPC = process.env.RPC || 'http://192.168.76.181:8899';
const PROG = '9ALsnxXNzDBv3mokngCHbruRTWUZiWR7pf7vswS1fCpf';
const { Connection, PublicKey } = require('@solana/web3.js');
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function j(path, body) {
const r = await fetch(GW + path, {
method: body ? 'POST' : 'GET',
headers: { 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
const t = await r.text();
let d = null; try { d = JSON.parse(t); } catch {}
if (!r.ok) throw new Error(`HTTP ${r.status} ${t.slice(0, 120)}`);
return d;
}
function betPda(id) {
const b = Buffer.alloc(8); b.writeBigUInt64LE(BigInt(id));
return PublicKey.findProgramAddressSync([Buffer.from('bet'), b], new PublicKey(PROG))[0];
}
async function readBet(conn, id) {
const a = await conn.getAccountInfo(betPda(id));
if (!a) return null;
const d = a.data;
return {
amount: d.readBigUInt64LE(8),
entry: d.readBigUInt64LE(32),
exit: d.readBigUInt64LE(40),
status: Number(d.readBigUInt64LE(56)),
bettor: new PublicKey(d.subarray(64, 96)).toBase58(),
};
}
(async () => {
const conn = new Connection(RPC, 'confirmed');
const MAX = Number(process.env.MAX || 8);
let ties = 0, normal = 0;
for (let i = 1; i <= MAX; i++) {
let id;
try {
const w = await j('/wallet', {});
await j('/faucet/' + w.address);
const bet = await j('/bet', { side: 'UP', amountUnits: '100000000', address: w.address });
id = bet.id;
process.stdout.write(`[${i}] ставка #${id} открыта entry=${bet.entryPrice} … `);
} catch (e) {
console.log(`[${i}] ОШИБКА ставки: ${e.message}`);
continue;
}
// ждём авто-закрытие (expiry 15s + тик планировщика 2s + запас)
let b = null;
for (let t = 0; t < 45; t++) {
await sleep(2000);
b = await readBet(conn, id).catch(() => null);
if (b && b.status !== 0) break;
}
if (!b) { console.log('аккаунт не читается'); continue; }
if (b.status === 0) { console.log(`осталась open (exit=${b.exit}) — не закрылась`); continue; }
const names = { 1: 'payout_done', 2: 'house_won', 3: 'REFUNDED' };
const name = names[b.status] || ('status=' + b.status);
if (b.status === 3) {
ties++;
const ok = b.exit === b.entry;
console.log(`✅ НИЧЬЯ→ВОЗВРАТ: exit=${b.exit} entry=${b.entry} ${ok ? '(равны!)' : '(НЕ равны — ОШИБКА!)'}`);
} else {
normal++;
console.log(`${name}: exit=${b.exit} entry=${b.entry}`);
}
}
console.log(`\nИТОГ: возвратов=${ties}, обычных исходов=${normal}`);
console.log(ties > 0 ? 'ВЕРДИКТ: возврат при ничьей РАБОТАЕТ на новой ставке' : 'ВЕРДИКТ: ничью поймать не удалось (вероятность ~33.6% за попытку)');
})();