# betBlox developers guide

Welcome to the developer documentation for **betBlox** the decentralized betting infrastucture protocol. betBlox allows anyone to build and run decentralised non-custodial onchain betting dapps and services This guide will help you understand the architecture, interact with the smart contracts, and build applications on top of the betBlox protocol. Additionally the guide covers the use of betBase community services like the betBase API, betBase oracle, betBlox subgraph and the bloxTester dev test tool.

### Introduction

betBlox is a decentralized protocol designed to facilitate decentralized fully onchain non-custodial peer-to-peer betting markets. It uses EVM smart contracts to ensure transparency, security, and trustless execution of bets and markets. The protocol implements a virtual Onchain Betting Market (OBM) that allows users to place bets onchain or to become market makers and create markets for other bettors.

### Protocol Architecture

The betBlox protocol is built on a modular architecture, separating concerns into distinct contracts for better maintainability and upgradability. The first version of betBlox implements greenBlox for Sports betting and simple predictions. Future versions will implement blue, purple and orangeBlox for a complete suite of betting products.

#### Core Components

1. **BetHandler**: The primary entry point for placing bets. It validates bet parameters and interacts with the MarketHandler to record bets.
2. **MarketHandler**: Manages the lifecycle of betting markets. It handles liquidity, odds, and settlement logic.
3. **EventHandler**: Acts as the source of truth for event data (e.g., sports match results). It tracks the state of events (Active, Playing, Completed) and ensures markets are settled correctly based on these states.
4. **MarketmakerBox (lite)**: The vault system where market makers deposit control their liquidity and earn fees.
5. **ParlayHandler**: A specialized handler for parlay bets, coordinating across multiple markets and events.
6. **LockBox**: The foundational contract for locking bets and ensuring secure deposit and withdrawal of funds.

#### Interaction Flow

1. **Create a MarketMaker**: Create a MarketMakerBox via the MarketMakerBoxFactory.
2. **Create a Market**: A Market Maker creates a market via `MarketHandler`, specifying the event and odds. Liquidity is reserved from their `MarketmakerBox`.
3. **Place a Bet**: A user calls `addBet` on `BetHandler`. The contract verifies the market and odds, transfers the user's stake, and records the bet.
4. **Resolve an Event**: An Oracle or authorized entity updates the event state in `EventHandler` to "Completed" and provides the result.
5. **Settle a Market**: `MarketHandler` uses the event result to determine winning outcomes. **Note**: Settlement is a permissionless action; once the event is completed, anyone (Market Maker, Bettor, or a third party) can call `settleMarket` to finalize the market.
6. **Claim Payouts**: Winners can claim their payouts via `payoutBet` in `BetHandler`, which releases the funds from the `bet-lockbox` (LockBox) and the locked stakes.

***

### Smart Contract Reference

This section provides a detailed reference for the core smart contracts in the betBlox protocol.

#### BetHandler.sol

**Introduction:** This contract handles the betting logic. It communicates with the `MarketHandler` to add bets to markets and manages the lifecycle of a bet.

**External Functions:**

* `setBetAgent(address inBetAgent)`: Sets a bet agent for the caller, allowing the agent to place bets on their behalf.
* `addBet(bytes32 marketHash, uint256 betAmount, uint256 odds, uint16 outcomeId)`: Adds a regular bet to a market on behalf of the caller.
* `agentBet(bytes32 marketHash, address bettor, uint256 betAmount, uint256 odds, uint16 outcomeId)`: Adds a bet to a market on behalf of another user (requires being their agent).
* `payoutBet(bytes32 betHash)`: Pays out a winning bet to the bettor. Settles the market first if necessary.
* `payoutBets(bytes32[] calldata betHashes)`: Pays out a list of winning bets. Efficient for batch processing.

**View Only Functions:**

* `token()`: Returns the address of the betting token.
* `tokenDecimals()`: Returns the number of precision decimals in the betting token.

#### EventHandler.sol

**Introduction:** This contract manages events, including storing event data, tracking states (Active, Playing, Completed), and firing chain events. It acts as a central registry for events.

**External Functions:**

* `checkOrAddEvent(bytes32 eventHash, uint32 marketType, address marketmaker)`: Checks if an event exists for a new market, or adds it if it doesn't.
* `addEvent(bytes32 eventHash, uint32 eventType)`: Adds a marketmaker-controlled event.
* `setEventActive(bytes32 eventHash, uint32 eventType)`: Updates an event to the Active state (called by Oracle).
* `setEventPlaying(bytes32 eventHash)`: Updates an event to the Playing state.
* `completeEvent(bytes32 eventHash, EventResult calldata result)`: Updates an event to the Completed state and records the result.
* `cancelEvent(bytes32 eventHash)`: Cancels an event.
* `invalidateEvent(bytes32 eventHash)`: Invalidates an event.

**View Only Functions:**

* `getEventData(bytes32 eventHash)`: Returns the full data of an event.
* `getEventState(bytes32 eventHash)`: Returns the current state of an event.
* `getEventResult(bytes32 eventHash)`: Returns the result of a completed event.
* `isOracleEvent(bytes32 eventHash)`: Checks if an event is controlled by an Oracle.
* `owner(bytes32 eventHash)`: Returns the owner of an event.
* `isValidMarket(uint32 inEventType, uint32 inMarketType)`: Checks if a market type is valid for a given event type.
* `isValidResult(uint32 inEventType, EventResult calldata inResult)`: Checks if a result is valid for a given event type.
* `assertEventIsActive(bytes32 eventHash)`: Reverts if the event is not in the Active state.
* `assertEventIsActiveOrPlaying(bytes32 eventHash)`: Reverts if the event is not Active or Playing.

#### MarketHandler.sol

**Introduction:** This contract handles markets, including storing market data, managing liquidity, and processing settlements. It interacts with `EventHandler` and `BetHandler`.

**External Functions:**

* `addMarket(...)`: Adds a new market with liquidity, odds, and other parameters.
* `addBet(BetData calldata bet)`: Adds a bet to a market (restricted to `BETS_ROLE`, i.e., `BetHandler`).
* `addLiquidity(bytes32 marketHash, uint256 inAmount)`: Adds additional liquidity to an existing market.
* `removeLiquidity(bytes32 marketHash, uint256 inAmount)`: Removes unused liquidity from a market.
* `setOdds(bytes32 marketHash, uint16 outcomeId, uint256 inOdds)`: Updates the odds for a specific outcome in a market.
* `settleMarket(bytes32 marketHash)`: Settles a market to prepare it for payouts.
* `payoutAll(BetSettleData[] calldata bets)`: Pays the marketmaker and all listed bettors (restricted to `BETS_ROLE`).
* `payoutMarketmaker(bytes32 marketHash)`: Pays the marketmaker of a market.
* `payoutBettor(BetSettleData calldata bet)`: Pays a specific bettor (restricted to `BETS_ROLE`).
* `setVIPGroup(bytes32 marketHash, uint8 inGroup)`: Changes the VIP group access for a market.

**View Only Functions:**

