# 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);
```
