/** * Проверка схемы «цена закрытия из истории» на РЕАЛЬНОЙ ставке. * Читает аккаунт Bet из localnet СЫРЫМИ БАЙТАМИ (без Anchor-обёрток), * берёт bet_time/expire_time/entry_price и спрашивает Postgres binance-market. * * Раскладка Bet (Anchor, после 8-байтового дискриминатора): * offset 8 : amount u64 * offset 16 : bet_time i64 * offset 24 : expire_time i64 * offset 32 : entry_price u64 * offset 40 : exit_price u64 * offset 48 : side u64 * offset 56 : status u64 * offset 64 : bettor Pubkey(32) */ const { Connection, PublicKey } = require("@solana/web3.js"); const { Client } = require("pg"); const PROGRAM_ID = new PublicKey(process.argv[2] || "9ALsnxXNzDBv3mokngCHbruRTWUZiWR7pf7vswS1fCpf"); const BET_ID = Number(process.argv[3] || 6); const RPC = "http://192.168.76.181:8899"; const u64 = (b, o) => b.readBigUInt64LE(o); const i64 = (b, o) => b.readBigInt64LE(o); (async () => { const conn = new Connection(RPC, "confirmed"); const seeds = Buffer.concat([Buffer.from("bet"), (() => { const a = Buffer.alloc(8); a.writeBigUInt64LE(BigInt(BET_ID)); return a; })()]); const [betPda] = PublicKey.findProgramAddressSync([seeds], PROGRAM_ID); const info = await conn.getAccountInfo(betPda, "confirmed"); if (!info) throw new Error("bet account not found: " + betPda.toBase58()); const d = info.data; const amount = u64(d, 8); const betTime = Number(i64(d, 16)); const exp = Number(i64(d, 24)); const entry = u64(d, 32); const exitP = u64(d, 40); const side = u64(d, 48); const status = u64(d, 56); const bettor = new PublicKey(d.subarray(64, 96)).toBase58(); console.log("=== СТАВКА №" + BET_ID + " (сырые байты аккаунта) ==="); console.log("PDA :", betPda.toBase58()); console.log("amount :", amount.toString()); console.log("bet_time :", betTime, new Date(betTime * 1000).toISOString()); console.log("expire_time:", exp, new Date(exp * 1000).toISOString(), "(=bet_time+" + (exp - betTime) + "с)"); console.log("entry_price:", entry.toString(), " exit_price:", exitP.toString()); console.log("side:", side.toString(), " status:", status.toString(), " bettor:", bettor); console.log("СЕЙЧАС :", Math.floor(Date.now() / 1000), new Date().toISOString()); console.log("просрочена на:", Math.floor(Date.now() / 1000) - exp, "с"); const c = new Client({ host: "192.168.76.182", port: 5434, user: "postgres", password: "postgres", database: "binance_market" }); await c.connect(); const q = async (label, sql, params) => { const r = await c.query(sql, params); console.log("\n--- " + label + " ---"); if (!r.rows.length) console.log("(ПУСТО — цены нет вовсе)"); for (const row of r.rows) console.log(JSON.stringify(row)); return r.rows; }; const bMs = betTime * 1000, eMs = exp * 1000; await q("1) сделки в окне ставки [bet_time, expire]", ` SELECT price::text AS price, event_time, to_timestamp(event_time/1000) AS t FROM trade_event WHERE symbol='solusdt' AND event_time BETWEEN $1 AND $2 ORDER BY event_time`, [bMs, eMs]); const e1 = await q("2) ENTRY = последняя цена НЕ ПОЗЖЕ bet_time", ` SELECT price::text AS price, event_time, to_timestamp(event_time/1000) AS t FROM trade_event WHERE symbol='solusdt' AND event_time <= $1 ORDER BY event_time DESC LIMIT 1`, [bMs]); const e2 = await q("3) EXIT = последняя цена НЕ ПОЗЖЕ expire_time", ` SELECT price::text AS price, event_time, to_timestamp(event_time/1000) AS t FROM trade_event WHERE symbol='solusdt' AND event_time <= $1 ORDER BY event_time DESC LIMIT 1`, [eMs]); if (e1[0] && e2[0]) { const p1 = BigInt(e1[0].price.replace(".", "").padEnd(0)); const a = e1[0].price, b = e2[0].price; console.log("\n=== ИТОГ ПО СХЕМЕ ==="); console.log("entry из истории:", a, "| entry on-chain:", entry.toString(), "(on-chain = price*1e8)"); console.log("exit из истории:", b); const toI = (s) => { const [i, f = ""] = s.split("."); return BigInt(i + f.padEnd(8, "0").slice(0, 8)); }; const ai = toI(a), bi = toI(b); console.log("entry(int):", ai.toString(), " exit(int):", bi.toString()); console.log("вердикт по контракту:", bi > ai ? "UP выиграл" : bi < ai ? "DOWN выиграл" : "РАВНО — ставка зависает (текущий контракт не финализирует)"); } await q("4) ЧТО БЫЛО БЫ при 'ждать выгодной цены' (после экспирации, +2 мин)", ` SELECT min(price)::text AS min_p, max(price)::text AS max_p, count(*) AS n, min(to_timestamp(event_time/1000)) AS с, max(to_timestamp(event_time/1000)) AS по FROM trade_event WHERE symbol='solusdt' AND event_time > $1 AND event_time <= $2`, [eMs, (exp + 120) * 1000]); await c.end(); })().catch((e) => { console.error("ERR:", e.message); process.exit(1); });