* `getMarketData(bytes32 marketHash)`: Returns the full data of a market.
* `getEventState(bytes32 marketHash)`: Returns the event state associated with a market.
* `getOwner(bytes32 marketHash)`: Returns the owner of a market.
* `hasOutcome(bytes32 marketHash, uint16 outcomeId)`: Checks if a specific outcome exists in a market.
* `getOutcome(bytes32 marketHash, uint16 outcomeId)`: Returns data for a specific outcome.
* `getProcessor(uint32 id)`: Returns the processor contract address for a market type.
* `isValidOutcome(uint32 inMarketType, uint16 inOutcomeId)`: Checks if an outcome ID is valid for a market type.
* `getWinningOutcome(...)`: Determines the winning outcome based on the event result.
* `isValidOffset(uint32 inMarketType, int32 inOffset)`: Checks if an offset value is valid for a market type.
* `getValidOutcomes(uint32 inMarketType)`: Returns all valid outcome IDs for a market type.

#### LockBox.sol

**Introduction:** Simple contract for storing tokens in a locked state. It keeps a list of locked tokens and can own the locked tokens. It inherits from `LockBoxAbstract` and `TokenValidator`.

**External Functions:**

* `lockAmount(address owner, address token, uint256 amount)`: Increases the users locked amount for a token. (Restricted to `LOCKBOX_ROLE`)
* `unlockAmount(address owner, address token, uint256 amount)`: Decreases the users locked amount. (Restricted to `LOCKBOX_ROLE`)
* `unlockAmountTo(address owner, address to, address token, uint256 amount)`: Decreases an owners locked amount and sets allowance to another address. (Restricted to `LOCKBOX_ROLE`)
* `transferLockAmount(address owner, address receiver, address token, uint256 amount)`: Transfers a lock amount from one owner to another. (Restricted to `LOCKBOX_ROLE`)

**View Only Functions:**

* `getLockedAmount(address owner, address token)`: Returns the amount currently locked for a user.
* `hasLockedAmount(address owner, address token, uint256 amount)`: Checks if a user has at least the specified amount locked.

#### MarketmakerBoxLite.sol

**Introduction:** A lightweight vault contract where marketmakers deposit tokens. It inherits from `LockBoxAbstract` to provide secure fund management without exposing raw lock/unlock functionality, ensuring all fund movements are accounted for by the protocol.

**External Functions:**

* `deposit(uint256 inAmount)`: Deposits tokens into the box.
* `withdraw(uint256 inAmount)`: Withdraws tokens from the box to the owner.
* `withdrawMax()`: Withdraws all available (unlocked) tokens.
* `reserveForMarket(uint256 inAmount)`: Reserves tokens for a market (restricted to `MARKETS_ROLE`).
* `returnToOwner(uint256 inAmount)`: Returns tokens from a market back to the owner (restricted to `MARKETS_ROLE`).
* `grantVIP(address inAddress, uint8 inGroup)`: Grants a VIP role to an address.
* `revokeVIP(address inAddress, uint8 inGroup)`: Revokes a VIP role.
* `grantSigner(address inAddress)`: Grants a signer role.
* `revokeSigner(address inAddress)`: Revokes a signer role.

**View Only Functions:**

* `isVIP(address inAddress, uint8 inGroup)`: Checks if an address has a specific VIP role.
* `getOwner()`: Returns the owner of the box.
* `getLockedAmount(address owner, address token)`: Returns the amount currently locked for a user.
* `hasLockedAmount(address owner, address token, uint256 amount)`: Checks if a user has at least the specified amount locked.

#### MarketmakerFactory.sol

**Introduction:** A factory contract for deploying `MarketmakerBoxLite` contracts. It ensures that new boxes are correctly initialized and registered.

**External Functions:**

* `createMarketmakerBox()`: Creates and deploys a new `MarketmakerBoxLite` for the caller.
* `createMarketmakerBoxForUser(address inOwner)`: Creates a box for a specific user (admin only).

**View Only Functions:**

* `getMarketmakerList()`: Returns a list of all created marketmaker boxes.
* `isMarketmaker(address inMarketmaker)`: Checks if an address has created a marketmaker box.

#### ParlayHandler.sol

**Introduction:** COMING SOON! Not deployed in current version of betBlox. This contract will handle parlay bets, which are combined bets on multiple outcomes. It manages the creation, settlement, and payout of parlays. Like `MarketHandler`, it relies on `EventHandler` for retrieving event status and results.

**External Functions:**

* `setMaxOutcomes(uint8)`: Sets the max number outcomes that can be combined when a bettor makes a parlay bet. (Restricted to `OPERATION_ADMIN_ROLE`).
* `setParlayAgent(address)`: Assigns an agent that is allowed to parlay bet for the bettor making the call.
* `addParlay(ParlayInput calldata, bytes calldata)`: The regular way to create a parlay bet.
* `agentParlay(ParlayInput calldata, bytes calldata)`: Adding a parlay bet as agent, on behalf of another bettor.
* `settleParlay(bytes32)`: Settles a parlay bet, when all corresponding events are settled. There are only 2 accounts involved in a parlay bet, an MM and a bettor, and both are automatically paid from the settle.

**View Only Functions:**

* `getMaxOutcomes()`: Returns the max allowed outcomes to combine.
* `getParlayData(bytes32)`: Returns the full data of a parlay.
* `getEventStates(bytes32)`: Returns a list of the event states, one for each outcome in the parlay bet.

#### AccessHandler.sol

**Introduction:** Not deployed as a separate contract, but inherited by all other contracts. This contract provides functionalty to restrict function calls by assigned roles and to Pause transactions entirely.

**External Functions:**

* `addAdmin(address)`: Add another super-admin. (Restricted to `DEFAULT_ADMIN_ROLE`).
* `removeAdmin(address)`: Remove a super-admin. (Restricted to `DEFAULT_ADMIN_ROLE`).
* `grantRole(bytes32 role, address account)`: Grant `role` to `account`. (Restricted to `DEFAULT_ADMIN_ROLE`).
* `revokeRole(bytes32 role, address account)`: Revoke `role` for `account`. (Restricted to `DEFAULT_ADMIN_ROLE`).
* `renounceRole(bytes32 role, address callerConfirmation)`: Lets a user revoke one of their own roles.
* `pause()`: Pauses the contract. (Restricted to `PAUSER_ROLE`).
* `unpause()`: Unpauses the contract. (Restricted to `PAUSER_ROLE`).

**View Only Functions:**

* `getRoleAdmin(bytes32 role)`: Returns the admin role that controls `role` (super-admin).
* `hasRole(bytes32 role, address account)`: Returns `true` if `account` is assigned `role`.
* `paused()`: Returns `true` if the contract is paused.

### Role Access Control

The betBlox protocol uses a robust role-based access control system to secure sensitive operations. Roles are identified by calculating a keccak256 hash of the roles name.

#### System Roles

* **DEFAULT\_ADMIN\_ROLE**: The super-admin role. Admins can grant and revoke other roles, including adding other admins. This particular role hash is always the zero hex hash.
* **OPERATION\_ADMIN\_ROLE**: Allows for operational tasks, such as creating `MarketmakerBox` contracts for users via the factory.
* **PAUSER\_ROLE**: Grants the ability to pause and unpause contracts. This is an emergency control mechanism to stop protocol activity in case of a critical issue.

