// ==UserScript== // @name Stake.com Visual Balance Modifier (Working In-Game) (ONLY STAKE ORIGINALS) // @namespace http://tampermonkey.net/ // @version 8.0 // @description Adds a persistent fake BTC balance and an integrated settings UI in the website footer to visually simulate gameplay on Stake.com. // @author XaRTeCK (Using Gemini 2.5 Pro NGL :3) // @match *://stake.com/* // @match *://rgs.twist-rgs.com/* // @connect stake.com // @connect rgs.twist-rgs.com // @license CC-BY-NC-ND-4.0 // @grant none // @run-at document-start // @downloadURL none // ==/UserScript== (function() { 'use strict'; const BALANCE_STORAGE_KEY = 'stake_fake_btc_balance_v4'; const WELCOME_MSG_KEY = 'stake_welcome_msg_shown_v5'; const DEFAULT_BTC_VALUE = 0.0047; // Approximately $500 USD if 1 BTC = $105,000 let currentFakeBet = { amount: 0, currency: null }; function getFakeBtcValue() { const savedBalance = localStorage.getItem(BALANCE_STORAGE_KEY); return savedBalance ? parseFloat(savedBalance) : DEFAULT_BTC_VALUE; } function setFakeBtcValue(amount) { const numericAmount = parseFloat(amount); if (!isNaN(numericAmount) && numericAmount >= 0) { localStorage.setItem(BALANCE_STORAGE_KEY, numericAmount.toString()); // This forces the balance display component to re-render with the new value const balanceToggle = document.querySelector('[data-testid="balance-toggle"] button'); if (balanceToggle) { balanceToggle.click(); balanceToggle.click(); } } } function showWelcomePopup() { if (localStorage.getItem(WELCOME_MSG_KEY)) return; const popupHTML = `

Gameplay Modifier Active

Your fake balance is ${getFakeBtcValue()} BTC. To change this amount, scroll to the very bottom of the Stake.com page.

`; document.body.insertAdjacentHTML('beforeend', popupHTML); document.getElementById('visual-script-close').addEventListener('click', () => { document.getElementById('visual-script-welcome')?.remove(); document.getElementById('visual-script-overlay')?.remove(); localStorage.setItem(WELCOME_MSG_KEY, 'true'); }); } function injectBalanceSettings(footerElement) { if (document.getElementById('fake-balance-settings')) return; const settingsHTML = `

This only changes the balance you see on your screen.

Saved!
`; footerElement.insertAdjacentHTML('afterbegin', settingsHTML); const input = document.getElementById('fake-balance-input-btc'); const savedMessage = document.getElementById('fake-balance-saved'); let timeoutId; input.addEventListener('input', (event) => { setFakeBtcValue(event.target.value); savedMessage.style.opacity = '1'; clearTimeout(timeoutId); timeoutId = setTimeout(() => { savedMessage.style.opacity = '0'; }, 1500); }); } const originalFetch = window.fetch; window.fetch = async function(url, options) { const FAKE_BTC_BALANCE = getFakeBtcValue(); const FAKE_PROVIDER_BALANCE = FAKE_BTC_BALANCE * 100_000_000; const requestUrl = new URL(url.toString(), window.location.origin); const host = requestUrl.hostname; const path = requestUrl.pathname; if (host.includes('rgs.twist-rgs.com') && path.includes('/wallet/authenticate')) { const response = await originalFetch(url, options); const data = await response.clone().json(); if (data.balance) data.balance.amount = FAKE_PROVIDER_BALANCE; return new Response(JSON.stringify(data), { status: 200, headers: response.headers }); } if (host.includes('stake.com') && path.includes('/_api/graphql') && options?.body) { let requestBody; try { requestBody = JSON.parse(options.body); } catch (e) { return originalFetch(url, options); } let modifiedOptions = options; if (requestBody.operationName === 'UserBalances') { const response = await originalFetch(url, options); const data = await response.clone().json(); const btcBalance = data?.data?.user?.balances.find(b => b.available.currency === 'btc'); if (btcBalance) { btcBalance.available.amount = FAKE_BTC_BALANCE; } return new Response(JSON.stringify(data), { status: response.status, headers: response.headers }); } if (requestBody.query?.includes('mutation') && requestBody.variables?.amount > 0) { currentFakeBet = { amount: requestBody.variables.amount, currency: requestBody.variables.currency }; const modifiedBody = JSON.parse(JSON.stringify(requestBody)); modifiedBody.variables.amount = 0; modifiedOptions = { ...options, body: JSON.stringify(modifiedBody) }; } const response = await originalFetch(url, modifiedOptions); const responseClone = response.clone(); try { const data = await response.json(); if (data.data) { const gameDataKey = Object.keys(data.data).find(key => data.data[key] && typeof data.data[key] === 'object' && 'amount' in data.data[key]); if (gameDataKey && currentFakeBet.amount > 0) { const gameData = data.data[gameDataKey]; gameData.amount = currentFakeBet.amount; if (gameData.payoutMultiplier > 0) gameData.payout = gameData.payoutMultiplier * currentFakeBet.amount; if (!gameData.active) currentFakeBet = { amount: 0, currency: null }; return new Response(JSON.stringify(data), { status: 200, headers: response.headers }); } } return responseClone; } catch (e) { return responseClone; } } if (host.includes('stake.com') && path.startsWith('/_api/casino/')) { let modifiedOptions = options; if (/\/(bet|roll|bonus)$/.test(path) && options?.body) { try { const originalRequestBody = JSON.parse(options.body); const modifiedBody = { ...originalRequestBody }; let totalAmount = 0; if (path.includes('/roulette/bet')) { ['colors', 'parities', 'dozens', 'numbers', 'columns', 'halves'].forEach(key => { if (Array.isArray(modifiedBody[key])) { modifiedBody[key].forEach(bet => { totalAmount += bet.amount; bet.amount = 0; }); } }); } else if (originalRequestBody.amount > 0) { totalAmount = originalRequestBody.amount; modifiedBody.amount = 0; } if (totalAmount > 0) { currentFakeBet = { amount: totalAmount, currency: originalRequestBody.currency }; modifiedOptions = { ...options, body: JSON.stringify(modifiedBody) }; } } catch (e) {} } const response = await originalFetch(url, modifiedOptions); const responseClone = response.clone(); try { const data = await response.json(); const gameDataKey = Object.keys(data).find(key => data[key] && typeof data[key] === 'object' && 'amount' in data[key]); if (gameDataKey && currentFakeBet.amount > 0 && data[gameDataKey].currency === currentFakeBet.currency) { const gameData = data[gameDataKey]; gameData.amount = currentFakeBet.amount; if (gameData.payoutMultiplier > 0) gameData.payout = gameData.payoutMultiplier * currentFakeBet.amount; if (gameData.state?.rounds) gameData.state.rounds.forEach(r => { if ('amount' in r) r.amount = currentFakeBet.amount; }); if (!gameData.active) currentFakeBet = { amount: 0, currency: null }; return new Response(JSON.stringify(data), { status: 200, headers: response.headers }); } return responseClone; } catch (e) { return responseClone; } } return originalFetch(url, options); }; window.addEventListener('DOMContentLoaded', () => { showWelcomePopup(); const footerObserver = new MutationObserver((mutations, observer) => { const footer = document.querySelector('footer[data-testid="footer"]'); if (footer) { injectBalanceSettings(footer); observer.disconnect(); // Stop observing once the footer is found and injected } }); footerObserver.observe(document.body, { childList: true, subtree: true }); }); })();