# Getting Started

The Turbine Python SDK (`turbine-py-client`) provides EIP-712 order signing, Ed25519 bearer token authentication, HTTP API access, WebSocket streaming, and gasless on-chain operations for the Turbine prediction market platform.

## Installation

```bash
pip install turbine-py-client
```

Requires Python 3.9+. Dependencies: `eth-account`, `eth-utils`, `httpx`, `web3`, `websockets`, `pynacl`, `python-dotenv`.

## Quick Start

```python
from turbine_client import TurbineClient, Outcome, Side, OrderArgs

# Read-only client (public data only)
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
)

# Fetch markets
markets = client.get_markets()
for market in markets:
    print(f"{market.question} (volume: {market.volume / 1e6:.2f} USDC)")
```

## Authentication Levels

The client supports three access levels. Each level unlocks additional functionality.

{% stepper %}
{% step %}

### Public (Read-Only)

What you need:

* `host` + `chain_id`

What you can do:

* Read markets, orderbooks, trades, prices

Example:

```python
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
)

# These all work without auth
markets = client.get_markets()
orderbook = client.get_orderbook(market_id)
trades = client.get_trades(market_id)
qm = client.get_quick_market("BTC")
```

{% endstep %}

{% step %}

### Signing (Order Creation)

What you need:

* `private_key` (wallet private key)

What you can do:

* Sign orders locally (create `SignedOrder` objects). Cannot submit to API.

Example:

```python
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
    private_key="0xYourPrivateKey",
)

# Sign an order locally
signed = client.create_limit_buy(
    market_id="0x...",
    outcome=Outcome.YES,
    price=500000,    # $0.50
    size=1000000,    # 1 share
)

print(f"Order hash: {signed.order_hash}")
print(f"Signature: {signed.signature}")

# client.post_order(signed)  # This would fail — no API credentials
```

{% endstep %}

{% step %}

### Full Access

What you need:

* `private_key` + `api_key_id` + `api_private_key` (Ed25519)

What you can do:

* Submit orders, cancel, get positions, gasless operations, and all authenticated endpoints.

Example:

```python
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
    private_key="0xYourPrivateKey",
    api_key_id="your_api_key_id",
    api_private_key="your_ed25519_private_key_hex",
)

# Create, sign, and submit
signed = client.create_limit_buy(
    market_id="0x...",
    outcome=Outcome.YES,
    price=500000,
    size=1000000,
)
result = client.post_order(signed)
print(f"Submitted: {result}")

# Cancel, query positions, claim winnings, etc.
orders = client.get_orders(market_id="0x...")
positions = client.get_positions(market_id="0x...")
```

{% endstep %}
{% endstepper %}

## Getting API Credentials

API credentials are Ed25519 key pairs used to generate bearer tokens for authenticated endpoints. Register them by proving wallet ownership:

```python
credentials = TurbineClient.request_api_credentials(
    host="https://api.turbinefi.com",
    private_key="0xYourPrivateKey",
)

print(f"API Key ID:      {credentials['api_key_id']}")
print(f"API Private Key: {credentials['api_private_key']}")
```

This signs a message with your wallet (`"Register API key for Turbine: <address>"`) and sends it to `POST /api/v1/api-keys`. The server returns a new Ed25519 key pair. Save both values — the private key is not recoverable.

If your wallet already has a registered key, this raises `TurbineApiError` with status code `409`.

## Configuration

### Constructor Parameters

| Parameter         | Type    | Required | Description                                      |
| ----------------- | ------- | -------- | ------------------------------------------------ |
| `host`            | `str`   | Yes      | API base URL (e.g., `https://api.turbinefi.com`) |
| `chain_id`        | `int`   | Yes      | Blockchain chain ID                              |
| `private_key`     | `str`   | No       | Wallet private key for EIP-712 signing           |
| `api_key_id`      | `str`   | No       | Ed25519 API key ID for bearer tokens             |
| `api_private_key` | `str`   | No       | Ed25519 private key (hex) for bearer tokens      |
| `timeout`         | `float` | No       | HTTP timeout in seconds (default: `30.0`)        |

### Using Environment Variables

```python
import os
from dotenv import load_dotenv
from turbine_client import TurbineClient

load_dotenv()

client = TurbineClient(
    host=os.environ.get("TURBINE_HOST", "https://api.turbinefi.com"),
    chain_id=int(os.environ.get("CHAIN_ID", "137")),
    private_key=os.environ.get("TURBINE_PRIVATE_KEY"),
    api_key_id=os.environ.get("TURBINE_API_KEY_ID"),
    api_private_key=os.environ.get("TURBINE_API_PRIVATE_KEY"),
)
```

### Supported Chains

| Chain        | Chain ID | Settlement Address                           | USDC Address                                 |
| ------------ | -------- | -------------------------------------------- | -------------------------------------------- |
| Polygon      | `137`    | `0xdB96C91d9e5930fE3Ed1604603CfA4ece454725c` | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` |
| Avalanche    | `43114`  | `0x893ca652525B1F9DC25189ED9c3AD0543ACfb989` | `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` |
| Base Sepolia | `84532`  | `0xF37B881F236033E55bF1cdAB628c7Cd88aAd89D4` | `0xf9065CCFF7025649F16D547DC341DAffF0C7F7f6` |

Chain configs are loaded automatically based on `chain_id`. Access them via:

```python
print(f"Settlement: {client._chain_config.settlement_address}")
print(f"CTF: {client._chain_config.ctf_address}")
print(f"USDC: {client._chain_config.usdc_address}")
```

### Client Properties

```python
client.host         # API base URL
client.chain_id     # Chain ID
client.address      # Wallet address (None if no signer)
client.can_sign     # True if private key is set
client.has_auth     # True if API credentials are set
```

### Context Manager

The client implements the context manager protocol for automatic resource cleanup:

```python
with TurbineClient(host="https://api.turbinefi.com", chain_id=137) as client:
    markets = client.get_markets()
# client.close() called automatically
```

## Price and Size Encoding

All prices and sizes use integer encoding with 6 decimal places:

| Concept | Raw Value  | Meaning                 |
| ------- | ---------- | ----------------------- |
| Price   | `500000`   | $0.50 (50% probability) |
| Price   | `1`        | $0.000001 (minimum)     |
| Price   | `999999`   | $0.999999 (maximum)     |
| Size    | `1000000`  | 1 share                 |
| Size    | `10000000` | 10 shares               |

Prices range from `1` to `999999` (exclusive of 0 and 1,000,000). A price of `500000` means $0.50 = 50% implied probability.

## Error Handling

```python
from turbine_client.exceptions import (
    TurbineError,          # Base exception
    TurbineApiError,       # HTTP API errors (has status_code)
    OrderValidationError,  # Invalid order parameters (has field)
    SignatureError,        # EIP-712 signing failures
    AuthenticationError,   # Missing credentials (has required_level)
    ConfigurationError,    # Invalid chain/config
    WebSocketError,        # WebSocket connection issues
)

try:
    result = client.post_order(signed_order)
except AuthenticationError as e:
    print(f"Auth failed (requires {e.required_level}): {e.message}")
except TurbineApiError as e:
    print(f"API error {e.status_code}: {e.message}")
except OrderValidationError as e:
    print(f"Invalid order ({e.field}): {e.message}")
```