#### Functional Roles

* **MARKETS\_ROLE**: Assigned to `MarketHandler` and coming `ParlayHandler`. This role allows these contracts to reserve and return tokens in a `MarketmakerBox` when markets are created or settled.
* **BETS\_ROLE**: Assigned to `BetHandler`. This role authorizes the contract to call sensitive functions in `MarketHandler`, such as `addBet` and `payoutBettor`.
* **ORACLE\_ROLE**: Assigned to trusted oracle addresses. Oracles with this role can control the state and results of events they manage.
* **SIGNER\_ROLE**: Assigned to trusted signers within a `MarketmakerBox`. `ParlayHandler` will then check the assigned role by calling `mmBox.hasRole(SIGNER_ROLE, [signer_address])`. This is used to validate off-chain agreements, such as the terms of a parlay bet.

***

### Oracle Integration

Oracles play an important role in the betBlox ecosystem by bridging real-world data (sports results) to the blockchain. Markets can be either **Controlled** (Oracle-managed) or **Non-Controlled** (Market Maker-managed).

#### Controlled Markets (Oracle Managed)

In a controlled market, the lifecycle of the underlying event is managed by an approved Oracle.

1. **Market Creation**: A Market Maker creates a market linked to a specific `eventHash`.
2. **Initialization**: When the first market is created for this `event_hash`, the event is created and the event state is set to `Init`.
3. **Activation**: The Oracle server constantly monitors for markets in the `Init` state. If it recognizes the `eventHash` as one it tracks, it calls `setEventActive` on the `EventHandler`. This transitions the event to `Active`.
4. **Lifecycle Management**: The Oracle updates the event state as the real-world event progresses (e.g., setting it to `Playing` when the match starts).
5. **Resolution**: Once the event concludes, the Oracle calls `completeEvent` with the final result. This allows the `MarketHandler` to settle markets and enable payouts.

#### Non-Controlled Markets (Market Maker Managed)

If a market is not set to be controlled by an Oracle, the responsibility for lifecycle management falls on the Market Maker.

* The Market Maker must manually update the event state and provide the final result.
* This requires trust in the Market Maker, as they have direct control over the outcome resolution.

***

### Market Components & Types

Markets in betBlox are structured around a few key components that define how bets are placed and settled.

#### Market Components

A market consists of the following parameters:

* **eventHash**: Identifies the corresponding event.
* **liquidity**: Is the amount of tokens the marketmaker has provided (laid) on the market.
* **betVolume**: Is the combined amount of tokens the bettors have bet (backed) on the market.
* **paid**: Is the combined amount settled, to both marketmaker and bettors, ignoring fee details.
* **marketType**: Is a 32 bit unsigned (nonzero) number that identifies the marketType.
* **b2MmFeePermille**: Is a market specific win fee rate, the bettors will pay to the marketmaker.
* **owner**: Is the wallet address of the marketmaker, that "owns" this market.
* **vipGroup**: Is a number between 0 and 255, that limits the access to who can bet. 0 means no VIP limitations.
* **offset**: Is a number value used for some market types like "totals-goals", "spread" etc., to define the handicap or total line (e.g. -1.5 goals).
* **settled**: Is a boolean stating if the market has been settled (event results processed and payout ready).
* **mmPaid**: Is a Boolean stating if the marketmaker is paid yet.
* **bettorsPaid**: Is a Boolean stating if all bettors are paid yet.
* **outcomes**: Is an array of outcome data, holding specific data for each bettable outcome (se below).

MarketOutcomeData has these parameters:

* **outcomeId**: Is a number from 0 - 65535 to define the outcome, as seen from the bettor (e.g. Home Win, Away Win, Draw).
* **odds**: Is the current odds as decimal-odds, offered by the marketMaker, to bet on this outcome (is stored with 10 precision digits in contract).
* **available**: Is the amount of the marketmakers volume, that is still available to bettors (unmatched).
* **betAmount**: Is the combined amount betted by bettors in this outcome.
* **betsWagered**: Is the number of bets on this outcome by bettors.
* **betsSettled**: Is the number of bets settled to the bettors combined, or to the mm if its a loss.
* **result**: Is an enum that defines if the result is a Win, HalfWin, Loss etc., after the market is settled.

#### Single Outcome vs. Book Markets

Markets can be configured in two primary ways regarding how they accept bets:

1. **Single Outcome Markets**: These markets are set up for a specific outcome (e.g., "Home Win" only). The Market Maker backs only this specific result.
2. **Book Markets**: These markets cover all possible outcomes for a specific market type (e.g., Home, Draw, and Away).
   * **Balanced Book Mechanics**: In a book market, the Market Maker can accept bets up to 100% of the assigned liquidity **on each outcome side**.
   * This allows for capital efficiency, as the liquidity is shared across the potential outcomes, assuming a balanced book where losing bets on one side fund the winning bets on the other.

**Example: Balanced Moneyline Book**

**Scenario**:

* **Market**: Moneyline (Home vs. Away)
* **Liquidity Provided**: 1000 USDC
* **Odds**: Home @ 2.0, Away @ 2.0

**Action 1**: Bettor A bets **1000 USDC on Home**.

* **Potential Payout**: 2000 USDC (1000 Stake + 1000 Profit).
* **Liquidity Usage**: The market reserves 1000 USDC of the MM's liquidity to cover the potential profit.
* **State**: Market is fully exposed on the Home side (100% of liquidity used).

**Action 2**: Bettor B bets **1000 USDC on Away**.

* **Potential Payout**: 2000 USDC (1000 Stake + 1000 Profit).
* **Liquidity Usage**: Because this is a book market, the MM can *also* use the same 1000 USDC liquidity to back this side. The losing side's stake will cover the winning side's profit.
* **State**: Market is fully exposed on the Away side as well.

**Resolution**:

* **If Home Wins**:
  * Bettor A receives 2000 USDC (1000 Stake + 1000 Profit).
  * The 1000 Profit comes from Bettor B's lost stake.
  * The MM retains their original 1000 USDC liquidity.
* **Result**: The MM facilitated 2000 USDC in volume with only 1000 USDC in capital, effectively doubling their capital efficiency compared to a single-outcome market.

#### Market Types and Parameters

The protocol supports various market types, each with specific behaviors:

**Moneyline (1x2)**

* **Description**: The simplest bet on who will win the match.
* **Outcomes**: Home Win, Away Win, Draw (for sports like Soccer).
* **Parameters**:
  * `kMarketType_MoneyLine`: Standard 2-way or 3-way moneyline (Multiple Outcomes / Book Market).
  * `kMarketType_MoneyLine_Home` / `_Away`: Single outcome variants.

**Spread (Asian Handicap)**

* **Description**: Bets on the margin of victory. One team receives a virtual head start (handicap).
* **Outcomes**: Home Win, Away Win (after applying the spread).
* **Parameters**:
  * **Offset**: The handicap value (e.g., -150 for -1.5 goals). Stored with 2 decimal precision.
  * `kMarketType_Spread`: Standard spread market.

**Total (Over/Under)**

