Auto-claim your 10-minute Stake.com reloads and Stake.us daily bonus via the direct GraphQL API — no clicks, no navigation. Free companion to the CodeStats Stake auto-claimer — live Stake bonus codes, full auto-claiming at https://codestats.gg · NEW: Stake Bonus Drop Tracker (free open-source drop history & stats) https://github.com/brokechubb/stake-bonus-drop-tracker
// ==UserScript==
// @name Auto Reload on Stake.com - CodeStats edition
// @description Auto-claim your 10-minute Stake.com reloads and Stake.us daily bonus via the direct GraphQL API — no clicks, no navigation. Free companion to the CodeStats Stake auto-claimer — live Stake bonus codes, full auto-claiming at https://codestats.gg · NEW: Stake Bonus Drop Tracker (free open-source drop history & stats) https://github.com/brokechubb/stake-bonus-drop-tracker
// @author CHUBB
// @homepageURL https://codestats.gg/
// @supportURL https://greasyfork.org/en/scripts/546623/feedback
// @contributionURL https://codestats.gg/
// @license MIT
// @namespace https://codestats.gg/
// @version 4.1
// @match https://stake.com/*
// @match https://stake.us/*
// @match https://stake.ac/*
// @match https://stake.games/*
// @match https://stake.bet/*
// @match https://stake.pet/*
// @match https://stake.mba/*
// @match https://stake.jp/*
// @match https://stake.bz/*
// @match https://stake.ceo/*
// @match https://stake.krd/*
// @match https://staketr.com/*
// @match https://stake1001.com/*
// @match https://stake1002.com/*
// @match https://stake1003.com/*
// @match https://stake1004.com/*
// @match https://stake1005.com/*
// @match https://stake1021.com/*
// @match https://stake1022.com/*
// @match https://stake.br/*
// @exclude https://stake.com/settings/*
// @exclude https://stake.us/settings/*
// @exclude https://stake.ac/settings/*
// @exclude https://stake.games/settings/*
// @exclude https://stake.bet/settings/*
// @exclude https://stake.pet/settings/*
// @exclude https://stake.mba/settings/*
// @exclude https://stake.jp/settings/*
// @exclude https://stake.bz/settings/*
// @exclude https://stake.ceo/settings/*
// @exclude https://stake.krd/settings/*
// @exclude https://staketr.com/settings/*
// @exclude https://stake1001.com/settings/*
// @exclude https://stake1002.com/settings/*
// @exclude https://stake1003.com/settings/*
// @exclude https://stake1004.com/settings/*
// @exclude https://stake1005.com/settings/*
// @exclude https://stake1021.com/settings/*
// @exclude https://stake1022.com/settings/*
// @exclude https://stake.br/settings/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @connect stake.com
// @connect stake.us
// @connect stake.ac
// @connect stake.games
// @connect stake.bet
// @connect stake.pet
// @connect stake.mba
// @connect stake.jp
// @connect stake.bz
// @connect stake.ceo
// @connect stake.krd
// @connect staketr.com
// @connect stake1001.com
// @connect stake1002.com
// @connect stake1003.com
// @connect stake1004.com
// @connect stake1005.com
// @connect stake1021.com
// @connect stake1022.com
// @connect stake.br
// @connect challenges.cloudflare.com
// @connect api.coingecko.com
// @run-at document-start
// @noframes
// ==/UserScript==
(function () {
"use strict";
// ===== CONSTANTS =====
const VERSION = "4.0";
const TURNSTILE_SITE_KEY = "0x4AAAAAAAGD4gMGOTFnvupz";
const SESSION_RE = /(?:^|; )session=([^;]*)/;
const GM_KEY = "csApiReload_v1";
const isStakeUs = /stake\.us/.test(window.location.hostname);
// claimInterval from the API is in milliseconds (confirmed: 600000 = 10 min)
const RETRY_DELAY_MS = 2 * 60 * 1000; // retry when not available / error
const POLL_BUFFER_MS = 30 * 1000; // extra buffer after claimInterval before claiming
// stake.us requires GM_xmlhttpRequest due to CORS on mutations
const GM_XHR_RE = /stake\.us/;
const COINGECKO_IDS = {
sol: "solana",
usdt: "tether",
eth: "ethereum",
btc: "bitcoin",
ltc: "litecoin",
xrp: "ripple",
eos: "eos",
bch: "bitcoin-cash",
trx: "tron",
bnb: "binancecoin",
doge: "dogecoin",
usdc: "usd-coin",
ape: "apecoin",
busd: "binance-usd",
cro: "crypto-com-chain",
dai: "dai",
link: "chainlink",
sand: "the-sandbox",
shib: "shiba-inu",
uni: "uniswap",
pol: "matic-network",
trump: "official-trump",
};
const PRICE_TTL = 5 * 60 * 1000;
const priceCache = {};
function fetchPrice(currency) {
const cached = priceCache[currency];
if (cached && Date.now() - cached.ts < PRICE_TTL)
return Promise.resolve(cached.price);
const id = COINGECKO_IDS[currency];
if (!id) return Promise.resolve(null);
return new Promise((resolve) => {
GM_xmlhttpRequest({
method: "GET",
url: `https://api.coingecko.com/api/v3/simple/price?ids=${id}&vs_currencies=usd`,
onload(r) {
try {
const data = JSON.parse(r.responseText);
const price = data?.[id]?.usd ?? null;
if (price)
priceCache[currency] = { price, ts: Date.now() };
resolve(price);
} catch (_) {
resolve(null);
}
},
onerror: () => resolve(null),
ontimeout: () => resolve(null),
});
});
}
const CURRENCIES = [
"usdt",
"btc",
"eth",
"ltc",
"sol",
"doge",
"bch",
"xrp",
"trx",
"eos",
"bnb",
"usdc",
"ape",
"busd",
"cro",
"dai",
"link",
"sand",
"shib",
"uni",
"pol",
"trump",
];
// Status query — VipMeta is the known operation name on Stake's gateway
// Fix: balances from API returns [{ available: { amount, currency } }]
// We query flat shape; the response is nested. Handle in balanceFor.
const STATUS_QUERY = `query VipMeta {
user {
id
balances {
available { amount currency }
}
reload: faucet {
id
active
value
claimInterval
lastClaim
expireAt
}
}
}`;
// Claim mutation — confirmed schema from ClaimFaucet network trace
const CLAIM_MUTATION = `mutation ClaimFaucet($currency: CurrencyEnum!, $turnstileToken: String!) {
claimReload: claimFaucet(currency: $currency, turnstileToken: $turnstileToken) {
reload: faucet {
user {
id
balances {
available { amount currency }
}
reload: faucet {
id
active
value
claimInterval
lastClaim
expireAt
}
}
}
}
}`;
const VAULT_MUTATION = `mutation CreateVaultDeposit($currency: CurrencyEnum!, $amount: Float!) {
createVaultDeposit(currency: $currency, amount: $amount) {
id
amount
currency
}
}`;
const DAILY_BONUS_STATUS_QUERY = `query VipMeta {
user {
dailyBonus {
id
active
lastClaim
amounts { amount currency }
}
}
}`;
const DAILY_BONUS_CLAIM_MUTATION = `mutation ClaimDailyBonus($turnstileToken: String!) {
claimDailyBonus(turnstileToken: $turnstileToken) {
amount
createdAt
currency
id
}
}`;
// ===== PERSISTENT STATE =====
function loadState() {
const defaults = {
currency: "sol",
reloadEnabled: true,
claimCount: 0,
autoVault: false,
dailyBonusEnabled: false,
dailyBonusClaimCount: 0,
dailyBonusLastClaim: null,
};
try {
const raw = GM_getValue(GM_KEY, null);
return raw ? Object.assign(defaults, raw) : defaults;
} catch (_) {
return defaults;
}
}
function saveState() {
try {
GM_setValue(GM_KEY, state);
} catch (_) {}
}
const state = loadState();
// ===== LOGGING =====
const tag = "[CodeStats API Reload Claimer]";
const log = (...a) => console.log(tag, ...a);
const warn = (...a) => console.warn(tag, ...a);
function logHUD(msg) {
const el = document.getElementById("csarc-log");
if (!el) return;
const line = document.createElement("div");
line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
line.style.padding = "1px 0";
el.appendChild(line);
while (el.children.length > 60) el.removeChild(el.firstChild);
el.scrollTop = el.scrollHeight;
}
function setStatus(text) {
const el = document.getElementById("csarc-status");
if (el) el.textContent = text;
}
function setTimer(ms) {
const el = document.getElementById("csarc-timer");
if (!el) return;
if (ms <= 0) {
el.textContent = "Claiming soon…";
return;
}
const s = Math.floor(ms / 1000);
el.textContent = `Next claim in: ${Math.floor(s / 60)}m ${s % 60}s`;
}
function setCounter() {
const el = document.getElementById("csarc-count");
if (el) el.textContent = state.claimCount;
}
function setInfo(faucet, claimedAmount, estimatedAmount) {
const el = document.getElementById("csarc-info");
if (!el || !faucet) return;
const fmt = (iso) => {
if (!iso) return "—";
const d = new Date(iso);
return isNaN(d)
? iso
: d.toLocaleString([], {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
const activeColor = faucet.active ? "#0f0" : "#f66";
const activeText = faucet.active ? "YES" : "NO";
const intervalMin = faucet.claimInterval
? Math.round(faucet.claimInterval / 60000) + "m"
: "—";
const sep = '<span style="color:#333"> | </span>';
el.innerHTML =
[
`Active: <strong style="color:${activeColor}">${activeText}</strong>`,
`Value: <strong style="color:#0f0">${faucet.value != null ? "$" + faucet.value : "—"}${claimedAmount != null ? ` <span style="color:#aaa">(${claimedAmount} ${state.currency.toUpperCase()})</span>` : estimatedAmount != null ? ` <span style="color:#666">(~${estimatedAmount} ${state.currency.toUpperCase()})</span>` : ""}</strong>`,
`Interval: <strong style="color:#ff0">${intervalMin}</strong>`,
].join(sep) +
`<br>` +
[
`Last Claim: <strong style="color:#0ff">${fmt(faucet.lastClaim)}</strong>`,
`Expires: <strong style="color:#f90">${fmt(faucet.expireAt)}</strong>`,
].join(sep);
}
// Fix: API returns balances as [{ available: { amount, currency } }]
// Flatten to [{ amount, currency }] for easier lookup
function flattenBalances(balances) {
if (!Array.isArray(balances)) return [];
return balances.map(b => b.available).filter(Boolean);
}
function balanceFor(flatBalances, currency) {
if (!Array.isArray(flatBalances)) return null;
const entry = flatBalances.find((b) => b.currency === currency);
return entry ? entry.amount : null;
}
async function vaultDeposit(currency, amount) {
const resp = await gql(
VAULT_MUTATION,
{ currency, amount },
"CreateVaultDeposit",
"mutation",
);
if (resp?.errors?.length)
throw new Error(resp.errors[0]?.message || "Vault error");
return resp?.data?.createVaultDeposit;
}
// ===== HTTP =====
function getSession() {
const m = document.cookie.match(SESSION_RE);
return m ? m[1] : "";
}
function gql(query, variables, operationName, opType = "query") {
const token = getSession();
const url = `${window.location.origin}/_api/graphql`;
const body = JSON.stringify({
operationName,
query,
variables: variables || {},
});
const headers = {
accept: "*/*",
"content-type": "application/json",
"x-access-token": token,
"x-language": "en",
"x-operation-name": operationName,
"x-operation-type": opType,
};
if (GM_XHR_RE.test(window.location.hostname)) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "POST",
url,
headers,
data: body,
onload(r) {
try {
resolve(JSON.parse(r.responseText));
} catch (e) {
reject(
new Error(
`Parse error: ${r.responseText.slice(0, 100)}`,
),
);
}
},
onerror: () => reject(new Error("Network error")),
ontimeout: () => reject(new Error("Request timeout")),
});
});
}
return fetch(url, {
method: "POST",
headers,
body,
credentials: "include",
}).then((r) => r.json());
}
// ===== TURNSTILE =====
class TurnstileManager {
constructor() {
this.cache = [];
this.maxCache = 3;
this.tokenTTL = 4 * 60 * 1000;
this.generatingCount = 0;
this.maxConcurrent = 2;
this._maintenance = null;
}
async init() {
await this._loadScript();
log("Turnstile ready");
setTimeout(() => this._fill(), 1000);
this._maintenance = setInterval(() => {
this._cleanExpired();
this._fill();
}, 30000);
}
_loadScript() {
return new Promise((resolve, reject) => {
if (unsafeWindow.turnstile) {
resolve();
return;
}
const s = document.createElement("script");
s.src = "https://challenges.cloudflare.com/turnstile/v0/api.js";
s.onload = resolve;
s.onerror = () =>
reject(new Error("Turnstile script failed to load"));
document.head.appendChild(s);
});
}
_fill() {
const needed =
this.maxCache - this.cache.length - this.generatingCount;
const toGen = Math.min(
needed,
this.maxConcurrent - this.generatingCount,
);
for (let i = 0; i < toGen; i++)
setTimeout(() => this._genCached(), i * 2000);
}
async _genCached() {
try {
const token = await this._createToken();
this.cache.push({ token, ts: Date.now() });
log(
`Token cached (pool: ${this.cache.length}/${this.maxCache})`,
);
} catch (e) {
warn("Cache token failed:", e.message);
}
}
_createToken() {
this.generatingCount++;
return new Promise((resolve, reject) => {
try {
const id = `_ts_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
const el = document.createElement("div");
el.id = id;
el.style.cssText =
"visibility:hidden;position:absolute;left:-10000px;top:-10000px;width:300px;height:65px;z-index:-1;";
document.body.appendChild(el);
let widgetId,
cleaned = false;
const cleanup = (delay = 0) => {
if (cleaned) return;
cleaned = true;
this.generatingCount--;
if (widgetId !== undefined) {
try {
unsafeWindow.turnstile.remove(widgetId);
} catch (_) {}
}
setTimeout(() => {
try {
el.parentNode?.removeChild(el);
} catch (_) {}
}, delay);
};
widgetId = unsafeWindow.turnstile.render(el, {
sitekey: TURNSTILE_SITE_KEY,
theme: "dark",
callback: (token) => {
cleanup(100);
resolve(token);
},
"error-callback": (err) => {
cleanup(2000);
reject(new Error(`Turnstile error: ${err}`));
},
"timeout-callback": () => {
cleanup(500);
reject(new Error("Turnstile timeout"));
},
});
} catch (e) {
this.generatingCount--;
reject(e);
}
});
}
_cleanExpired() {
const now = Date.now();
this.cache = this.cache.filter((e) => now - e.ts < this.tokenTTL);
}
async getToken() {
this._cleanExpired();
if (this.cache.length > 0) {
const entry = this.cache.shift();
this._fill();
return entry.token;
}
for (let i = 1; i <= 3; i++) {
try {
return await Promise.race([
this._createToken(),
new Promise((_, r) =>
setTimeout(
() => r(new Error("Token timeout")),
30000,
),
),
]);
} catch (e) {
const retryable = /300030|300010|timeout/i.test(e.message);
if (retryable && i < 3) {
warn(`Token attempt ${i}/3: ${e.message} — retrying`);
await new Promise((r) => setTimeout(r, 1000));
continue;
}
throw e;
}
}
}
}
// ===== SCHEDULER =====
let scheduleTimer = null;
let countdownTimer = null;
let claimInProgress = false;
let turnstile = null;
let lastFaucet = null;
function schedule(delayMs) {
clearTimeout(scheduleTimer);
clearInterval(countdownTimer);
if (!state.reloadEnabled) return;
const delay = Math.max(0, delayMs);
const endTime = Date.now() + delay;
setTimer(delay);
countdownTimer = setInterval(() => {
const rem = endTime - Date.now();
if (rem <= 0) {
clearInterval(countdownTimer);
setTimer(0);
return;
}
setTimer(rem);
}, 1000);
scheduleTimer = setTimeout(() => {
clearInterval(countdownTimer);
checkAndClaim();
}, delay);
}
// ===== MAIN LOGIC =====
async function checkAndClaim() {
if (claimInProgress) return;
if (!state.reloadEnabled) return;
claimInProgress = true;
setStatus("Checking reload status…");
logHUD("Checking reload status…");
let faucet, prevBalanceFlat;
try {
const resp = await gql(STATUS_QUERY, {}, "VipMeta", "query");
if (resp?.errors?.length)
throw new Error(resp.errors[0]?.message || "GraphQL error");
const user = resp?.data?.user;
faucet = user?.reload;
if (!faucet) throw new Error("No faucet data in response");
// Fix: flatten the nested balance structure from API
prevBalanceFlat = flattenBalances(user?.balances ?? []);
lastFaucet = faucet;
setInfo(faucet);
if (faucet.value != null) {
const cur = state.currency;
fetchPrice(cur)
.then((price) => {
if (price && state.currency === cur) {
const est = parseFloat(
(faucet.value / price).toFixed(8),
);
setInfo(faucet, null, est);
}
})
.catch(() => {});
}
} catch (e) {
warn("Status check failed:", e.message);
logHUD(`Status check error: ${e.message}`);
setStatus("Status error — retry in 2m");
claimInProgress = false;
schedule(RETRY_DELAY_MS);
return;
}
log("Faucet status:", JSON.stringify(faucet));
// Check expiry
const expireAt = faucet.expireAt
? new Date(faucet.expireAt).getTime()
: Infinity;
// Calculate when next claim is available based on API
const nextClaimMs = computeNextMs(faucet);
// Check if reload has expired (no longer available)
if (isFinite(expireAt) && expireAt < Date.now()) {
const nextMs = Math.max(computeNextMs(faucet), 30 * 60 * 1000);
schedule(nextMs);
setStatus("Expired — next in " + Math.round(nextMs / 60000) + "m");
logHUD("Reload expired — next check in " + Math.round(nextMs / 60000) + "m");
claimInProgress = false;
return;
}
if (!faucet.active) {
// active:false = no reload assigned — use longer interval
const nextMs = Math.max(computeNextMs(faucet), 30 * 60 * 1000);
schedule(nextMs);
setStatus("Not active — next in " + Math.round(nextMs / 60000) + "m");
logHUD("Reload not active — next check in " + Math.round(nextMs / 60000) + "m");
claimInProgress = false;
return;
}
// Check if claimable (time-based)
if (nextClaimMs > 0) {
logHUD("Not yet claimable — retry in " + Math.round(nextClaimMs / 60000) + "m");
setStatus("Wait " + Math.round(nextClaimMs / 60000) + "m");
claimInProgress = false;
schedule(nextClaimMs);
return;
}
// Available — claim it
await doClaim(faucet, prevBalanceFlat);
}
async function doClaim(prevFaucet, prevBalanceFlat) {
setStatus("Getting Turnstile token…");
logHUD("Getting Turnstile token…");
let token;
try {
token = await turnstile.getToken();
} catch (e) {
warn("Turnstile failed:", e.message);
logHUD(`Token error: ${e.message} — reloading…`);
setStatus("Turnstile error — reloading…");
claimInProgress = false;
setTimeout(() => window.location.reload(), 3000);
return;
}
setStatus("Sending claim…");
logHUD("Sending claim request…");
const claimCurrency = isStakeUs ? "sweeps" : state.currency;
let resp;
try {
resp = await gql(
CLAIM_MUTATION,
{ currency: claimCurrency, turnstileToken: token },
"ClaimFaucet",
"query",
);
} catch (e) {
warn("Claim request failed:", e.message);
logHUD(`Request error: ${e.message}`);
setStatus("Network error — retry in 2m");
claimInProgress = false;
schedule(RETRY_DELAY_MS);
return;
}
if (resp?.errors?.length) {
const msg = resp.errors[0]?.message || "Unknown error";
warn("Claim GraphQL error:", msg);
logHUD(`Claim error: ${msg}`);
const lower = msg.toLowerCase();
if (
lower.includes("already") ||
lower.includes("not available") ||
lower.includes("interval")
) {
// Re-query status to get the real next claim time
claimInProgress = false;
try {
const stResp = await gql(STATUS_QUERY, {}, "VipMeta", "query");
const stFaucet = stResp?.data?.user?.reload;
if (stFaucet) {
lastFaucet = stFaucet;
setInfo(stFaucet);
const nextMs = computeNextMs(stFaucet);
const waitMs = nextMs > 0 ? nextMs : RETRY_DELAY_MS;
setStatus(`Claim rejected — next in ${Math.round(waitMs / 60000)}m`);
logHUD(`Claim rejected: ${msg} — next in ${Math.round(waitMs / 60000)}m`);
schedule(waitMs);
} else {
logHUD(`Claim rejected: ${msg} — retry in ${Math.round(RETRY_DELAY_MS / 60000)}m`);
schedule(RETRY_DELAY_MS);
}
} catch {
schedule(RETRY_DELAY_MS);
}
return;
} else {
setStatus(`Error — retry in 2m`);
claimInProgress = false;
schedule(RETRY_DELAY_MS);
}
return;
}
const claimUser = resp?.data?.claimReload?.reload?.user;
const faucetAfter = claimUser?.reload;
log("Post-claim faucet data:", JSON.stringify(faucetAfter));
// Fix: flatten nested balance structure from API
const balAfterFlat = flattenBalances(claimUser?.balances ?? []);
const before = balanceFor(prevBalanceFlat ?? [], claimCurrency) ?? 0;
const after = balanceFor(balAfterFlat, claimCurrency) ?? 0;
const delta = parseFloat((after - before).toFixed(8));
if (faucetAfter) {
lastFaucet = faucetAfter;
setInfo(faucetAfter, delta > 0 ? delta : null);
}
state.claimCount++;
saveState();
setCounter();
const valueStr =
prevFaucet?.value != null ? ` ($${prevFaucet.value})` : "";
logHUD(`Reload claimed!${valueStr} Total: ${state.claimCount}`);
if (state.autoVault) {
if (delta > 0) {
try {
await vaultDeposit(claimCurrency, delta);
logHUD(`Vaulted ${delta} ${claimCurrency.toUpperCase()}`);
} catch (e) {
warn("Vault failed:", e.message);
logHUD(`Vault failed: ${e.message}`);
}
} else {
logHUD("Vault: no balance delta detected");
}
}
const nextMs = faucetAfter
? computeNextMs(faucetAfter)
: 600000 + POLL_BUFFER_MS;
setStatus(
`Claimed${valueStr} — next in ${Math.round(nextMs / 60000)}m`,
);
log(
`Claim #${state.claimCount} success. Next in ${Math.round(nextMs / 1000)}s`,
);
claimInProgress = false;
schedule(nextMs);
}
// claimInterval is in MILLISECONDS from the API (confirmed: 600000 = 10 min)
// Guard: if API returns seconds (< 3600), convert to ms to handle either format
function computeNextMs(faucet) {
const { claimInterval, lastClaim } = faucet || {};
if (!claimInterval || !lastClaim) return 600000 + POLL_BUFFER_MS;
const lastMs = new Date(lastClaim).getTime();
if (isNaN(lastMs)) {
warn("Could not parse lastClaim:", lastClaim);
return 600000 + POLL_BUFFER_MS;
}
// Normalize: if claimInterval looks like seconds (<100000), convert to ms
const intervalMs = claimInterval < 100000 ? claimInterval * 1000 : claimInterval;
const nextAt = lastMs + intervalMs;
const fromNow = nextAt - Date.now();
log(`computeNextMs: interval=${intervalMs}ms nextAt=${new Date(nextAt).toISOString()} fromNow=${fromNow}ms`);
if (fromNow <= 0) return 0;
return fromNow + POLL_BUFFER_MS;
}
function computeDailyNextMs(lastClaim) {
if (!lastClaim) return 0;
const lastMs = new Date(lastClaim).getTime();
if (isNaN(lastMs)) return 0;
const DAILY_INTERVAL_MS = 24 * 60 * 60 * 1000;
const fromNow = lastMs + DAILY_INTERVAL_MS - Date.now();
return fromNow <= 0 ? 0 : fromNow + POLL_BUFFER_MS;
}
// ===== DAILY BONUS =====
let dailyBonusTimer = null;
let dailyBonusClaiming = false;
let dailyBonusNextCheck = null;
function fmtMsDaily(ms) {
if (ms <= 0) return "now";
const h = Math.floor(ms / 3600000);
const m = Math.floor((ms % 3600000) / 60000);
const s = Math.floor((ms % 60000) / 1000);
if (h > 0) return `${h}h ${m}m ${s}s`;
if (m === 0) return `${s}s`;
return `${m}m ${s}s`;
}
function scheduleDailyBonus(delayMs) {
clearTimeout(dailyBonusTimer);
if (!isStakeUs || !state.dailyBonusEnabled) return;
dailyBonusNextCheck = Date.now() + delayMs;
updateDailyBonusStatus();
dailyBonusTimer = setTimeout(checkDailyBonus, delayMs);
}
function updateDailyBonusStatus() {
const el = document.getElementById("csarc-daily-status");
if (!el) return;
if (!isStakeUs) { el.textContent = "Not on stake.us"; return; }
if (!state.dailyBonusEnabled) { el.textContent = "Disabled"; return; }
if (dailyBonusClaiming) { el.textContent = "Claiming…"; return; }
if (dailyBonusNextCheck == null) { el.textContent = "Waiting…"; return; }
const rem = dailyBonusNextCheck - Date.now();
el.textContent = rem <= 0 ? "Checking…" : `Next: ${fmtMsDaily(rem)}`;
}
async function checkDailyBonus() {
if (!isStakeUs || !state.dailyBonusEnabled || dailyBonusClaiming) return;
dailyBonusClaiming = true;
updateDailyBonusStatus();
logHUD("💰 Checking Daily Bonus…");
try {
const resp = await gql(DAILY_BONUS_STATUS_QUERY, {}, "VipMeta", "query");
if (resp?.errors?.length) {
logHUD(`Daily Bonus error: ${resp.errors[0]?.message}`);
dailyBonusClaiming = false;
scheduleDailyBonus(15 * 60 * 1000);
return;
}
const db = resp?.data?.user?.dailyBonus;
if (!db || !db.active) {
logHUD("💰 Daily Bonus not active");
dailyBonusClaiming = false;
scheduleDailyBonus(30 * 60 * 1000);
return;
}
const nextMs = computeDailyNextMs(db.lastClaim);
if (nextMs > 0) {
dailyBonusClaiming = false;
scheduleDailyBonus(nextMs);
return;
}
// Time to claim
setStatus("Daily Bonus — getting token…");
logHUD("💰 Getting token for Daily Bonus…");
let token;
try {
token = await turnstile.getToken();
} catch (e) {
logHUD(`Daily Bonus token error: ${e.message}`);
dailyBonusClaiming = false;
scheduleDailyBonus(5 * 60 * 1000);
return;
}
setStatus("Daily Bonus — claiming…");
logHUD("💰 Claiming Daily Bonus…");
let claimResp;
try {
claimResp = await gql(
DAILY_BONUS_CLAIM_MUTATION,
{ turnstileToken: token },
"ClaimDailyBonus",
"query",
);
} catch (e) {
logHUD(`Daily Bonus request error: ${e.message}`);
dailyBonusClaiming = false;
scheduleDailyBonus(5 * 60 * 1000);
return;
}
if (claimResp?.errors?.length) {
const msg = claimResp.errors[0]?.message || "Unknown error";
const errType = claimResp.errors[0]?.errorType || "";
logHUD(`Daily Bonus error: ${msg}`);
dailyBonusClaiming = false;
if (errType === "dailyBonusClaimInterval" || msg.toLowerCase().includes("interval")) {
scheduleDailyBonus(30 * 60 * 1000);
} else {
scheduleDailyBonus(5 * 60 * 1000);
}
return;
}
const bonusData = claimResp?.data?.claimDailyBonus;
if (bonusData && bonusData.amount) {
const amt = Number(bonusData.amount).toFixed(8).replace(/\.?0+$/, "");
const cur = (bonusData.currency || "").toUpperCase();
logHUD(`💰 Daily Bonus claimed! ${amt} ${cur}`);
state.dailyBonusClaimCount++;
state.dailyBonusLastClaim = new Date().toISOString();
saveState();
updateDailyCount();
}
dailyBonusClaiming = false;
scheduleDailyBonus(25 * 60 * 60 * 1000); // 25h
} catch (e) {
logHUD(`Daily Bonus error: ${e.message}`);
dailyBonusClaiming = false;
scheduleDailyBonus(15 * 60 * 1000);
} finally {
updateDailyBonusStatus();
}
}
function startDailyBonus() {
if (!isStakeUs || !state.dailyBonusEnabled) return;
scheduleDailyBonus(30 * 1000); // First check in 30s
}
function stopDailyBonus() {
clearTimeout(dailyBonusTimer);
dailyBonusTimer = null;
dailyBonusNextCheck = null;
dailyBonusClaiming = false;
updateDailyBonusStatus();
}
function updateDailyCount() {
const el = document.getElementById("csarc-daily-count");
if (el) el.textContent = state.dailyBonusClaimCount || 0;
}
function buildHUD() {
if (document.getElementById("csarc-hud")) return;
const hud = document.createElement("div");
hud.id = "csarc-hud";
hud.style.cssText = [
"position:fixed",
"bottom:10px",
"right:10px",
"width:500px",
"max-height:275px",
"background:rgba(0,0,0,0.87)",
"color:#0f0",
"font:12px/1.4 monospace",
"padding:10px",
"border:1px solid #0f0",
"border-radius:8px",
"z-index:2147483647",
"overflow:hidden",
].join(";");
hud.innerHTML = `
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:7px;text-decoration:underline">
<span style="font-size:15px;font-weight:550;letter-spacing:0.3px"><a href="https://codestats.gg" target="_blank" rel="noopener" style="color:#0f0;text-decoration:underline">CodeStats.gg</a> VIP Reload Claimer v${VERSION}</span>
<button id="csarc-min" style="padding:2px 8px;background:#0f0;color:#000;border:none;border-radius:3px;cursor:pointer;font-weight:bold">−</button>
</div>
<div id="csarc-body">
<div style="display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap">
<button id="csarc-toggle" style="height:26px;padding:0 8px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;cursor:pointer;font-weight:bold;box-sizing:border-box">${state.reloadEnabled ? "RELOAD: ON" : "RELOAD: OFF"}</button>
<button id="csarc-now" style="height:26px;padding:0 8px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;cursor:pointer;font-weight:bold;box-sizing:border-box">CHECK NOW</button>
<label style="color:#aaa;display:flex;align-items:center;gap:4px">Currency:
${isStakeUs
? '<span style="height:26px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;padding:0 8px;font-weight:bold;display:inline-flex;align-items:center">SWEEPS</span>'
: `<select id="csarc-cur" style="height:26px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;padding:0 8px;font-weight:bold;box-sizing:border-box">
${CURRENCIES.map((c) => `<option value="${c}"${c === state.currency ? " selected" : ""}>${c.toUpperCase()}</option>`).join("")}
</select>`}
</label>
<label style="color:#aaa;display:flex;align-items:center;gap:4px">Auto-Vault:
<select id="csarc-vault" style="height:26px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;padding:0 8px;font-weight:bold;box-sizing:border-box">
<option value="0"${!state.autoVault ? " selected" : ""}>OFF</option>
<option value="1"${state.autoVault ? " selected" : ""}>ON</option>
</select>
</label>
</div>
<div id="csarc-daily-row" style="display:flex;align-items:center;gap:6px;margin-bottom:6px;flex-wrap:wrap">
<label style="color:#aaa;display:flex;align-items:center;gap:4px">
${!isStakeUs
? '<span style="height:26px;background:#000;color:#555;border:1px solid #333;border-radius:3px;padding:0 8px;font-weight:bold;display:inline-flex;align-items:center">N/A</span>'
: `<button id="csarc-daily-toggle" style="height:26px;padding:0 8px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;cursor:pointer;font-weight:bold;box-sizing:border-box">DAILY $1: ${state.dailyBonusEnabled ? "ON" : "OFF"}</button>`}
</label>
${!isStakeUs ? '' : '<button id="csarc-daily-check" style="height:26px;padding:0 8px;background:#000;color:#0f0;border:1px solid #0f0;border-radius:3px;cursor:pointer;font-weight:bold;box-sizing:border-box">CHECK NOW</button>'}
<span id="csarc-daily-status" style="font-size:11px;color:#aaa">${!isStakeUs ? "Not on stake.us" : state.dailyBonusEnabled ? "Waiting…" : "Disabled"}</span>
<span style="font-size:11px;color:#0f0">Claims: <strong id="csarc-daily-count">${state.dailyBonusClaimCount || 0}</strong></span>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;font-size:11px;color:#aaa">
<span>Status: <span id="csarc-status" style="color:#0f0">${state.reloadEnabled ? "Starting…" : "Paused"}</span></span>
<span>Claims: <strong id="csarc-count" style="color:#0f0">${state.claimCount}</strong>
<button id="csarc-reset" style="margin-left:5px;padding:1px 5px;background:#600;color:#f66;border:none;border-radius:3px;cursor:pointer;font-size:10px">RESET</button>
</span>
</div>
<div id="csarc-info" style="margin-bottom:4px;font-size:11px;color:#aaa;line-height:1.6"></div>
<div id="csarc-log" style="height:75px;overflow-y:auto;border-top:1px solid #030;padding-top:4px;margin-bottom:4px;font-size:11px"></div>
<div id="csarc-timer" style="font-weight:bold;color:#ff0;font-size:11px"></div>
</div>`;
document.body.appendChild(hud);
document.getElementById("csarc-min").addEventListener("click", () => {
const body = document.getElementById("csarc-body");
const btn = document.getElementById("csarc-min");
if (body.style.display === "none") {
body.style.display = "";
hud.style.maxHeight = "280px";
btn.textContent = "−";
} else {
body.style.display = "none";
hud.style.maxHeight = "40px";
btn.textContent = "+";
}
});
document
.getElementById("csarc-toggle")
.addEventListener("click", () => {
state.reloadEnabled = !state.reloadEnabled;
saveState();
document.getElementById("csarc-toggle").textContent =
state.reloadEnabled ? "RELOAD: ON" : "RELOAD: OFF";
if (state.reloadEnabled) {
setStatus("Resuming…");
logHUD("Reload claims enabled");
checkAndClaim();
} else {
clearTimeout(scheduleTimer);
clearInterval(countdownTimer);
setStatus("Reloads off");
document.getElementById("csarc-timer").textContent = "—";
logHUD("Reload claims disabled");
}
});
document.getElementById("csarc-now").addEventListener("click", () => {
if (claimInProgress) {
logHUD("Already in progress");
return;
}
clearTimeout(scheduleTimer);
clearInterval(countdownTimer);
logHUD("Manual check triggered");
checkAndClaim();
});
const curSelect = document.getElementById("csarc-cur");
if (curSelect) {
curSelect.addEventListener("change", (e) => {
state.currency = e.target.value;
saveState();
logHUD(`Currency: ${state.currency.toUpperCase()}`);
if (lastFaucet) {
setInfo(lastFaucet);
if (lastFaucet.value != null) {
const cur = state.currency;
fetchPrice(cur)
.then((price) => {
if (
price &&
lastFaucet.value != null &&
state.currency === cur
) {
const est = parseFloat(
(lastFaucet.value / price).toFixed(8),
);
setInfo(lastFaucet, null, est);
}
})
.catch(() => {});
}
}
});
}
document
.getElementById("csarc-vault")
.addEventListener("change", (e) => {
state.autoVault = e.target.value === "1";
saveState();
logHUD(`Auto-Vault: ${state.autoVault ? "ON" : "OFF"}`);
});
document.getElementById("csarc-reset").addEventListener("click", () => {
state.claimCount = 0;
saveState();
setCounter();
logHUD("Counter reset");
});
const dailyToggle = document.getElementById("csarc-daily-toggle");
if (dailyToggle) {
dailyToggle.addEventListener("click", () => {
state.dailyBonusEnabled = !state.dailyBonusEnabled;
saveState();
dailyToggle.textContent = `DAILY $1: ${state.dailyBonusEnabled ? "ON" : "OFF"}`;
logHUD(`Daily Bonus: ${state.dailyBonusEnabled ? "ON" : "OFF"}`);
if (state.dailyBonusEnabled) {
startDailyBonus();
} else {
stopDailyBonus();
}
});
}
const dailyCheck = document.getElementById("csarc-daily-check");
if (dailyCheck) {
dailyCheck.addEventListener("click", () => {
if (dailyBonusClaiming) { logHUD("Daily Bonus already in progress"); return; }
clearTimeout(dailyBonusTimer);
logHUD("💰 Manual Daily Bonus check triggered");
checkDailyBonus();
});
}
// Live countdown for daily bonus status
setInterval(() => updateDailyBonusStatus(), 1000);
}
let hudGuard = null;
function watchHUD() {
if (hudGuard) return;
hudGuard = setInterval(() => {
if (!document.getElementById("csarc-hud") && document.body)
buildHUD();
}, 2000);
}
// ===== BOOTSTRAP =====
async function start() {
buildHUD();
watchHUD();
logHUD(`Loaded v${VERSION} successfully.`);
turnstile = new TurnstileManager();
try {
await turnstile.init();
} catch (e) {
logHUD(`Turnstile failed: ${e.message} — reloading…`);
warn("Turnstile init failed:", e);
setStatus("Turnstile error — reloading…");
setTimeout(() => window.location.reload(), 3000);
return;
}
if (isStakeUs && state.dailyBonusEnabled) startDailyBonus();
if (!state.reloadEnabled) {
setStatus("Reloads off");
logHUD("Reload claims disabled");
return;
}
checkAndClaim();
}
function ready(fn) {
if (
document.readyState === "complete" ||
document.readyState === "interactive"
) {
setTimeout(fn, 1000);
} else {
document.addEventListener("DOMContentLoaded", () =>
setTimeout(fn, 1000),
);
}
}
ready(start);
})();