Skip to content

Repository files navigation

grvt-sdk

Python SDK for GRVT Exchange — a ZK-powered perpetuals DEX.

Covers the full integration surface: cookie-based session auth, EIP-712 order signing, synchronous and async REST clients, and a reconnecting WebSocket client with per-channel typed dispatch and sequence gap detection.

CI Python License


Quickstart

import asyncio
from grvt_sdk import GRVTClient, GRVTEnv, Orderbook

async def main() -> None:
    async with GRVTClient(api_key="...", env=GRVTEnv.TESTNET) as client:

        # REST – fetch current orderbook
        book = await client.rest.get_orderbook("BTC_USDT_Perp")
        print(book.bids[0])

        # WebSocket – stream live orderbook updates
        async def on_book(b: Orderbook) -> None:
            print(b.bids[0].price)

        await client.ws.subscribe("orderbook.BTC_USDT_Perp", on_book, msg_type=Orderbook)
        await client.ws.run_forever()

asyncio.run(main())

Installation

pip install -e ".[dev]"   # from source

Requires Python 3.10+ and the following dependencies (installed automatically): aiohttp, eth-account, pydantic>=2.5, requests, websockets.


Features

Area What the SDK does
Auth POST /auth/api_key/login → session cookie. Proactive refresh 5 min before expiry. asyncio.Lock prevents concurrent re-auth races.
EIP-712 signing Fixed-point integer encoding for prices and sizes — avoids float precision bugs that would fail on-chain signature verification.
REST (sync) GRVTRestClient — order CRUD, account summary, orderbook, trades, instruments. Exponential backoff on 429 / 5xx.
REST (async) AsyncGRVTRestClient — aiohttp-based, same event loop as the WS client.
WebSocket Reconnect with exponential backoff. Per-channel typed dispatch. Sequence number gap detection with on_gap callback.
Façade GRVTClient — single object owning REST + WS on a shared auth instance.
Types Pydantic v2 models with field-level validation on all inputs (hex hashes, decimal strings, int64 bounds, uint32 limits).

Project layout

src/grvt_sdk/
├── client.py    # GRVTClient – unified façade
├── auth.py      # GRVTAuth  – cookie management, sync + async
├── signing.py   # sign_order, recover_signer – EIP-712
├── rest.py      # GRVTRestClient, AsyncGRVTRestClient
├── ws.py        # GRVTWebSocketClient – reconnect, typed dispatch
└── types.py     # Pydantic v2 models for the full API schema

examples/
├── quickstart.py     # end-to-end: auth → sign → submit → subscribe
├── market_maker.py   # two-sided quoting, SeqNonce, position limits, graceful shutdown
└── latency.py        # REST RTT + fill-to-confirm latency benchmark

tests/
├── test_signing.py  # 15 EIP-712 unit tests (offline)
├── test_types.py    # 36 Pydantic model validation tests (offline)
├── test_ws.py       # 22 WebSocket dispatch tests (offline)
└── test_client.py   # 10 façade tests (offline)

Signing an order

from grvt_sdk import GRVTAuth, GRVTEnv, Order, OrderLeg, OrderMetadata, TimeInForce, sign_order
import time

auth  = GRVTAuth(api_key="...", env=GRVTEnv.TESTNET)
order = Order(
    sub_account_id=12345,
    time_in_force=TimeInForce.GOOD_TILL_TIME,
    expiration=int(time.time_ns()) + 60 * 10 ** 9,  # 60 s from now
    legs=[OrderLeg(
        instrument_hash="0x...",   # keccak256 of instrument name
        size="0.01",
        limit_price="50000.0",
        is_buying_asset=True,
    )],
    metadata=OrderMetadata(client_order_id=1, create_time=time.time_ns()),
)

sign_order(order, private_key="0x...", chain_id=GRVTEnv.TESTNET.chain_id)
# order.signature is now set — ready to submit

Examples

Market maker (examples/market_maker.py)

A runnable two-sided quoting loop that demonstrates the full integration surface: subscribes to the orderbook WS stream, places a bid and ask around mid with a configurable spread, re-quotes on fills, enforces position limits with reduce_only, and cancels all open orders on Ctrl-C.