* **Description**: Bets on whether the total score will be over or under a specified amount.
* **Outcomes**: Over, Under.
* **Parameters**:
  * **Offset**: The total line (e.g., 250 for 2.5 goals). Stored with 2 decimal precision.
  * `kMarketType_Total`: Standard total market.

**Fulltime Result**

* **Description**: Similar to Moneyline but specifically for full-time results in sports like Soccer.
* **Outcomes**: Home Win, Draw, Away Win.
* **Parameters**:
  * `kMarketType_FulltimeResult`: Standard 3-way market.

**Prediction**

* **Description**: Generic prediction markets with a fixed number of outcomes.
* **Outcomes**: 1 to 5 specific prediction outcomes. **Note**: Outcomes are mutually exclusive, meaning there can only be one winning outcome per market.
* **Parameters**:
  * `kMarketType_Prediction1` to `kMarketType_Prediction5`: Defines the number of possible outcomes.

***

***

### Fee Structure

betBlox implements a flexible fee structure that incentivizes Market Makers while ensuring protocol sustainability. Fees are calculated based on the **net winnings** (profit) and are deducted automatically during payouts.

#### 1. Market Maker Fees (Bettor Wins)

When a bettor wins a bet, the Market Maker who created the market can charge a fee on the bettor's profit.

* **Fee Type**: `b2MmFeePermille` (Bettor to Market Maker Fee).
* **Payer**: The winning Bettor.
* **Receiver**: The Market Maker.
* **Calculation**: `Bettor Profit * b2MmFeePermille / 1000`.
* **Purpose**: Compensates the Market Maker for providing liquidity and taking on risk.

#### 2. Protocol Fees (Bettor Wins)

The protocol can also charge a fee on a bettor's profit.

* **Fee Type**: `feePermilleBettor`.
* **Payer**: The winning Bettor.
* **Receiver**: The Protocol (Fee Receiver address).
* **Calculation**: `Bettor Profit * feePermilleBettor / 1000`.

#### 3. Protocol Fees (Market Maker Wins)

When a Market Maker wins (i.e., the bettor loses), the protocol charges a fee on the Market Maker's profit. The rate depends on whether the market was controlled by an Oracle or managed manually by the Market Maker.

* **Fee Types**:
  * `feePermilleOracleMM`: Fee rate for Oracle-managed events.
  * `feePermilleOwnMM`: Fee rate for Market Maker-managed events.
* **Payer**: The Market Maker.
* **Receiver**: The Protocol (Fee Receiver address).
* **Calculation**: `Market Maker Profit * Applicable Fee Rate / 1000`.
* **Purpose**: Ensures the protocol earns revenue from trading activity, regardless of who wins.

***

***

### Agent Betting & Automation

betBlox includes a native "Agent" system that allows users to delegate betting execution to another address (an "Agent") without giving up custody of their funds. This is designed specifically for automated trading, AI clients and bots, and copy-betting services.

#### How it Works

The system separates the **Authorization** (User) from the **Execution** (Agent).

