import { createRequire } from "node:module"; createRequire(import.meta.url)("bn-eslint.js"); import type { Round } from "./abi.js"; import { config } from "./config.js"; import { account, clampBet, getCurrentEpoch, getMinBetAmount, getRound, betBull, betBear, getBufferSeconds, getBlockTimestamp } from "./contract.js"; import { decide, type Side } from "./strategy.js"; import { outcome } from "./strategy.js"; const POLL_MS = 15_000; const fmtBnb = (w: bigint) => (Number(w) / 1e18).toFixed(4); const fmtTime = () => new Date().toLocaleTimeString("en-GB", { hour12: false }); let lastBetEpoch: bigint | null = null; let lastBetSide: Side = null; let lastBetWon: boolean | null = null; let roundsSinceBet = 0; async function fetchHistory(currentEpoch: bigint, count: number): Promise { const out: Round[] = []; for (let i = 0; i < count; i++) { const e = currentEpoch - BigInt(i); if (e <= 0n) break; try { const r = await getRound(e); out.unshift(r); } catch { break; } } return out; } async function run(): Promise { const minBet = await getMinBetAmount(); const amount = clampBet(config.betAmountWei, minBet); const currentEpoch = await getCurrentEpoch(); const history = await fetchHistory(currentEpoch, config.lookbackRounds + 5); if (lastBetEpoch !== null && lastBetEpoch < currentEpoch) { const prevRound = history.find((r) => r.epoch === lastBetEpoch); if (prevRound) { const o = outcome(prevRound); lastBetWon = o === "tie" ? null : o === (lastBetSide === "bull" ? "bull" : "bear"); const result = o === "tie" ? "TIE" : lastBetWon ? "WON" : "LOST"; console.log(`[${fmtTime()}] Last bet epoch ${lastBetEpoch} (${lastBetSide}): ${result}`); } roundsSinceBet = lastBetEpoch === currentEpoch - 1n ? 1 : Number(currentEpoch - lastBetEpoch - 1n) + 1; } else if (lastBetEpoch === currentEpoch) { roundsSinceBet = 0; } const { side, edge } = decide(history, lastBetSide, lastBetWon, roundsSinceBet); if (side === null) { console.log(`[${fmtTime()}] Epoch ${currentEpoch} | skip (edge ${edge.toFixed(2)} < min or no signal)`); return; } const currentRound = history[history.length - 1]; const now = await getBlockTimestamp(); const buffer = await getBufferSeconds(); if (currentRound && now >= currentRound.lockTimestamp - buffer) { console.log(`[${fmtTime()}] Epoch ${currentEpoch} | skip (lock window, no new bets)`); return; } try { const txHash = side === "bull" ? await betBull(amount) : await betBear(amount); lastBetEpoch = currentEpoch; lastBetSide = side; lastBetWon = null; roundsSinceBet = 0; console.log(`[${fmtTime()}] BET PLACED: ${side.toUpperCase()} ${fmtBnb(amount)} BNB @ epoch ${currentEpoch} | tx ${txHash}`); } catch (e) { console.error(`[${fmtTime()}] Bet failed:`, e); } } async function loop(): Promise { console.log("--- PancakeSwap Prediction Bot ---"); console.log(`Wallet: ${account.address}`); console.log(`Contract: ${config.contract}`); console.log(`Poll every ${POLL_MS / 1000}s. Press Ctrl+C to stop.\n`); for (;;) { try { await run(); } catch (e) { console.error(`[${fmtTime()}] Error:`, e); } await new Promise((r) => setTimeout(r, POLL_MS)); } } loop();