# Casino Integration

This page is for developers, vibe coders and AI agents who want to wrap the contracts in their own product. Whether you're building a Telegram bot, a Farcaster Frame, a custom skinned frontend, an AI agent that plays Blackjack on its own terms, or a niche-language UI for a community Overtime hasn't reached, everything you need is in the repo.

***

### TL;DR for the impatient

* **Contracts:** [`github.com/thales-markets/contracts-v2`](https://github.com/thales-markets/contracts-v2), in `contracts/core/Casino/` five Solidity files, MIT-licensed, \~5k lines total.
* **Networks:** Base, Optimism, Arbitrum.
* **Collaterals:** USDC, WETH, $OVER.
* **Randomness:** Chainlink VRF v2.5 (`IVRFCoordinatorV2Plus`).
* **Each game = one contract.** Same shape:&#x20;
  * `placeBet` → `requestRandomWords` → `rawFulfillRandomWords` → resolved.
* **Pass a `_referrer` address** on every bet you make on behalf of users to capture up to 20% of generated fees automatically.
* **Free bets supported** via `placeBetWithFreeBet` against the existing Overtime `IFreeBetsHolder`.

***

### A note for AI agents and vibe coders: use Eth Skills

If you're an AI agent, or you're prompting one, building on Ethereum, the best starting point isn't this page or even the Overtime repo. It's [**ethskills.com**](https://ethskills.com/).

ETHSKILLS is an open library of skill files that fix the things LLMs get wrong about Ethereum out of the box. Stale gas prices. Hallucinated contract addresses. Outdated patterns. Wrong terminology ("on-chain" vs "onchain"). It's structured as fetch-on-demand markdown files an agent can pull at runtime.

Recommended skills to read before integrating with Overtime Casino:

* [**`ethskills.com/SKILL.md`**](https://ethskills.com/SKILL.md): table of contents and overall framing
* [**`ethskills.com/tools/SKILL.md`**](https://ethskills.com/tools/SKILL.md): current tooling (Foundry, Scaffold-ETH 2, abi.ninja, MCPs)
* [**`ethskills.com/standards/SKILL.md`**](https://ethskills.com/standards/SKILL.md): ERC-20, EIP-7702, ERC-8004 (agent identity)
* [**`ethskills.com/orchestration/SKILL.md`**](https://ethskills.com/orchestration/SKILL.md): three-phase build pattern (localhost → live testnet → production)
* **The Chainlink VRF skill in cryptoskills.dev**, VRF v2.5 specifics, subscription management, callback patterns

Bootstrap your project with `npx create-eth@latest` if you want a working Scaffold-ETH 2 frontend wired to a local hardhat fork in 60 seconds. Then point it at the Casino contracts.

The rest of this guide assumes you have basic web3 tooling set up. If you don't, the Eth Skills route will get you there faster than reading 50 docs pages.

***

### Repository layout

```
contracts-v2/
└── contracts/
    └── core/
        └── Casino/
            ├── Roulette.sol     # 6 bet types, up to 10 picks per spin
            ├── Dice.sol         # d20, ROLL_OVER / ROLL_UNDER
            ├── Blackjack.sol    # state machine, hit/stand/double/split
            ├── Baccarat.sol     # Player/Banker/Tie, full Punto Banco
            └── Slots.sol        # 3-reel, configurable symbols/payouts
```

Each file is self-contained, written in Solidity 0.8.20, follows OpenZeppelin upgradeable patterns (`Initializable`, `ProxyOwned`, `ProxyPausable`, `ProxyReentrancyGuard`), and has `@notice` natspec on virtually every public function.

***

### The shape every Casino contract shares

This is the part worth internalizing. Once you understand the lifecycle of one contract, you understand all five.

#### Public entry points

```solidity
// Place a real-money bet
function placeBet(
    address collateral,    // USDC, WETH, or $OVER
    uint amount,           // collateral amount, in token-native decimals
    /* game-specific args (bet type, selection, target, etc.) */
    address _referrer      // your affiliate wallet, or address(0)
) external returns (uint betId, uint requestId);

// Place a bet using the user's free-bet balance
function placeBetWithFreeBet(
    address collateral,
    uint amount,
    /* game-specific args */
) external returns (uint betId, uint requestId);

// Cancel a stuck bet after cancelTimeout
function cancelBet(uint betId) external;
```

Roulette additionally exposes `placeMultiBet` and `placeMultiBetWithFreeBet` for multi-pick spins; Blackjack exposes per-action entrypoints (`hit`, `stand`, `doubleDown`, `split`) on top of the initial `placeBet` (named `deal` in some flows).

#### Internal lifecycle

```
user calls placeBet
  ├─ pulls collateral via safeTransferFrom
  ├─ validates selection / target / pick list
  ├─ computes worst-case payout, reserves it against bankroll
  ├─ calls vrfCoordinator.requestRandomWords(...)
  ├─ stores Bet struct, status = PENDING
  └─ emits BetPlaced(betId, requestId, user, collateral, amount, ...)

[time passes — Chainlink generates randomness]

vrfCoordinator calls rawFulfillRandomWords(requestId, randomWords[])
  ├─ msg.sender check: only vrfCoordinator can call this
  ├─ derives game outcome from randomWords[0]
  ├─ updates bet status = RESOLVED
  ├─ transfers payout (if won), pays referrer (if lost)
  └─ emits BetResolved(betId, requestId, user, result, won, payout)
```

That's the whole loop. Every game contract follows it. The only differences are what happens between "derive outcome" and "compute payout", game-specific math.

#### Events you'll want to index

| Event                                                                                   | When it fires                             |
| --------------------------------------------------------------------------------------- | ----------------------------------------- |
| `BetPlaced(betId, requestId, user, collateral, amount, ...)`                            | User places a bet, before VRF callback    |
| `MultiBetPlaced(betId, requestId, user, collateral, totalAmount, pickCount, isFreeBet)` | Roulette only, multi-pick bets            |
| `BetResolved(betId, requestId, user, result, won, payout)`                              | VRF fulfills and bet resolves             |
| `BetCancelled(betId, requestId, user, refundedAmount, adminCancelled)`                  | User or admin cancels a stuck bet         |
| `ReferrerPaid(referrer, user, amount, betAmount, collateral)`                           | Affiliate fee transferred on a losing bet |

For Blackjack, additional events fire for action transitions (`HandActionRequested`, `CardDealt`, etc.). The full event list lives at the bottom of each contract source file.

***

### Quickstart: place a Roulette bet from a TypeScript frontend

```typescript
import { ethers } from "ethers";
import RouletteABI from "./abi/Roulette.json";
import IERC20ABI from "./abi/IERC20.json";

const ROULETTE_ADDRESS = "0x..."; // deployed Roulette address on your target chain
const USDC_ADDRESS    = "0x..."; // USDC on the same chain
const REFERRER        = "0xYOURAFFILIATEWALLET"; // or ethers.ZeroAddress

const provider = new ethers.BrowserProvider(window.ethereum);
const signer   = await provider.getSigner();

const usdc     = new ethers.Contract(USDC_ADDRESS,    IERC20ABI,    signer);
const roulette = new ethers.Contract(ROULETTE_ADDRESS, RouletteABI, signer);

// 1. One-time approval
const stake = 5_000_000n; // 5 USDC (6 decimals)
await (await usdc.approve(ROULETTE_ADDRESS, stake)).wait();

// 2. Place a STRAIGHT bet on number 17
const BetType = { STRAIGHT: 0, RED_BLACK: 1, ODD_EVEN: 2, LOW_HIGH: 3, DOZEN: 4, COLUMN: 5 };
const tx = await roulette.placeBet(USDC_ADDRESS, stake, BetType.STRAIGHT, 17, REFERRER);
const receipt = await tx.wait();

// Extract betId from the BetPlaced event
const event = receipt.logs
  .map(l => { try { return roulette.interface.parseLog(l); } catch { return null; } })
  .find(e => e && e.name === "BetPlaced");
const betId = event.args.betId;

// 3. Wait for resolution by listening for BetResolved
roulette.on("BetResolved", (resolvedBetId, requestId, user, result, won, payout) => {
  if (resolvedBetId === betId) {
    console.log(`Spin result: ${result}, won: ${won}, payout: ${payout}`);
  }
});
```

This is the complete pattern. Substitute the bet type, args and contract address for each game, and the same flow applies.

***

### Quickstart: place a Dice bet from an AI agent (viem)

```typescript
import { createPublicClient, createWalletClient, http, parseAbi } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount(process.env.AGENT_KEY as `0x${string}`);
const wallet  = createWalletClient({ account, chain: base, transport: http() });
const client  = createPublicClient({ chain: base, transport: http() });

const DICE      = "0x...";
const USDC      = "0x...";
const REFERRER  = "0xYOURAFFILIATEWALLET";

const diceAbi = parseAbi([
  "function placeBet(address collateral, uint256 amount, uint8 betType, uint8 target, address referrer) external returns (uint256, uint256)",
  "event BetResolved(uint256 indexed betId, uint256 indexed requestId, address indexed user, uint8 result, bool won, uint256 payout)",
]);

// ROLL_UNDER 11 = 50% probability
const BetType = { ROLL_UNDER: 0, ROLL_OVER: 1 };

const hash = await wallet.writeContract({
  address: DICE,
  abi: diceAbi,
  functionName: "placeBet",
  args: [USDC, 5_000_000n, BetType.ROLL_UNDER, 11, REFERRER],
});

const receipt = await client.waitForTransactionReceipt({ hash });
// ... parse logs the same way as above
```

For agents specifically, the design is friendly:

* **Each contract is a single-purpose machine.** Small public surface, well-named functions, deterministic behavior.
* **State is queryable.** Read `bets[betId]` (or game-equivalent) to recover any bet's full state at any time.
* **Events are reliable.** Index `BetResolved` to build a "watch and react" loop without polling state.
* **No hidden auth.** No API keys. No login. No CAPTCHA. The wallet *is* the auth.

***

### Reading game configuration from chain

Before you place bets at scale (or expose a slot's RTP to your users), read the relevant configuration directly:

```typescript
// Dice — what's the current house edge?
const houseEdge = await dice.read.houseEdge();
// Returns 1e18-precision; 1e16 = 1%

// Slots — what's the pay table?
const symbolCount = await slots.read.symbolCount();
const weights: bigint[] = [];
const triples: bigint[] = [];
const pairs:   bigint[] = [];
for (let i = 0; i < Number(symbolCount); i++) {
  weights.push(await slots.read.symbolWeights([i]));
  triples.push(await slots.read.triplePayout([i]));
  pairs.push  (await slots.read.pairPayout([i]));
}

// Baccarat — what's the current Banker payout multiplier?
const bankerMul = await baccarat.read.bankerPayoutMultiplier();
// 1.95e18 = 1.95×

// Roulette — what's the maxProfitUsd cap?
const maxProfitUsd = await roulette.read.maxProfitUsd();
```

There is no "pull this from the API and trust the operator." The chain *is* the API.

***

### Free bets

If your product serves users who already have an Overtime free-bet balance, call `placeBetWithFreeBet` (or `placeMultiBetWithFreeBet` in Roulette) instead of `placeBet`. The signature is identical except no collateral pull happens — the contract debits the user's free-bet balance via the existing `IFreeBetsHolder`.

```solidity
function placeBetWithFreeBet(
    address collateral,
    uint amount,
    BetType betType,
    uint8 selection
) external returns (uint betId, uint requestId);
```

Free-bet wins are settled to `freeBetsHolder` automatically. Your frontend doesn't need to do anything special beyond the call itself.

***

### Bankroll, liquidity, and bet sizing

Every Casino contract maintains a **per-collateral bankroll reservation** (`reservedProfitPerCollateral`). When a bet is placed, the contract reserves the worst-case payout against the bankroll. If the bankroll is insufficient at that moment, the bet reverts with `InsufficientAvailableLiquidity`.

For Roulette specifically, multi-pick bets compute the **worst-case net liability across all 37 wheel outcomes**, not the naive sum of all picks' payouts. Mutually exclusive picks (e.g. Dozen 1 + Dozen 2) don't double-reserve. This is implemented in `_worstCaseProfit`. If you write a custom client, mirror this logic when validating bets locally to avoid wasted reverts.

There's also a per-bet `maxProfitUsd` cap, normalized through the Chainlink price feed. Large bets that would exceed it revert with `MaxProfitExceeded`. Your frontend should query `maxProfitUsd` and `getCollateralPrice(collateral)` and gate the user before submission.

***

### Cancellation flow

If a Chainlink VRF callback never arrives (very rare; possible during Chainlink network incidents):

```solidity
function cancelBet(uint betId) external;
```

After `cancelTimeout` (minimum 30 seconds, configurable per game) has passed since the bet was placed, the user can cancel and recover their full stake. Your frontend should expose this as a "Recover stake" button on stuck bets, and ideally hide it behind a 30+ second elapsed-time check so users don't see it on bets that will resolve normally.

There is also `adminCancelBet`, callable only by addresses with the `MARKET_RESOLVING` role on the Overtime manager. Operators (including 3rd-party integrations using their own deployment) can use this for ops emergencies, but **on the canonical Overtime deployment, the user-driven `cancelBet` is the path.**

***

### Pausability

Every contract is `ProxyPausable`. The owner (or addresses with the `TICKET_PAUSER` role) can pause new bets via `setPausedByRole`. **Already-pending bets continue to resolve.** Cancellation paths remain available.

Your frontend should handle the `Paused` revert gracefully and surface a clear "casino paused" state. The pause state itself is readable via `paused()`.

***

### Subgraph and indexing

Overtime maintains a public subgraph that indexes all Casino events across supported chains. If you don't want to run your own indexer, query that. URL and schema are at **docs.overtime.io**.

If you do want your own indexer:

* **Self-host with The Graph node**, Goldsky, Envio, or Ponder
* **Index every contract per chain** (5 contracts × 3 chains = 15 contract instances)
* **Watch for proxy upgrades** — these are upgradeable proxies. Address is stable, but ABI may change. Re-pull ABIs after major version bumps.

***

### Security and operational notes

* **Always validate user input client-side** before submitting bets, wrong selection encodings will revert. The interface clarity (`enum BetType`, `uint8 selection`) is a feature; mirror those types in your frontend.
* **Watch for `requestId == 0` collision**: the contracts use `requestIdToBetId` mapping. A `requestId` of zero is treated as "unknown." This is a Chainlink-side guarantee; just be aware.
* **Reentrancy is handled** by `ProxyReentrancyGuard` on every state-mutating function. You don't need to wrap calls in your own reentrancy protection.
* **The CEI pattern** (Checks → Effects → Interactions) is followed in all resolution paths. Bet status flips to `RESOLVED` *before* payout transfers go out. If a payout transfer fails, the resolution still stands; the user retains a claim against the contract balance.
* **Don't hardcode contract addresses.** Read them from the Overtime documentation site or the deployments JSON in the repo. Addresses can vary per chain. **Never hallucinate**, verify on a block explorer.

***

### Don't like the canonical frontend? Build your own.

This is the point. The contracts are public infrastructure. The frontend at overtimemarkets.xyz is *one* possible interface, not *the* interface.

A few examples of what you can ship in an afternoon:

* **A Telegram bot** that lets users place dice rolls in chat, with their own wallet, your address as referrer
* **A Discord game** that runs Blackjack hands inside a server's casino channel
* **A Farcaster Frame** with a "spin slots" button
* **An AI agent** that plays Blackjack autonomously, sized to a budget, optimizing for variance
* **A specialized roulette UI** for a community that wants different table aesthetics, language localization, custom multi-pick presets
* **An embedded widget** on your existing crypto site that lets your users bet from your platform

Pass your `_referrer` address into every bet, and you capture **up to 20% of generated fees** from every interaction. See Become an Overtime Casino Affiliate for the affiliate side.

***

### Resources

* **Contracts repo:** [github.com/thales-markets/contracts-v2](https://github.com/thales-markets/contracts-v2) → `contracts/core/Casino/`
* **Overtime docs:** [docs.overtime.io](https://docs.overtime.io)
* **Chainlink VRF v2.5 docs:** [docs.chain.link/vrf/v2-5/overview](https://docs.chain.link/vrf/v2-5/overview)
* **Eth Skills (for AI agents and vibe coders):** [ethskills.com](https://ethskills.com/)
* **Scaffold-ETH 2:** `npx create-eth@latest`

The casino is a public utility, we want to see what gets built on top!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.overtime.io/overtime-casino/casino-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