1. **Custody**: The User (Bettor) keeps their funds in their own wallet. They do **not** deposit funds into a bot's wallet.
2. **Approval**: The User approves the `BetHandler` contract to spend their betting tokens (standard ERC20 approval).
3. **Delegation**: The User calls `setBetAgent(agentAddress)` on the `BetHandler` to authorize a specific address (e.g., a bot's hot wallet) to place bets on their behalf.
4. **Execution**: The Agent calls `agentBet(...)` specifying the User's address as the `bettor`.
5. **Acceptance**: The `BetHandler` verifies the relationship and pulls the bet amount directly from the User's wallet. Any winnings are sent back directly to the User.

#### Use Case: AI Betting Bot

This feature enables a secure setup for AI-driven betting services:

* **User Setup**:
  * User holds 1000 USDC in their cold/warm wallet.
  * User approves `BetHandler` for 1000 USDC.
  * User authorizes the AI Bot's address as their agent.
* **Bot Operation**:
  * The AI Bot scans markets for value bets.
  * When a specific opportunity arises (e.g., "Home Win" odds > 2.5), the Bot triggers `agentBet` for the User.
  * The transaction gas is paid by the Bot, but the 100 USDC stake is pulled from the User.
* **Security**:
  * The Bot **cannot** withdraw funds or transfer them elsewhere. It can only place bets into the protocol.
  * The User can revoke the Agent's access at any time by calling `setBetAgent(address(0))`.

***

***

### VIP System

betBlox includes a granular access control system known as the **VIP System**. This allows Market Makers to restrict who can place bets on their markets. This feature is powerful for creating private betting clubs, exclusive high-roller markets, or regulatory-compliant KYC pools.

#### How it Works

Every market has a `vipGroup` parameter (uint8) set during creation or updated via `setVIPGroup`.

* **Group 0**: Public Market. Anyone can bet. (Default)
* **Groups 1-254**: VIP Markets. Only addresses with the specific VIP role can bet.
* **Group 255**: Closed Market. No one can bet (effectively pausing the market).

#### Managing Access

Access is managed at the **MarketmakerBox** level. A Market Maker grants VIP roles to specific user addresses. Once a user has a VIP role (e.g., Group 1), they can bet on *any* market created by that Market Maker that is set to `vipGroup = 1`.

* **Grant Access**: `mmBox.grantVIP(userAddress, groupNumber)`
* **Revoke Access**: `mmBox.revokeVIP(userAddress, groupNumber)`

#### Use Cases

**1. Private Betting Club**

**Scenario**: You want to run a betting pool exclusively for your friends or colleagues.

* **Setup**:
  1. Create a `MarketmakerBox`.
  2. Assign "Group 1" status to all your friends' addresses using `grantVIP`.
  3. When creating markets, set `vipGroup` to `1`.
* **Result**: Only your friends can place bets. Random users on the blockchain will be rejected by the smart contract if they try to bet.

**2. Exclusive Low-Fee Markets**

**Scenario**: You are a professional Market Maker and want to offer reduced fees (e.g., 0% fee) to your high-volume VIP clients, while charging standard fees to the public.

* **Setup**:
  1. Define "Group 10" as your "VIP High Roller" tier.
  2. Grant "Group 10" status to your qualifying large-volume customers.
  3. Create two identical markets for the same event:
     * **Market A (Public)**: `vipGroup = 0`, `Fee = 2%`.
     * **Market B (VIP)**: `vipGroup = 10`, `Fee = 0%`.
* **Result**: Your VIP clients can bet on Market B with zero fees, while the general public can only access Market A. This allows for tiered service levels on-chain.

***

***

### Token Gating

In addition to role-based access control, betBlox uses a **Token Gating** system. This feature allows the protocol to restrict access to specific functions based on whether the caller holds a minimum balance of BET tokens.

In betBlox v1.0 only MarketMaking is token gated. This means that only users with a minimum balance of BET tokens can create markets.

#### Token Gated Functions

The following contracts and functions support token gating:

* **MarketHandler**
  * `addMarket`: Creating a new market.
  * `addLiquidity`: Adding liquidity to an existing market.
  * `removeLiquidity`: Removing liquidity from a market.
* **EventHandler**
  * `addEvent`: Creating a new market maker-controlled event.
* **MarketmakerBoxLite**
  * `deposit`: Depositing funds into the market maker box.
  * `withdraw`: Withdrawing funds from the box.
  * `withdrawMax`: Withdrawing all available funds.

***

### Finding Data & Indexing

To interact with the protocol effectively (e.g., placing a bet on a specific market), you need to know the unique identifiers (hashes) for Events, Markets, and Bets. Since all core actions emit events on the blockchain, you can retrieve this data in several ways.

#### 1. Transaction Logs (Direct)

When you execute a transaction (like `addMarket` or `addBet`), the smart contract emits an event containing the generated hash.

* **Event Created**: Emits `EventAdded(bytes32 eventHash, ...)`
* **Market Created**: Emits `MarketAdded(bytes32 marketHash, ...)`
* **Bet Placed**: Emits `BetAdded(bytes32 betHash, ...)`

You can parse these logs from the transaction receipt immediately after execution to store the hashes in your local database.

#### 2. Block Explorers (Etherscan)

If you need to find a hash manually or verify data, you can use a block explorer like [Etherscan](https://etherscan.io/).

**Manual Lookup**:

1. Navigate to the relevant contract address (e.g., `MarketHandler`).
2. Click on the **"Events"** tab.
3. Filter by the event topic (e.g., `MarketAdded`).
4. The `marketHash` will be listed in the data fields.

**API Access**: Etherscan also provides a robust **API** that allows you to programmatically fetch these logs instead of doing it manually. For high-volume applications, Etherscan offers a **free** and a **paid** version with significantly higher rate limits, allowing for almost unlimited calls.

#### 3. TheGraph

For building scalable applications (dApps) that need to display lists of markets or user betting history, querying the blockchain directly can be inefficient.

betBase provides a hosted **Subgraph** on TheGraph protocol. This indexes selected betBlox protocol events (those critical for process flow) and makes them queryable via GraphQL. Note that many other events are emitted for debugging and manual verification purposes but may not be indexed.

Anyone can host their own subgraph on TheGraph protocol.

**Aggregated Entities**: The betBase subgraph goes beyond simple event indexing. It uses **special constructed entities** that assemble data from multiple contract events into single, easy-to-query objects. For example, a `Market` entity in the subgraph might combine data from `MarketAdded`, `MarketOutcomeUpdated`, and `MarketSettled` events, giving you the complete state of a market in one request.

* **Query Markets**: Get all active markets for a specific sport.
* **Query Bets**: Get all bets placed by a specific user.
* **Query Stats**: Get volume and liquidity data.

See the betblox subgraph reference guide below for detailed information.

***

### betBase API

betBase provides a REST API to facilitate easy integration of betBlox AIoracle real-world sports data with the betBlox protocol. While betBlox handles the on-chain execution of bets and markets, the betBase API is the source for finding meta data for upcoming sports events handled by the AIoracle and their corresponding on-chain identifiers (`eventHash`).

#### Core Concepts

**The Event Hash**

The `eventHash` is the critical link between the off-chain world (a football match happening in real life) and the on-chain protocol.

* **On-Chain**: contracts like `MarketHandler` and `EventHandler` require an `eventHash` to create markets or track status.
* **Off-Chain**: You use the betBase API to discover upcoming games (e.g., "Liverpool vs. Arsenal") and retrieve their unique `eventHash`.

#### API Endpoints

Base URL: `https://api.betbase.xyz`

**1. Get Sport Event Count**

**Endpoint**: `/get_sport_event_count_betblox`

**Description**: Returns the number of active sport events within each sport category.

```json
{
  "success": 1,
  "results": [
    { "sport_id": "12", "count": "15", "sport_name": "Ice Hockey" },
    { "sport_id": "4", "count": "20", "sport_name": "Soccer" },
    { "sport_id": "7", "count": "7", "sport_name": "Basketball" }
  ]
}
```

**2. Get Sports & Leagues**

**Endpoint**: `/get_sports_leagues_betblox`

**Description**: Returns a list of all sports and their IDs and the Leagues and IDs for each sport.

```json
{
  "success": 1,
  "results": [
    {
      "sport_id": "23",
      "name": "baseball",
      "leagues": [
        { "id": "1000", "name": "MLB", "events48h": "0", "flag": "us" }
      ]
    },
    {
      "sport_id": "4",
      "name": "soccer",
      "leagues": [
        { "id": "1204", "name": "England Premier League", "events48h": "0", "flag": "gb" },
        { "id": "1205", "name": "England Championship", "events48h": "1", "flag": "gb" }
      ]
    }
  ]
}
```

**3. Get Events**

**Endpoint**: `/get_events_betblox?sport_id={id}&league_id={id}`

**Description**: Returns a full list of events for all sports that are within the time range set to 48 hours before start. The parameters `sport_id` and `league_id` are optional event filters.

```json
{
  "success": 1,
  "results": [
    {
      "event_hash": "0x27ddac59f4d2e9a57cd0f88822396821b4dc08d5a5504db3e495becc80b53993",
      "event_time": "1769731200",
      "sport_id": "7",
      "league_id": "1046",
      "league_name": "Usa: Nba",
      "home_name": "Philadelphia 76ers",
      "away_name": "Sacramento Kings"
    },
    {
      "event_hash": "0x7941d54a1c7fa135563f4e38b52ea6c485e90f5d0043112b29a8de578f95c025",
      "event_time": "1769731200",
      "sport_id": "7",
      "league_id": "1046",
      "league_name": "Usa: Nba",
      "home_name": "Washington Wizards",
      "away_name": "Milwaukee Bucks"
    }
  ]
}
```

**4. Get Event Info**

**Endpoint**: `/get_event_info_betblox?event_hash[]={hash}`

**Description**: Returns information about one or more event\_hashes. Input is one or more `event_hash[]=` appended.

```json
{
  "success": 1,
  "results": [
    {
      "event_hash": "0x27ddac59f4d2e9a57cd0f88822396821b4dc08d5a5504db3e495becc80b53993",
      "event_time": "1769731200",
      "sport_id": "7",
      "league_id": "1046",
      "league_name": "Usa: Nba",
      "home_name": "Philadelphia 76ers",
      "away_name": "Sacramento Kings",
      "score": "",
      "event_state": "Active"
    }
  ]
}
```

***

### Integration Guide

#### Getting Started

To start developing with betBlox, you will need to interact with the deployed contracts on the relevant network.

1. **Connect to the Network:** Ensure your application is connected to the correct blockchain network (Base).
2. **Get Contract Addresses:** Obtain the addresses of the core contracts (`BetHandler`, `MarketHandler`, etc.) from the official deployment list.
3. **Approve Tokens:** Before placing bets or creating markets, you must approve the relevant contracts to spend your tokens.

#### Placing a Bet

To place a bet, follow these steps:

1. Identify the `marketHash` of the market you wish to bet on.
2. Call `approve` on the betting token contract to allow `BetHandler` to spend your bet amount.
3. Call `addBet` on `BetHandler` with the `marketHash`, `betAmount`, `odds`, and `outcomeId`.

```solidity
// Example: Placing a bet
IERC20(bettingToken).approve(address(betHandler), betAmount);
betHandler.addBet(marketHash, betAmount, odds, outcomeId);
```

#### Becoming a Market Maker

1. Create a `MarketmakerBox` using the `MarketmakerFactory`.
2. Deposit tokens into your `MarketmakerBox`.
3. Call `addMarket` on `MarketHandler` to create a new market using your deposited liquidity.

#### bloxTester Dev Tool

The betBlox protocol provides a bloxTester dev tool to help you test the betBlox protocol directly on Base Mainnet.

You can find the bloxTester dev tool here: [betBlox bloxTester](https://tools.betblox.xyz) *(URL placeholder)*.

***

### betBlox Subgraph reference guide

#### 1. Introduction

The betBlox subgraph indexes events, markets, bets, and parlays from the betBlox smart contracts on the Base blockchain. It provides a queryable interface to access historical and real-time data about betting activities.

#### Key Features

* **Events & Markets**: Query detailed information about sports events and their associated betting markets.
* **Betting History**: Access individual bets and parlay bets linked to specific users and outcomes.
* **Settlement Data**: Retrieve results and payout information for settled markets and bets.

#### Endpoint

You can access the subgraph via The Graph Gateway. You will need an API key from the [Subgraph Studio](https://thegraph.com/studio/).

`https://gateway.thegraph.com/api/[YOUR_API_KEY]/subgraphs/id/7MsG12oTAxnvLz1KyRyLFNm5RjrkYyXeYN9ww6wWunEM`

**Data Structure Overview**

The subgraph is built around a few core entities:

* **EventData**: The root entity representing a sports match or game.
* **MarketData**: A specific betting market (e.g., "Match Winner") within an event.
* **MarketOutcomeData**: A specific outcome (e.g., "Home Team Wins") within a market.
* **BetData**: An individual user's bet on an outcome.
* **ParlayData**: A multi-leg bet combining outcomes from different events. \[Coming Soon]
* **ParlayOutcomeData**: The leg specific data holding market/event relevant info. \[Coming Soon]
* **PayoutInfo**: A common entity used to detail all payouts.

***

#### 2. Entities

Here are the primary entities available in the betBlox subgraph, based on the schema.

**EventData**

The `EventData` entity represents a unique sports event or match.

* **id**: `Bytes!` - (32 bytes) EventHash, unique identifier for the event.
* **state**: `Int!` - (uint8) Current state of the event (e.g., scheduled, active, completed).
* **owner**: `Bytes` - (address, 20 bytes) Address of the event creator/manager.
* **eventType**: `BigInt` - (uint32) Type of event (e.g. Basketball, Football).
* **firstMarketType**: `BigInt!` - (uint32) Identifier for the first market type. The type is saved for the market that created the event, so it can be used to check type compatibility, when the event type is later set.
* **controlled**: `Boolean` - After being set Active this indicates if the event is Oracle controlled.
* **result\_homeScore**: `Int` - (uint16) The fulltime score of the home team.
* **result\_awayScore**: `Int` - (uint16 The fulltime score of the away team.
* **result\_prediction**: `Int` - (uint8) The winning outcome of the prediction: 1-5.
* **result\_desc**: `String` - (string) Optional description of the result. Could explain an overtime result, difference from the fulltime result, for instance.
* **markets**: `[MarketData!]!` - List of associated markets.
* **parlayOutcomes**: `[ParlayOutcomeData!]!` - List of associated parlay outcomes.
* **blockNumber**: `BigInt!` - (BigInt) Number/id of the last modification block.
* **blockTimestamp**: `BigInt!` - (BigInt) Timestamp of the last modification block.
* **transactionHash**: `Bytes!` - (32 bytes) Hash of the last transaction that modified the entity.

**MarketData**

The `MarketData` entity represents a betting market within an event (e.g., "Match Winner").

* **id**: `Bytes!` - (32 bytes) MarketHash, unique identifier for the market.
* **eventHash**: `Bytes!` - (32 bytes) EventHash, unique identifier for the parent event.
* **owner**: `Bytes` - (address, 20 bytes) Address of the Marketmaker.
* **marketType**: `BigInt` - (uint32) Type of market (e.g. 1x2, moneyline, total-goals).
* **b2MmFeePermille**: `Int` - (uint16) Is the market specific win fee rate, the bettors will pay to the marketmaker.
* **vipGroup**: `Int` - (uint8) Is the VIP group (0-255), that limits the access to who can bet. 0 means no VIP limitations, 255 means all are restricted so betting is paused and all other values are assignable to bettors.
* **offset**: `Int` - (int32) Is a number value used for some market types like "totals-goals", "spread" etc., to define the handicap or total line (e.g. -1.5 goals).
* **liquidity**: `BigInt!` - (BigInt) Total liquidity available in the market.
* **betVolume**: `BigInt!` - (BigInt) Total volume of bets placed.
* **allPaidAmount**: `BigInt!` - (BigInt) Full paid amount, is only set after full payout.
* **settled**: `Boolean!` - Whether the market has been settled.
* **mmPayout**: `PayoutInfo` - Detail amounts of the Marketmaker payout
* **outcomes**: `[MarketOutcomeData!]!` - List of possible outcomes in this market.
* **bets**: `[BetData!]!` - List of bets placed on this market.
* **event**: `EventData` - Link to the parent event.
* **blockNumber**: `BigInt!` - (BigInt) Number/id of the last modification block.
* **blockTimestamp**: `BigInt!` - (BigInt) Timestamp of the last modification block.
* **transactionHash**: `Bytes!` - (32 bytes) Hash of the last transaction that modified the entity.

**MarketOutcomeData**

The `MarketOutcomeData` entity represents a specific outcome within a market (e.g. "Home Win").

* **id**: `Bytes!` - (32+4 bytes) Unique identifier (MarketHash + OutcomeId).
* **marketHash**: `Bytes!` - (32 bytes) MarketHash, unique identifier for the parent market.
* **odds**: `BigInt!` - (BigInt) Is the current odds as decimal-odds, offered by the marketMaker, to bet on this outcome (is stored with 10 precision digits, eg. `19000000000` for 1.900 decimal odds).
* **outcomeId**: `Int!` - (uint16) Numeric ID of the outcome (e.g. 1 for "Home Win", 2 for "Away Win").
* **available**: `BigInt!` - (BigInt) Is the liquidity from the Marketmaker, still available for new bets. Is updated for every bet and add/remove liquidity.
* **betVolume**: `BigInt!` - (BigInt) Is the total amount of bets from bettors, on this outcome. Is updated for every bet.
* **outcomeResult**: `Int!` - (uint8) Is an enum to express the result of this outcome: `{ Undefined, Win, HalfWin, Void, HalfLoss, Loss }`.
* **market**: `MarketData!` - Link to the parent market.
* **bets**: `[BetData!]!` - List of bets placed on this specific outcome.
* **blockNumber**: `BigInt!` - (BigInt) Number/id of the last modification block.
* **blockTimestamp**: `BigInt!` - (BigInt) Timestamp of the last modification block.
* **transactionHash**: `Bytes!` - (32 bytes) Hash of the last transaction that modified the entity.

**BetData**

The `BetData` entity represents a single bet placed by a user.

* **id**: `Bytes!` - (32 bytes) BetHash, unique identifier for the bet.
* **marketHash**: - `Bytes!` (32 bytes) MarketHash, unique identifier for the parent market.
* **bettor**: `Bytes!` - (address) Address of the user who placed the bet.
* **outcomeId**: `Int!` - (uint16) Numeric ID of the bet outcome (e.g. 1 for "Home Win", 2 for "Away Win").
* **betType**: `BigInt` - (uint8) Enum to determine bet type (to recognize agent bets): `{ Undefined, Market, Agent }`.
* **betAmount**: `BigInt!` - (BigInt) Amount wagered.
* **odds**: `BigInt!` - (BigInt) Is the odds as decimal-odds, at the time the bet was placed.
* **settled**: `Boolean!` - Whether the bet has been settled.
* **payout**: `PayoutInfo` - Details about the payout (if settled).
* **outcome**: `MarketOutcomeData!` - The specific outcome chosen.
* **market**: `MarketData!` - The parent market the bet was placed on.
* **blockNumber**: `BigInt!` - (BigInt) Number/id of the last modification block.
* **blockTimestamp**: `BigInt!` - (BigInt) Timestamp of the last modification block.
* **transactionHash**: `Bytes!` - (32 bytes) Hash of the last transaction that modified the entity.

**ParlayData**

The `ParlayData` entity represents a multi-leg bet (parlay).

* **id**: `Bytes!` (32 bytes) ParlayHash, unique identifier for the parlay.
* **liquidity**: `BigInt!` - (BigInt) Liquidity to the parlay by the Marketmaker.
* **betAmount**: `BigInt!` - (BigInt) Amount wagered by the bettor.
* **odds**: `BigInt!` - Combined odds for the parlay.
* **parlayType**: `BigInt` - (uint8) Enum to determine parlay type (to recognize agent parlays): `{ Undefined, Parlay, Agent }`.
* **b2MmFeePermille**: `BigInt!` - (BigInt) Is a paraly specific win fee rate, the bettors will pay to the marketmaker.
* **mm**: `Bytes` - (address, 20 bytes) Address of the Marketmaker.
* **bettor**: `Bytes!` - (address) - Address of the user who placed the parlay bet.
* **settled**: `Boolean!` - Whether the parlay has been settled.
* **parlayResult**: `Int!` - (uint8) Is an enum to express the result of this parlay, as seen from the bettor: `{ Undefined, Win, Void, Loss }`.
* **outcomes**: `[ParlayOutcomeData!]!` - List of individual legs in the parlay.
* **bettorPayout**: `PayoutInfo` - Detail amounts of the bettor payout.
* **mmPayout**: `PayoutInfo` - Detail amounts of the Marketmaker payout.
* **blockNumber**: `BigInt!` - (BigInt) Number/id of the last modification block.
* **blockTimestamp**: `BigInt!` - (BigInt) Timestamp of the last modification block.
* **transactionHash**: `Bytes!` - (32 bytes) Hash of the last transaction that modified the entity.

**ParlayOutcomeData**

The `ParlayOutcomeData` entity represents a single leg within a parlay bet.

* **id**: `Bytes!` - (32+4 bytes) Unique identifier (txHash + logIndex). This is never updated, and does not need be easily recreated.
* **parlayHash**: `Bytes!` (32 bytes) ParlayHash, unique identifier for the parent parlay.
* **eventHash**: `Bytes!` - (32 bytes) EventHash, unique identifier for corresponding event.
* **marketType**: `BigInt` - (uint32) Type of market (e.g. 1x2, moneyline, total-goals).
* **offset**: `Int` - (int32) Is a number value used for some market types like "totals-goals", "spread" etc., to define the handicap or total line (e.g. -1.5 goals).
* **outcomeId**: `Int!` - (uint16) The specific outcome selected.
* **parlay**: `ParlayData!` - Link to the parent parlay bet.
* **event**: `EventData!` - Link to the event associated with this leg.
* **blockNumber**: `BigInt!` - (BigInt) Number/id of the last modification block.
* **blockTimestamp**: `BigInt!` - (BigInt) Timestamp of the last modification block.
* **transactionHash**: `Bytes!` - (32 bytes) Hash of the last transaction that modified the entity.

**PayoutInfo**

The `PayoutInfo` entity contains detailed payout information for settled bets and markets.

* **amountPaid**: `BigInt!` - (BigInt) Amount paid out to the bettor/Marketmaker.
* **amountWon**: `BigInt!` - (BigInt) Amount won by the receiver (profit).
* **amountReturned**: `BigInt!` - (BigInt) Amount returned to the receiver (fee free amount).
* **amountFeesToMm**: `BigInt!` - (BigInt) Fees paid to the Marketmaker.
* **amountFeesProto**: `BigInt!` - (BigInt) Fees paid to the protocol.

***

#### 3. Querying Guide

This guide explains how to construct queries to fetch data from the betBlox subgraph.

**Basic Query Structure**

GraphQL queries allow you to fetch exactly the data you need.

```graphql
query {
  eventDatas(first: 5) {
    id
    state
    blockTimestamp
  }
}

```

**Filtering**

**By ID**

Fetch a specific event by its ID (Hash).

```graphql
query {
  eventData(id: "0x...") {
    id
    state
  }
}

```

**By State**

Fetch only active events (e.g., state 1).

```graphql
query {
  eventDatas(where: { state: 1 }) {
    id
    state
  }
}

```

**By Owner**

Fetch events created by a specific address.

```graphql
query {
  eventDatas(where: { owner: "0xYourAddress" }) {
    id
  }
}

```

**Pagination**

Use `first` and `skip` to paginate through results.

```graphql
query {
  eventDatas(first: 10, skip: 0) {
    id
  }
}

```

**Sorting**

Use `orderBy` and `orderDirection` to sort results.

```graphql
query {
  eventDatas(orderBy: blockTimestamp, orderDirection: desc) {
    id
    blockTimestamp
  }
}

```

**Nested Queries (Relationships)**

The power of the subgraph lies in traversing relationships.

**Events with Markets and Outcomes**

Fetch events along with their markets and the outcomes for those markets.

```graphql
query {
  eventDatas(first: 5) {
    id
    markets {
      id
      marketType
      liquidity
      outcomes {
        id
        outcomeId
        odds
      }
    }
  }
}

```

**Bets within a Market**

Fetch the last 10 bets placed on a specific market.

```graphql
query {
  marketData(id: "0x...") {
    bets(first: 10, orderBy: blockTimestamp, orderDirection: desc) {
      id
      bettor
      betAmount
      outcome {
        outcomeId
      }
    }
  }
}

```

***

#### 4. TypeScript Examples

Here are some practical examples of how to query the betBlox subgraph using TypeScript. We'll use `graphql-request` for simplicity, but you can use Apollo Client or `fetch` as well.

**Setup**

First, install the necessary package:

```bash
npm install graphql-request graphql

```

**Example 1: Fetching Active Events with Markets**

This example fetches all active events (state 1) along with their markets and outcomes.

```typescript
import { request, gql } from 'graphql-request';

const endpoint = '[https://gateway.thegraph.com/api/](https://gateway.thegraph.com/api/)[YOUR_API_KEY]/subgraphs/id/7MsG12oTAxnvLz1KyRyLFNm5RjrkYyXeYN9ww6wWunEM';

interface MarketOutcome {
  id: string;
  outcomeId: number;
  odds: string;
}

interface Market {
  id: string;
  marketType: string;
  liquidity: string;
  outcomes: MarketOutcome[];
}

interface Event {
  id: string;
  state: number;
  blockTimestamp: string;
  markets: Market[];
}

const query = gql`
  query GetActiveEvents {
    eventDatas(first: 5, where: { state: 1 }) {
      id
      state
      blockTimestamp
      markets {
        id
        marketType
        outcomes {
          id
          outcomeId
          odds
        }
      }
    }
  }
`;

async function fetchActiveEvents() {
  const data = await request<{ eventDatas: Event[] }>(endpoint, query);
  console.log(JSON.stringify(data, null, 2));
}

fetchActiveEvents().catch((error) => console.error(error));

```

**Example 2: Fetching Recent Bets**

Fetch the most recent bets placed in the system.

```typescript
import { request, gql } from 'graphql-request';

const endpoint = '[https://gateway.thegraph.com/api/](https://gateway.thegraph.com/api/)[YOUR_API_KEY]/subgraphs/id/7MsG12oTAxnvLz1KyRyLFNm5RjrkYyXeYN9ww6wWunEM';

interface Bet {
  id: string;
  betAmount: string;
  odds: string;
  bettor: string;
  market: {
    id: string;
  };
}

const query = gql`
  query GetRecentBets {
    betDatas(first: 5, orderBy: blockTimestamp, orderDirection: desc) {
      id
      betAmount
      odds
      bettor
      market {
        id
      }
    }
  }
`;

async function fetchRecentBets() {
  const data = await request<{ betDatas: Bet[] }>(endpoint, query);
  console.log('Bets:', JSON.stringify(data, null, 2));
}

fetchRecentBets().catch((error) => console.error(error));

```

**Example 3: Market Liquidity Analysis**

Analyze liquidity and bet volume for specific markets.

```typescript
import { request, gql } from 'graphql-request';

const endpoint = '[https://gateway.thegraph.com/api/](https://gateway.thegraph.com/api/)[YOUR_API_KEY]/subgraphs/id/7MsG12oTAxnvLz1KyRyLFNm5RjrkYyXeYN9ww6wWunEM';

interface MarketData {
  id: string;
  liquidity: string;
  betVolume: string;
  marketType: string;
}

const query = gql`
  query GetMarketLiquidity {
    marketDatas(first: 10, orderBy: liquidity, orderDirection: desc) {
      id
      liquidity
      betVolume
      marketType
    }
  }
`;

async function fetchMarketAnalytics() {
  const data = await request<{ marketDatas: MarketData[] }>(endpoint, query);
  
  data.marketDatas.forEach((market) => {
    console.log(`Market ID: ${market.id}`);
    console.log(`Liquidity: ${market.liquidity}`);
    console.log(`Bet Volume: ${market.betVolume}`);
    console.log('---');
  });
}

fetchMarketAnalytics().catch((error) => console.error(error));

```

***

### Parlay Betting Guide

Parlay Betting is a special case of betting in the protocol which requires off-chain interaction with a market maker server process to approve a combined bet of onchain markets. This guide explains the technical workflow of the `ParlayHandler.sol` smart contract, detailing how parlay bets are constructed, placed on-chain, and settled.

#### 1. The Parlay Input Data

A parlay bet is defined by the `ParlayInput` struct, which serves as the signed agreement between the **Bettor** (Client) and the **Market Maker** (Server).

**Data Structure**

The `ParlayInput` contains:

* **Participants**: `bettor` (User address) and `mm` (Market Maker address).
* **Bet Terms**:
  * `betAmount`: The user's stake.
  * `liquidity`: The amount the Market Maker is risking (the payout).
  * `odds`: The combined decimal odds for the parlay.
  * `b2MmFeePermille`: The fee rate paid to the MM on a win.
* **Outcomes**: An array of selected predictions (`outcomeId`, `marketType`, `eventHash`) that must all occur.

**The "Optimistic" Flow**

1. **Client**: Constructs the proposed bet (outcomes, stake).
2. **Server (MM)**: The market maker has assigned the server, via its public key, a parlay signer role in his marketMaker box. The server Validates the risk/odds off-chain. If accepted, the MM server process **signs** a hash of the `ParlayInput` with its private key.
3. **Client**: Submit the `ParlayInput` data + the MM's server `signature` to the blockchain.

#### 2. On-Chain Placement (`addParlay`)

When the client calls `addParlay()`, the smart contract performs strict validation before locking funds.

**Verification Steps**

1. **Signature Check**: The contract hashes the input data and uses `ECDSA.recover` to verify that the signature belongs to the Market Maker server. This ensures the terms haven't been tampered with.
2. **Validation**:
   * **Amounts**: Checks if `betAmount` and `liquidity` align with the provided `odds`.
   * **Uniqueness**: Checks that the same event isn't used twice in one parlay.
   * **Leg Validity**: Verifies that every `eventHash` exists and the `marketType`/`outcomeId` are valid valid options.
   * **Authorization**: Checks if the bettor has approved the contract to spend their tokens.

**Fund Locking**

If valid, the contract:

1. Transfers the `betAmount` from the Bettor.
2. Reserves the `liquidity` from the Market Maker's vault (`MarketMakerBox`).
3. Locks **both** sums into the `BetBox` (a secure LockBox contract) under the specific `parlayHash`.

#### 3. Settlement & Resolution (`settleParlay`)

Once the real-world events have concluded, the `settleParlay` function resolves the bet.

**The Logic**

The contract iterates through **every single outcome** in the parlay and checks its status via the `EventHandler` and `MarketHandler`.

* **Winning a Leg**: An outcome is only a "Win" if the event is completed (`Active` state removed) and the resulting outcome matches the user's prediction.
* **Losing a Leg**: If the prediction is wrong.
* **Void/Canceled Events**: If an event is canceled or a market is voided.

**The "All-or-Nothing" Rule**

Crucially, this contract implements a strict **All-or-Nothing** rule:

* **WIN**: Every single outcome must result in a `Win`.
* **LOSS**: If **ANY** outcome is a `Loss`, **OR** matches are `Canceled` or `Void`, the **entire parlay is marked as a LOSS**.

> **Note**: Unlike some traditional bookmakers that might remove a voided leg and reduce the odds, this contract treats a Void/Canceled leg as a failure of the parlay condition, resulting in a loss for the bettor.

**Payout**

* **If Parlay Wins**:
  * **Bettor receives**: Their original `betAmount` + the MM's `liquidity`.
  * *(Fees are deducted from the winnings)*.
* **If Parlay Loses**:
  * **Market Maker receives**: Their reserved `liquidity` (unlocked) + the Bettor's `betAmount` (profit).
  * *(Fees are deducted from the profit)*.
