// SPDX-License-Identifier: UNLICENSED // Proprietary - (c) 2026 Durian (durianfun). All rights reserved. Not open source; for Durianfun + authorized integrations only. See /LICENSE. pragma solidity 0.8.24; import "../EntropyConsumer.sol"; import "../EntropyLib.sol"; /// @title RouletteConsumer /// @notice Example: a single-signature European roulette spin (0..36), keeper-free. No real money in /// this demo (it records the pocket) — it pairs with dumb-roulette/index.html. Each spin pays /// the protocol fee and self-cranks the previous spin so results land without a 2nd user tx. /// /// A REAL money roulette must escrow the stake at spin() time, pay out in _onRandomness, /// forfeit on expiry, and CAP the aggregate stake per block (see CoinFlipHouse + plan). contract RouletteConsumer is EntropyConsumer { using EntropyLib for uint256; uint32 public constant CB_GAS = 120_000; mapping(uint256 => address) public spinner; mapping(uint256 => uint8) public pocketOf; // 37 = unsettled uint256 private _nonce; uint256 private _lastPending = type(uint256).max; event SpinRequested(uint256 indexed id, address indexed player); event SpinResult(uint256 indexed id, address indexed player, uint8 pocket, bool red); constructor(address e) EntropyConsumer(e) {} function spin() external payable { uint256 f = entropy.fee(CB_GAS); require(msg.value >= f, "fee"); if (_lastPending != type(uint256).max) _tryReveal(_lastPending); bytes32 seed = keccak256(abi.encodePacked(msg.sender, block.number, _nonce++)); uint256 id = _roll(seed, CB_GAS); spinner[id] = msg.sender; pocketOf[id] = 37; _lastPending = id; emit SpinRequested(id, msg.sender); if (msg.value > f) { (bool ok, ) = msg.sender.call{value: msg.value - f}(""); // refund overpay require(ok, "refund failed"); } } function _onRandomness(uint256 id, uint256 rng) internal override { address p = spinner[id]; delete spinner[id]; uint8 pocket = uint8(rng.pick(0, 37)); pocketOf[id] = pocket; emit SpinResult(id, p, pocket, _isRed(pocket)); } function _isRed(uint8 n) private pure returns (bool) { if (n == 0) return false; uint256 redMask = 0x154AAD52AA; // bit n => red, verified for n in 1..36 return (redMask >> n) & 1 == 1; } }