Migrating from Dwellir
We serve Dwellir's gateway service — hyperliquid_l1_gateway.v2.HyperliquidL1Gateway — with identical wire semantics on our endpoint. Generated stubs, request messages, and decoding logic work unchanged; the migration is an endpoint string, an x-api-key header, and a validation run.
What stays the same
The full gateway surface, streaming and point-in-time. Nothing in this table requires a code change:
Reflection is enabled, so grpcurl … list will show the gateway alongside our native packages — see SDKs & protos.
The migration
Swap the endpoint
Replace the Dwellir endpoint with ours wherever the channel is built. TLS over HTTP/2, port 443:
grpc endpointdiffMove auth to x-api-key metadata
Authentication is an API key sent as gRPC metadata on each call — replace your previous credential mechanism with the
x-api-keypair. Keys come from the console; see Authentication.client.pydiffCheck your channel options
- Message size.
StreamOrderbookSnapshotsandGetOrderBookSnapshotresponses can be large on liquid markets — set max receive message size to at least 256 MB. - Reconnects. Streams are long-lived but not eternal; reconnect with backoff. A
DATA_LOSSstatus means your consumer fell behind — reconnect, and use the gateway's point-in-timeGetFills/GetBlock(or native replay from height) to close the gap.
channel = grpc.secure_channel( "stream.hyperliquidrpc.com:443", grpc.ssl_channel_credentials(), options=[ # order-book snapshots can exceed default limits — allow >=256 MB ("grpc.max_receive_message_length", 268_435_456), ],)- Message size.
Validate side by side
Run both endpoints in parallel before cutting over. Fills and blocks carry their height, so per-block equality is mechanical:
validate.pypython# run both providers in parallel and diff fills per block.# uses the hyperliquid_l1_gateway.v2 stubs you already generated.import grpc OLD = "your-current-dwellir-endpoint:443"NEW = "stream.hyperliquidrpc.com:443" def fills(endpoint, metadata=()): channel = grpc.secure_channel( endpoint, grpc.ssl_channel_credentials(), options=[("grpc.max_receive_message_length", 268_435_456)], ) gateway = HyperliquidL1GatewayStub(channel) return gateway.StreamFills(StreamFillsRequest(), metadata=metadata) old = fills(OLD) # existing authnew = fills(NEW, metadata=(("x-api-key", "YOUR_KEY"),)) # ours # align on a common block height, then compare per-block fill setsfor a, b in zip(old, new): assert a.block_height == b.block_height, (a.block_height, b.block_height) assert {(f.oid, f.px, f.sz) for f in a.fills} == \ {(f.oid, f.px, f.sz) for f in b.fills} print("block", a.block_height, "ok:", len(a.fills), "fills") # point-in-time methods are easy to spot-check too:# gateway.GetOrderBookSnapshot(...) against both endpoints at one heightLet it run through a busy period — funding intervals and a volatility burst are the interesting cases — then cut over.
What you gain
The gateway gets you migrated; the native packages on the same endpoint and key are why you move:
- Attribution-rich trades — the
hyperliquid_swaps.v1flat schema adds trader wallet, realized PnL, fees and rebate flag, maker/taker, and position context to every fill: trades stream. - Surfaces beyond the gateway — order lifecycle, raw book diffs, full L4 book, TWAPs, and funding/liquidation events.
- Server-side filtering and replay — subscribe by coin and wallet; start any native stream from a past block height to backfill, then continue live.
- The historical archive, same schema — 1.65B+ order events and 1B+ book updates, queryable and exportable with the live field names.
- RPC on the same key — HyperEVM JSON-RPC and the HyperCore /info API.