Розробка системи джекпотів на блокчейні
Jackpot система в крипто-казино — механіка, де частина кожної ставки йде в накапливаємий приз, який виграє випадковий гравець. Прогресивний джекпот створює excitement й FOMO — користувачі продовжують грати тому що «в будь-який момент я можу сорвати джекпот».
Типи джекпотів
Progressive jackpot: фонд зростає з кожною ставкою (зазвичай 1-3% від кожної ставки). Немає фіксованого потолку. Рідко срабатывает але може вирости дуже великим.
Fixed jackpot: фіксований приз, який срабатывает при певній умові (випадення конкретної комбінації символів у Slots, конкретний множник у Crash).
Must-hit-by jackpot: гарантовано сорвётся до досягнення певної суми. Знижує дисперсію для оператора.
Tiered jackpot: кілька рівнів (Mini, Minor, Major, Grand/Mega). Різні ймовірності й розміри. Гравці з більшими ставками отримують доступ до вищих тірів.
Реалізація смарт контракту
contract JackpotSystem {
struct Jackpot {
uint256 currentAmount;
uint256 seedAmount; // мінімум в джекпоті після срабатывання
uint256 contributionRate; // % від ставок (basis points)
uint256 winProbabilityBase; // базова ймовірність (basis points за одиницю ставки)
uint256 minTriggerAmount; // мінімум для срабатывання
uint256 maxTriggerAmount; // для must-hit-by
bool isActive;
}
Jackpot[4] public jackpots; // MINI, MINOR, MAJOR, GRAND
// Тирові вимоги (мінімальна ставка для участі)
uint256[4] public tierMinBet = [0.001 ether, 0.01 ether, 0.1 ether, 1 ether];
event JackpotWon(uint256 indexed tierId, address winner, uint256 amount);
event JackpotContribution(uint256 indexed tierId, uint256 amount, uint256 newTotal);
// Взнос при кожній ставці
function contributeToJackpots(uint256 betAmount) external onlyGameContract {
for (uint8 tier = 0; tier < 4; tier++) {
if (betAmount >= tierMinBet[tier] && jackpots[tier].isActive) {
uint256 contribution = (betAmount * jackpots[tier].contributionRate) / 10000;
jackpots[tier].currentAmount += contribution;
emit JackpotContribution(tier, contribution, jackpots[tier].currentAmount);
}
}
}
// Перевірка jackpot виграшу (викликається після кожної ставки)
function checkJackpot(
address player,
uint256 betAmount,
uint256 random
) external onlyGameContract returns (uint256 wonTier, uint256 wonAmount) {
for (uint8 tier = 3; tier >= 0; tier--) { // перевіряємо від GRAND до MINI
Jackpot storage jp = jackpots[tier];
if (!jp.isActive || betAmount < tierMinBet[tier]) continue;
if (jp.currentAmount < jp.minTriggerAmount) continue;
// Ймовірність пропорційна ставці
uint256 probability = (jp.winProbabilityBase * betAmount) / 1 ether;
// Must-hit-by: збільшуємо ймовірність при наближенні до максимуму
if (jp.maxTriggerAmount > 0 && jp.currentAmount >= jp.maxTriggerAmount * 9 / 10) {
probability = probability * 10; // x10 ймовірність в останніх 10%
}
uint256 roll = random % 1_000_000;
if (roll < probability) {
wonTier = tier;
wonAmount = jp.currentAmount;
// Скидаємо джекпот до seed amount
jp.currentAmount = jp.seedAmount;
// Виплата
payable(player).transfer(wonAmount);
emit JackpotWon(tier, player, wonAmount);
break;
}
if (tier == 0) break; // uint8 не піде в negative
}
}
}
Інтеграція Chainlink VRF
Для джекпота критично важливо мати чесний random — це найбільші виплати:
// Jackpot-specific VRF запрос: більш високий REQUEST_CONFIRMATIONS
function requestJackpotRandom(address player, uint256 betAmount)
external onlyGameContract returns (uint256 requestId)
{
requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: KEY_HASH,
subId: SUBSCRIPTION_ID,
requestConfirmations: 5, // додаткові confirmations для крупних виплат
callbackGasLimit: 150_000,
numWords: 1,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
)
})
);
jackpotRequests[requestId] = JackpotRequest({ player: player, betAmount: betAmount });
}
Jackpot дисплей — психологія накопичення
Візуалізація зростаючого лічильника — обов'язкова:
// Real-time оновлення через WebSocket
function JackpotDisplay({ tierId }: { tierId: number }) {
const [amount, setAmount] = useState(0);
const animatedAmount = useAnimatedCounter(amount, 1500); // 1.5s анімація
useEffect(() => {
const ws = new WebSocket(WS_URL);
ws.on("jackpot_update", (data) => {
if (data.tierId === tierId) {
setAmount(data.newAmount);
}
});
return () => ws.close();
}, [tierId]);
return (
<div className={`jackpot-display jackpot-tier-${tierId}`}>
<span className="jackpot-label">{TIER_NAMES[tierId]}</span>
<span className="jackpot-amount">
${formatCurrency(animatedAmount)}
</span>
</div>
);
}
Анімований лічильник, постійно зростаючий — потужний психологічний тригер. Звукові ефекти при крупних взносах («тик» кожні $100) посилюють ефект.
Історія й транзакції
Публічна історія перемог критична для довіри:
CREATE TABLE jackpot_wins (
id SERIAL PRIMARY KEY,
tier VARCHAR(16) NOT NULL,
winner_address VARCHAR(42) NOT NULL,
amount NUMERIC(36, 18) NOT NULL,
tx_hash VARCHAR(66) NOT NULL,
game_type VARCHAR(64),
won_at TIMESTAMPTZ DEFAULT NOW()
);
Розробка системи джекпотів: 4 рівні + інтеграція з ігровими контрактами + Chainlink VRF + real-time дисплей — 3-5 тижнів.