export GRVT_API_KEY="your_api_key"
export GRVT_PRIVATE_KEY="0x..."
export GRVT_SUB_ACCOUNT_ID="12345"
python examples/market_maker.py

Latency benchmark (examples/latency.py)

Measures the two latency dimensions that matter most to market makers:

Benchmark What it measures
REST round-trip create_order() call → HTTP response
Fill-to-confirm Order submit → fill event arrives on private WS stream

Reports P50 / P95 / P99 / max / mean in milliseconds across N samples. High REST RTT points to network or exchange processing latency; high fill-to-confirm points to the WS pipeline.

export GRVT_API_KEY="your_api_key"
export GRVT_PRIVATE_KEY="0x..."
export GRVT_SUB_ACCOUNT_ID="12345"
export GRVT_INSTRUMENT_HASH="0x..."   # keccak256 of instrument name

# REST round-trip benchmark (20 samples, far-from-market price — orders won't fill)
python examples/latency.py

# Also run fill-to-confirm benchmark (set an at-market price)
export GRVT_LIMIT_PRICE="95000.0"
export GRVT_N_SAMPLES="50"
python examples/latency.py

Example output:

GRVT Latency Benchmark
  env=testnet  instrument=BTC_USDT_Perp  samples=20

Running REST round-trip benchmark…

  REST round-trip (submit → HTTP response) (20 samples)
    P50  :     42.3 ms
    P95  :     61.8 ms
    P99  :     68.2 ms
    max  :     68.2 ms
    mean :     44.1 ms

Running tests

# All 83 offline unit tests — no credentials required
pytest tests/ -v

# End-to-end demo against testnet
export GRVT_API_KEY="..."
export GRVT_PRIVATE_KEY="0x..."
export GRVT_SUB_ACCOUNT_ID="12345"
python examples/quickstart.py

Testnet endpoints

Service URL
Auth / Edge https://edge.testnet.grvt.io
Trading REST https://trades.testnet.grvt.io
Market Data REST https://market-data.testnet.grvt.io
Trading WS wss://trades.testnet.grvt.io/ws
Market Data WS wss://market-data.testnet.grvt.io/ws
Chain ID 326

Comparison with grvt-pysdk

The official grvt-pysdk is a solid reference implementation. This SDK was built by studying it closely and addressing the gaps that matter most in a production trading context.

GRVT's builder-examples covers the basic integration pattern — API key auth and single-leg order submission. The examples here (market_maker.py, latency.py) pick up where that leaves off: two-sided quoting with position limits, SeqNonce for high-frequency submissions, graceful reconnect, and latency measurement — the production concerns that surface once the basic integration is working.

grvt-pysdk this SDK
Cookie name Hardcoded "gravity" — breaks when server sends exchange_token (issue #97) Reads whichever cookie name the server returns
Async re-auth race No lock — concurrent coroutines can trigger duplicate login requests asyncio.Lock with double-checked locking
Proactive refresh Refreshes only after expiry Refreshes 5 min before expiry — long-running bots never hit auth failures
EIP-712 encoding Uses float arithmetic for price/size Decimal throughout — int(float("1.013") * 1e9) == 1012999999, not 1013000000
Nonce strategy Timestamp-based only Pluggable NonceProvider — sequence counter for high-frequency quoting
WebSocket gaps No sequence tracking Per-channel sequence number gap detection with on_gap callback
Type safety Plain dataclasses, no validation Pydantic v2 — field-level validation at construction, not at submission. All REST methods return typed models, none return raw dict
Static analysis No mypy configuration mypy --strict — zero errors across all 7 source files, blocking in CI on Python 3.10/3.11/3.12
Unified entry point Separate auth / REST / WS objects to wire manually GRVTClient façade — one object, shared auth, async context manager
Test coverage No offline tests 83 offline unit tests + 5 integration smoke tests (--integration flag, skipped in CI)
Developer docs No contributor guide CONTRIBUTING.md — prerequisites, test commands, step-by-step guide for adding endpoints

License

MIT

About

Python SDK for GRVT Exchange – REST, WebSocket, EIP-712 signing, and low-latency order pipeline

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages