> For the complete documentation index, see [llms.txt](https://docs.stimpak.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stimpak.io/stimpak-ecosystem/overview/duels/developers.md).

# Developer Integration

This guide provides the contract addresses, interfaces, and API endpoints needed to integrate with Stimpak Duels programmatically.

## Contract Addresses

### Arbitrum Mainnet (Chain ID: 42161)

| Contract             | Address                                                                                                              |
| -------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **CompetitionHub**   | [0xB1bd061197B7099c3289262c31Ab08ED5F254A7f](https://arbiscan.io/address/0xB1bd061197B7099c3289262c31Ab08ED5F254A7f) |
| **CompetitionAdmin** | [0xa475F65C40419638CD0902A2b032A0c9b6A99C74](https://arbiscan.io/address/0xa475F65C40419638CD0902A2b032A0c9b6A99C74) |
| **Settings**         | [0x8b13bdc3307ABC0cFDAA17BD0F9fC1D79146aDDb](https://arbiscan.io/address/0x8b13bdc3307ABC0cFDAA17BD0F9fC1D79146aDDb) |
| **GameLogic**        | [0x26b4282F8Bc0324ACe42AFaA47c7BdB69B625B4d](https://arbiscan.io/address/0x26b4282F8Bc0324ACe42AFaA47c7BdB69B625B4d) |
| **Reader**           | [0x3a12bf16809DC8ab9e2B4dA2835f48840e3090d1](https://arbiscan.io/address/0x3a12bf16809DC8ab9e2B4dA2835f48840e3090d1) |
| **USDC**             | [0xaf88d065e77c8cC2239327C5EDb3A432268e5831](https://arbiscan.io/address/0xaf88d065e77c8cC2239327C5EDb3A432268e5831) |

**Contract Source Code:** [github.com/stimpak-io/stimpak-duels-contracts](https://github.com/stimpak-io/stimpak-duels-contracts)

## Supported Markets

| Market   | Address                                                                                                              | Max Leverage |
| -------- | -------------------------------------------------------------------------------------------------------------------- | ------------ |
| BTC/USD  | [0x47c031236e19d024b42f8AE6780E44A573170703](https://arbiscan.io/address/0x47c031236e19d024b42f8AE6780E44A573170703) | 100x         |
| ETH/USD  | [0x70d95587d40A2caf56bd97485aB3Eec10Bee6336](https://arbiscan.io/address/0x70d95587d40A2caf56bd97485aB3Eec10Bee6336) | 100x         |
| SOL/USD  | [0x09400D9DB990D5ed3f35D7be61DfAEB900Af03C9](https://arbiscan.io/address/0x09400D9DB990D5ed3f35D7be61DfAEB900Af03C9) | 100x         |
| LINK/USD | [0x7f1fa204bb700853D36994DA19F830b6Ad18455C](https://arbiscan.io/address/0x7f1fa204bb700853D36994DA19F830b6Ad18455C) | 100x         |

***

## Core Interfaces

### Creating a Duel

Duels are created through the **CompetitionHub** contract. There are two types:

#### 1. Head-to-Head (H2H) Duel

```solidity
function proposeH2HCompetition(
    address _market,              // GMX market address (e.g., BTC/USD)
    uint256 _collateralAmount,    // Starting balance in USDC (6 decimals)
    uint256 _buyInAmount,         // Entry fee in USDC (6 decimals)
    address _buyInToken,          // USDC address
    uint256 _buffer,              // Buffer time before duel starts (seconds)
    uint256 _duration,            // Duel duration (seconds)
    uint256 _expirationDuration,  // Time for opponent to accept (seconds)
    bool _isProtected,            // If true, requires signature to join
    uint256 _signatureExpiration, // Signature expiration timestamp
    bytes memory _signature,      // Backend signature for validation
    bytes32 _title                // Optional title (bytes32)
) external returns (uint256 competitionId)
```

#### 2. Deathmatch (Multi-player)

```solidity
function createDeathmatchCompetition(
    address _market,              // GMX market address
    uint256 _collateralAmount,    // Starting balance per trader (USDC, 6 decimals)
    uint256 _buyInAmount,         // Entry fee (USDC, 6 decimals)
    address _buyInToken,          // USDC address
    uint256 _startTime,           // Unix timestamp when duel starts
    uint256 _endTime,             // Unix timestamp when duel ends
    uint256 _minParticipants,     // Minimum players needed (or cancelled)
    uint256 _maxParticipants,     // Maximum players allowed
    bool _isProtected,            // If true, requires signature to join
    uint256 _signatureExpiration, // Signature expiration timestamp
    bytes memory _signature,      // Backend signature
    bytes32 _title                // Optional title
) external returns (uint256 competitionId)
```

***

### Joining a Duel

```solidity
function joinCompetition(
    uint256 _competitionId,       // ID of the competition to join
    uint256 _expiration,          // Signature expiration timestamp
    bytes memory _signature       // Backend signature for validation
) external
```

**Note**: Before joining, users must approve the CompetitionHub to spend their USDC:

```solidity
// Approve buy-in amount + collateral amount
IERC20(usdcAddress).approve(competitionHubAddress, buyInAmount + collateralAmount);
```

***

### Trading in a Duel

Once joined, each participant gets a **Trader contract** deployed for them. Trading is done through this contract.

#### Open a Position

```solidity
function openPosition(
    uint256 collateralAmountUsdc, // Collateral to use (USDC, 6 decimals)
    uint256 _acceptablePrice,     // Max/min acceptable price (30 decimals)
    uint256 _size,                // Position size in USD (30 decimals)
    uint256 _collateral,          // Collateral for the position
    bool _isLong,                 // true = long, false = short
    uint256 _triggerPrice         // Trigger price for limit orders (0 for market)
) external payable
```

#### Close a Position

```solidity
function closePosition(
    uint256 _acceptablePrice,     // Acceptable execution price (30 decimals)
    uint256 _sizeDelta,           // Size to close (30 decimals, use position size for full close)
    bool _isLong,                 // Position direction
    uint256 _triggerPrice         // 0 for market order
) external payable
```

#### Cancel an Order

```solidity
function cancelOrder(
    bytes32 _orderKey             // The order key to cancel
) external payable
```

**Note**: Trading functions require ETH for GMX execution fees (typically 0.0001-0.001 ETH).

***

### Reading Duel Data

#### Get Competition Data

```solidity
function getCompetitionData(uint256 competitionId) external view returns (
    bool isHeadToHead,
    bool isProtected,
    uint8 status,                 // 0=Awaiting, 1=Registration, 2=Active, 3=Ended, 4=Finalized, 5=Cancelled
    address market,
    uint256 startTime,
    uint256 endTime,
    uint256 buyInAmount,
    address buyInToken,
    uint256 collateralAmount,
    uint256 prizePool,
    uint256 platformFeePool,
    uint256 sponsorshipPool,
    uint256 minParticipants,
    uint256 maxParticipants,
    address winner
)
```

#### Get Participant's Trader Contract

```solidity
function getTraderContract(
    uint256 _competitionId,
    address _participant
) external view returns (address traderContract)
```

***

## Competition Status Codes

| Status            | Value | Description                             |
| ----------------- | ----- | --------------------------------------- |
| Awaiting Opponent | 0     | H2H waiting for opponent                |
| Registration Open | 1     | Deathmatch accepting entries            |
| Active            | 2     | Trading is live                         |
| Ended             | 3     | Trading complete, awaiting finalization |
| Finalized         | 4     | Winner determined, prizes distributed   |
| Cancelled         | 5     | Duel cancelled, refunds available       |
| Elapsed           | 6     | Expired without sufficient participants |
| No Contest        | 7     | Ended with no valid trades              |

***

## Example Integration (ethers.js v6)

```typescript
import { ethers } from 'ethers';

// Contract ABIs (simplified - full ABIs available in our GitHub)
const COMPETITION_HUB_ABI = [
  'function joinCompetition(uint256 _competitionId, uint256 _expiration, bytes memory _signature) external',
  'function getCompetitionData(uint256 competitionId) external view returns (bool, bool, uint8, address, uint256, uint256, uint256, address, uint256, uint256, uint256, uint256, uint256, uint256, address)',
  'function getTraderContract(uint256 _competitionId, address _participant) external view returns (address)'
];

const TRADER_ABI = [
  'function openPosition(uint256 collateralAmountUsdc, uint256 _acceptablePrice, uint256 _size, uint256 _collateral, bool _isLong, uint256 _triggerPrice) external payable',
  'function closePosition(uint256 _acceptablePrice, uint256 _sizeDelta, bool _isLong, uint256 _triggerPrice) external payable',
  'function availableAmount() external view returns (uint256)'
];

const ERC20_ABI = [
  'function approve(address spender, uint256 amount) external returns (bool)',
  'function allowance(address owner, address spender) external view returns (uint256)'
];

// Addresses (Arbitrum Mainnet)
const COMPETITION_HUB = '0xB1bd061197B7099c3289262c31Ab08ED5F254A7f';
const USDC = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';

async function joinDuel(signer: ethers.Signer, competitionId: number, signature: string, expiration: number) {
  const hub = new ethers.Contract(COMPETITION_HUB, COMPETITION_HUB_ABI, signer);
  const usdc = new ethers.Contract(USDC, ERC20_ABI, signer);
  
  // Get competition data to know approval amount
  const data = await hub.getCompetitionData(competitionId);
  const buyInAmount = data[6];  // buyInAmount
  const collateral = data[8];   // collateralAmount
  const totalAmount = buyInAmount + collateral;
  
  // Approve USDC spend
  const allowance = await usdc.allowance(await signer.getAddress(), COMPETITION_HUB);
  if (allowance < totalAmount) {
    const approveTx = await usdc.approve(COMPETITION_HUB, totalAmount);
    await approveTx.wait();
  }
  
  // Join the competition
  const joinTx = await hub.joinCompetition(competitionId, expiration, signature);
  await joinTx.wait();
  
  return joinTx.hash;
}

async function openLongPosition(signer: ethers.Signer, competitionId: number, sizeUsd: bigint) {
  const hub = new ethers.Contract(COMPETITION_HUB, COMPETITION_HUB_ABI, signer);
  const userAddress = await signer.getAddress();
  
  // Get the user's trader contract
  const traderAddress = await hub.getTraderContract(competitionId, userAddress);
  const trader = new ethers.Contract(traderAddress, TRADER_ABI, signer);
  
  // Get available collateral
  const available = await trader.availableAmount();
  
  // Open a long position with market order
  // Using 1% slippage on acceptable price (you'd fetch current price from GMX)
  const acceptablePrice = ethers.parseUnits('100000', 30); // Example: $100k BTC price with 30 decimals
  const executionFee = ethers.parseEther('0.0003'); // GMX execution fee
  
  const tx = await trader.openPosition(
    available,           // Use full available collateral
    acceptablePrice,     // Acceptable price (30 decimals)
    sizeUsd,             // Position size (30 decimals)
    available,           // Collateral amount
    true,                // isLong
    0,                   // triggerPrice (0 for market order)
    { value: executionFee }
  );
  
  await tx.wait();
  return tx.hash;
}
```

***

## REST API

Stimpak Duels provides a REST API for querying duel data programmatically. API keys are available by request - contact the Stimpak team to get access.

### Base URL

**Production:** `https://api-duels.stimpak.io/api/v1`

### Authentication

All API requests require an API key passed in the `Authorization` header:

```
Authorization: Bearer <your_api_key>
```

### Endpoints

#### Get All Duels

```http
GET /duels/all?page=1&limit=20
```

Returns a paginated list of all duels.

**Query Parameters:**

| Parameter | Type   | Default | Description              |
| --------- | ------ | ------- | ------------------------ |
| `page`    | number | 1       | Page number              |
| `limit`   | number | 20      | Items per page (max 100) |

***

#### Get Open Duels

```http
GET /duels/open?page=1&limit=20
```

Returns duels that are currently open for registration (status: Awaiting Opponent or Registration Open).

***

#### Get Active Duels

```http
GET /duels/active?page=1&limit=20
```

Returns duels that are currently in progress (status: Active or Ended).

***

#### Get Finalized Duels

```http
GET /duels/finalized?page=1&limit=20
```

Returns completed duels (status: Finalized).

***

#### Get Duel Details

```http
GET /duels/:duel_id
```

Returns detailed information about a specific duel.

**Response:**

```json
{
  "duel_id": 75,
  "status": "active",
  "market": "BTC/USD",
  "market_address": "0x47c031236e19d024b42f8AE6780E44A573170703",
  "is_head_to_head": false,
  "collateral_amount": "100.00",
  "buy_in_amount": "10.00",
  "start_time": "2026-01-15T00:00:00Z",
  "end_time": "2026-01-22T00:00:00Z",
  "participants": {
    "current": 5,
    "min": 2,
    "max": 10
  },
  "prize_pool": "50.00",
  "title": "Weekly BTC Showdown"
}
```

***

#### Get Your Position

```http
GET /duels/:duel_id/my-position
```

Returns your entry and current position in a specific duel.

**Response:**

```json
{
  "duel_id": 75,
  "wallet_address": "0x...",
  "trader_contract": "0x...",
  "joined_at": "2026-01-14T12:00:00Z",
  "open_position": {
    "market": "BTC/USD",
    "is_long": true,
    "size_usd": "500.00",
    "collateral_usd": "100.00",
    "entry_price": "95000.00",
    "current_price": "96500.00",
    "leverage": "5.0",
    "unrealized_pnl_usd": "7.89",
    "liquidation_price": "76000.00"
  },
  "available_collateral": "0.00",
  "realized_pnl_usd": "12.50",
  "total_pnl_usd": "20.39"
}
```

***

#### Get Leaderboard

```http
GET /duels/:duel_id/leaderboard?include_positions=true&limit=10
```

Returns the current leaderboard for a duel.

**Query Parameters:**

| Parameter           | Type    | Default | Description                   |
| ------------------- | ------- | ------- | ----------------------------- |
| `include_positions` | boolean | false   | Include open position details |
| `limit`             | number  | 20      | Number of entries to return   |

**Response:**

```json
{
  "duel_id": 75,
  "status": "active",
  "leaderboard": [
    {
      "rank": 1,
      "wallet_address": "0x...",
      "total_pnl_usd": "45.67",
      "total_pnl_percentage": "45.67",
      "realized_pnl_usd": "20.00",
      "unrealized_pnl_usd": "25.67",
      "open_position": {
        "market": "BTC/USD",
        "is_long": true,
        "size_usd": "500.00",
        "leverage": "5.0",
        "unrealized_pnl_usd": "25.67"
      }
    }
  ],
  "total_participants": 5,
  "your_rank": 3
}
```

***

### Error Responses

All errors follow this format:

```json
{
  "error": "unauthorized",
  "message": "Invalid or expired API key"
}
```

| Status Code | Error          | Description                |
| ----------- | -------------- | -------------------------- |
| 401         | `unauthorized` | Invalid or missing API key |
| 404         | `not_found`    | Duel not found             |
| 429         | `rate_limited` | Too many requests          |

***

## Signature Requirements

Backend signatures are required for:

* **Finalization** of competitions
* **Joining private (protected) competitions**

Public competitions can be created and joined without a signature. Contact the Stimpak team for API access to obtain signatures programmatically.

### Signature Format

The signature validates:

* User address
* Competition parameters
* Nonce (to prevent replay attacks)
* Expiration timestamp

***

## Resources

* **Contract Source Code**: [github.com/stimpak-io/stimpak-duels-contracts](https://github.com/stimpak-io/stimpak-duels-contracts)
* **API Access**: Contact the Stimpak team via Discord to request an API key
* **Production API**: `https://api-duels.stimpak.io/api/v1`
* **Subgraph**: [api.goldsky.com/.../stimpak-duels-mainnet/1.0.0/gn](https://api.goldsky.com/api/public/project_cmcc1or8s8c2m01x8hi42758x/subgraphs/stimpak-duels-mainnet/1.0.0/gn)
* **Discord**: Join our developer community for support and API key requests

***

## Events to Listen For

```solidity
// Competition lifecycle
event CompetitionCreated(uint256 indexed competitionId, bool isHeadToHead, bool isProtected, address indexed proposer);
event CompetitionJoined(uint256 indexed competitionId, address participant);
event CompetitionStarted(uint256 indexed competitionId);
event CompetitionFinalized(uint256 indexed competitionId, address winner, bool isCancelled);

// Trading events (from Trader contract)
event TradeExecuted(bytes32 indexed orderKey, bool isLong, uint256 sizeDelta, uint256 executionPrice);
event PositionOpened(bytes32 indexed orderKey, bool isLong, uint256 size, uint256 collateral);
event PositionClosed(bytes32 indexed orderKey, uint256 realizedPnl);
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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.stimpak.io/stimpak-ecosystem/overview/duels/developers.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.
