hyperliquid 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -1
- data/.ruby-version +1 -1
- data/AGENTS.md +83 -0
- data/CHANGELOG.md +10 -0
- data/CLAUDE.md +2 -197
- data/lib/hyperliquid/exchange.rb +40 -50
- data/lib/hyperliquid/info.rb +2 -1
- data/lib/hyperliquid/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 749f15d29e4a3e03829a031352be5c151c83d178ef5b7ac4a03e4e6741d2c097
|
|
4
|
+
data.tar.gz: 558db42547ec4f1a615b31e45730e868b84ee4a0641d56c3103257c8ff546707
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78163c112fb337a68f453fdca4d9ead9cd219e5919dd5d4c39697dde9d104d28ca32e37a3075e34eced886cc685845fb128b3b7196e418ab80db806ce28cb388
|
|
7
|
+
data.tar.gz: cb5a6f2bd65e4b31235a200c970355dc20eb5050c74c334d03ee6bee694c0550680c02a86001ed2003cbd53eb1edac30d0c9747af3af6628ffcc37a5a893938f
|
data/.rubocop.yml
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
AllCops:
|
|
2
2
|
NewCops: enable
|
|
3
|
-
TargetRubyVersion: 3.
|
|
3
|
+
TargetRubyVersion: 3.3
|
|
4
4
|
SuggestExtensions: false
|
|
5
5
|
Exclude:
|
|
6
6
|
- 'test_*.rb' # Exclude ad-hoc integration test scripts
|
|
7
7
|
- 'scripts/**/*' # Exclude integration test scripts
|
|
8
|
+
- 'local/**/*' # Exclude local test scripts
|
|
8
9
|
- 'vendor/**/*' # Exclude vendored gems (CI bundles here)
|
|
9
10
|
|
|
10
11
|
# Allow longer methods for complex logic
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.4.
|
|
1
|
+
3.4.8
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to AI coding agents working with this repository.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Ruby SDK (v1.0.1) for the Hyperliquid decentralized exchange API. Three API surfaces: **Info** (read-only market data), **Exchange** (authenticated trading), and **WebSocket** (real-time streaming). Built on Faraday for HTTP, the `eth` gem for EIP-712 signing, `msgpack` for action serialization, and `ws_lite` for WebSocket connections.
|
|
8
|
+
|
|
9
|
+
**Ruby**: >= 3.3.0 (CI tests 3.3, 3.4)
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bin/setup # install dependencies
|
|
15
|
+
rake # run tests + linting (CI default)
|
|
16
|
+
rake spec # tests only
|
|
17
|
+
rake rubocop # linting only
|
|
18
|
+
bundle exec rspec spec/hyperliquid/cloid_spec.rb # single file
|
|
19
|
+
bundle exec rspec spec/hyperliquid/cloid_spec.rb:62 # single test by line
|
|
20
|
+
bin/console # IRB with SDK loaded
|
|
21
|
+
ruby example.rb # example usage script
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Integration Tests (Testnet)
|
|
25
|
+
```bash
|
|
26
|
+
HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_all.rb # all
|
|
27
|
+
HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_08_usd_class_transfer.rb # single
|
|
28
|
+
```
|
|
29
|
+
Integration tests live in `scripts/` as standalone files. `test_integration.rb` at project root is a convenience wrapper.
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
### Request Flow
|
|
34
|
+
|
|
35
|
+
The SDK has three parallel API surfaces, all routed through `Hyperliquid::SDK` (`lib/hyperliquid.rb`):
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Hyperliquid.new(...)
|
|
39
|
+
├── sdk.info → Info → Client → POST /info (always available)
|
|
40
|
+
├── sdk.exchange → Exchange → Client → POST /exchange (requires private_key)
|
|
41
|
+
└── sdk.ws → WS::Client → WSS /ws (real-time streaming)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Info path**: Method builds `{ type: 'someType' }` body → `Client` POSTs to `/info` → parsed JSON returned.
|
|
45
|
+
|
|
46
|
+
**Exchange path**: Method builds action payload → `Signer` generates EIP-712 signature over msgpack-encoded action → `Client` POSTs signed payload to `/exchange` → parsed JSON returned.
|
|
47
|
+
|
|
48
|
+
**WebSocket path**: `WS::Client` manages a persistent WSS connection with subscription tracking, automatic reconnection, ping keepalive (50s), and a bounded message queue (1024 max, drops oldest on overflow). Subscriptions are identified by a canonical key and dispatched via callbacks on a dedicated thread.
|
|
49
|
+
|
|
50
|
+
### Signing (Python SDK Parity)
|
|
51
|
+
|
|
52
|
+
The signing chain in `lib/hyperliquid/signing/` must exactly match the official Python SDK:
|
|
53
|
+
|
|
54
|
+
1. **Action hash**: `keccak256(msgpack(action) + nonce(8B big-endian) + vault_flag + [vault_addr] + [expires_flag + expires_after])`
|
|
55
|
+
2. **Phantom agent**: `{ source: 'a'|'b', connectionId: action_hash }` (a=mainnet, b=testnet)
|
|
56
|
+
3. **EIP-712 signature** over phantom agent with Exchange domain (chain ID 1337)
|
|
57
|
+
|
|
58
|
+
Any change to signing must maintain parity with the Python SDK or transactions will be rejected.
|
|
59
|
+
|
|
60
|
+
### Numeric Conversion
|
|
61
|
+
|
|
62
|
+
**float_to_wire** (in Exchange): Converts to string with 8 decimal precision, validates rounding tolerance (1e-12), normalizes trailing zeros. No scientific notation.
|
|
63
|
+
|
|
64
|
+
**Market order pricing** (_slippage_price): Apply slippage (default 5%) to mid price → round to 5 significant figures → round to `(6 for perp, 8 for spot) - szDecimals` decimal places.
|
|
65
|
+
|
|
66
|
+
**Spot vs Perp**: Assets with index >= 10,000 are spot (`SPOT_ASSET_THRESHOLD` in Exchange). This affects decimal place calculations.
|
|
67
|
+
|
|
68
|
+
### Testing
|
|
69
|
+
|
|
70
|
+
- **Unit tests** (`spec/`): RSpec + WebMock. WebMock resets between tests. Monkey-patching disabled. Test files mirror `lib/` structure.
|
|
71
|
+
- **Integration tests** (`scripts/`): Run against testnet with a real private key. Each script is self-contained.
|
|
72
|
+
|
|
73
|
+
### Code Style
|
|
74
|
+
|
|
75
|
+
RuboCop targets Ruby 3.3. Key relaxations: methods up to 50 lines, no class length limit (Info/Exchange are large by design), no block length limit in specs, no parameter list limit in Exchange. `scripts/`, `test_*.rb`, `local/`, and `vendor/` are excluded from linting.
|
|
76
|
+
|
|
77
|
+
### CI
|
|
78
|
+
|
|
79
|
+
GitHub Actions (`.github/workflows/main.yml`): runs `bundle exec rake` (tests + lint) on Ruby 3.3 and 3.4 for pushes to main and all PRs. Release workflow creates GitHub releases from CHANGELOG.md on version tags.
|
|
80
|
+
|
|
81
|
+
## Additional Docs
|
|
82
|
+
|
|
83
|
+
Detailed API reference, examples, WebSocket guide, configuration, and error handling in `docs/`.
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Ruby Hyperliquid SDK Changelog]
|
|
2
2
|
|
|
3
|
+
## [1.0.2] - 2026-02-05
|
|
4
|
+
|
|
5
|
+
- Lower minimum Ruby requirement to 3.3 and align RuboCop target
|
|
6
|
+
- Expand CI matrix to Ruby 3.3, 3.4, and 4.0
|
|
7
|
+
- Bump `ws_lite` dependency to `~> 1.0.1`
|
|
8
|
+
|
|
9
|
+
## [1.0.1] - 2026-02-03
|
|
10
|
+
|
|
11
|
+
- Minor refactors to reduce method complexity
|
|
12
|
+
|
|
3
13
|
## [1.0.0] - 2026-02-03
|
|
4
14
|
|
|
5
15
|
### WebSocket Support
|
data/CLAUDE.md
CHANGED
|
@@ -2,200 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
This is a Ruby SDK for the Hyperliquid decentralized exchange API. The current version (0.4.0) supports both **read operations** (Info API) and **authenticated write operations** (Exchange API) for trading.
|
|
8
|
-
|
|
9
|
-
**Target Ruby Version**: 3.4.0+
|
|
10
|
-
|
|
11
|
-
## Development Commands
|
|
12
|
-
|
|
13
|
-
### Running Tests
|
|
14
|
-
```bash
|
|
15
|
-
# Run all tests
|
|
16
|
-
rake spec
|
|
17
|
-
|
|
18
|
-
# Run tests and linting together (default rake task)
|
|
19
|
-
rake
|
|
20
|
-
|
|
21
|
-
# Run a single test file
|
|
22
|
-
bundle exec rspec spec/hyperliquid/cloid_spec.rb
|
|
23
|
-
|
|
24
|
-
# Run a specific test by line number
|
|
25
|
-
bundle exec rspec spec/hyperliquid/cloid_spec.rb:62
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Linting
|
|
29
|
-
```bash
|
|
30
|
-
# Run RuboCop linter
|
|
31
|
-
rake rubocop
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Interactive Console
|
|
35
|
-
```bash
|
|
36
|
-
# Open an interactive console with the SDK loaded
|
|
37
|
-
bin/console
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Example Script
|
|
41
|
-
```bash
|
|
42
|
-
# Run the example usage script
|
|
43
|
-
ruby example.rb
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Integration Testing (Testnet)
|
|
47
|
-
```bash
|
|
48
|
-
# Run all integration tests (requires private key)
|
|
49
|
-
# Get testnet funds from: https://app.hyperliquid-testnet.xyz
|
|
50
|
-
HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_all.rb
|
|
51
|
-
|
|
52
|
-
# Run a single integration test
|
|
53
|
-
HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_08_usd_class_transfer.rb
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Integration tests live in `scripts/` as individual files. Each can be run standalone for debugging. `test_integration.rb` at the project root is a convenience wrapper that runs them all.
|
|
57
|
-
|
|
58
|
-
### Setup
|
|
59
|
-
```bash
|
|
60
|
-
# Install dependencies
|
|
61
|
-
bin/setup
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Architecture
|
|
65
|
-
|
|
66
|
-
### Core Components
|
|
67
|
-
|
|
68
|
-
**Hyperliquid::SDK** (`lib/hyperliquid.rb`)
|
|
69
|
-
- Main entry point created via `Hyperliquid.new(testnet:, timeout:, retry_enabled:, private_key:, expires_after:)`
|
|
70
|
-
- Manages environment selection (mainnet vs testnet)
|
|
71
|
-
- Exposes the `info` API client (always available)
|
|
72
|
-
- Exposes the `exchange` API client (when `private_key` provided)
|
|
73
|
-
|
|
74
|
-
**Hyperliquid::Client** (`lib/hyperliquid/client.rb`)
|
|
75
|
-
- Low-level HTTP client built on Faraday
|
|
76
|
-
- Handles all POST requests to the Hyperliquid API
|
|
77
|
-
- Manages retry logic (disabled by default, opt-in via `retry_enabled: true`)
|
|
78
|
-
- Converts HTTP errors into typed exceptions
|
|
79
|
-
|
|
80
|
-
**Hyperliquid::Info** (`lib/hyperliquid/info.rb`)
|
|
81
|
-
- High-level API client for all Info endpoints (read-only)
|
|
82
|
-
- Organized into three sections:
|
|
83
|
-
1. **General Info**: Market data, user orders, fills, rate limits, portfolios, referrals, fees, staking
|
|
84
|
-
2. **Perpetuals**: Perp DEXs, metadata, user state, funding rates, open interest
|
|
85
|
-
3. **Spot**: Spot tokens, balances, deploy auctions, token details
|
|
86
|
-
- All methods accept user wallet addresses and return parsed JSON responses
|
|
87
|
-
|
|
88
|
-
**Hyperliquid::Exchange** (`lib/hyperliquid/exchange.rb`)
|
|
89
|
-
- High-level API client for Exchange endpoints (authenticated write operations)
|
|
90
|
-
- Order placement: `order`, `bulk_orders`, `market_order`
|
|
91
|
-
- Order cancellation: `cancel`, `cancel_by_cloid`, `bulk_cancel`, `bulk_cancel_by_cloid`
|
|
92
|
-
- Supports trigger orders (stop loss / take profit)
|
|
93
|
-
- Supports vault trading via `vault_address` parameter
|
|
94
|
-
- Caches asset metadata for efficient lookups
|
|
95
|
-
|
|
96
|
-
**Hyperliquid::Signing::Signer** (`lib/hyperliquid/signing/signer.rb`)
|
|
97
|
-
- EIP-712 signature generation using phantom agent scheme
|
|
98
|
-
- Matches official Python SDK signing algorithm exactly
|
|
99
|
-
- Supports vault address and expiration in signature
|
|
100
|
-
|
|
101
|
-
**Hyperliquid::Signing::EIP712** (`lib/hyperliquid/signing/eip712.rb`)
|
|
102
|
-
- EIP-712 domain and type definitions
|
|
103
|
-
- L1 chain ID (1337) and source identifiers ('a' mainnet, 'b' testnet)
|
|
104
|
-
|
|
105
|
-
**Hyperliquid::Cloid** (`lib/hyperliquid/cloid.rb`)
|
|
106
|
-
- Type-safe client order ID class
|
|
107
|
-
- Validates 16-byte hex format (0x + 32 hex characters)
|
|
108
|
-
- Factory methods: `from_int`, `from_str`, `from_uuid`, `random`
|
|
109
|
-
|
|
110
|
-
**Hyperliquid::Constants** (`lib/hyperliquid/constants.rb`)
|
|
111
|
-
- API URLs for mainnet and testnet
|
|
112
|
-
- Endpoint paths (`/info`, `/exchange`)
|
|
113
|
-
- Default timeout values
|
|
114
|
-
|
|
115
|
-
**Hyperliquid::Errors** (`lib/hyperliquid/errors.rb`)
|
|
116
|
-
- Typed exception hierarchy for API errors
|
|
117
|
-
- Base class: `Hyperliquid::Error`
|
|
118
|
-
- Specific errors: `ClientError`, `ServerError`, `AuthenticationError`, `RateLimitError`, `BadRequestError`, `NotFoundError`, `TimeoutError`, `NetworkError`
|
|
119
|
-
|
|
120
|
-
### API Request Pattern
|
|
121
|
-
|
|
122
|
-
**Info API (read-only):**
|
|
123
|
-
1. SDK method called (e.g., `sdk.info.all_mids`)
|
|
124
|
-
2. Info class builds request body with `type` field (e.g., `{ type: 'allMids' }`)
|
|
125
|
-
3. Client POSTs JSON body to `/info` endpoint
|
|
126
|
-
4. Client parses response and handles errors
|
|
127
|
-
5. Parsed JSON returned to caller
|
|
128
|
-
|
|
129
|
-
**Exchange API (authenticated):**
|
|
130
|
-
1. SDK method called (e.g., `sdk.exchange.order(...)`)
|
|
131
|
-
2. Exchange class builds action payload with order/cancel details
|
|
132
|
-
3. Signer generates EIP-712 signature over msgpack-encoded action
|
|
133
|
-
4. Exchange POSTs signed payload to `/exchange` endpoint
|
|
134
|
-
5. Client parses response and handles errors
|
|
135
|
-
6. Parsed JSON returned to caller
|
|
136
|
-
|
|
137
|
-
### Testing
|
|
138
|
-
|
|
139
|
-
- Uses RSpec for testing
|
|
140
|
-
- WebMock for HTTP mocking
|
|
141
|
-
- Spec helper configures WebMock to reset between tests
|
|
142
|
-
- Test files mirror source structure in `spec/`
|
|
143
|
-
|
|
144
|
-
### Code Style
|
|
145
|
-
|
|
146
|
-
RuboCop configuration (`.rubocop.yml`):
|
|
147
|
-
- Targets Ruby 3.4.0+
|
|
148
|
-
- Allows longer methods (max 50 lines) for complex logic
|
|
149
|
-
- Disables class length checks (Info/Exchange classes implement many endpoints)
|
|
150
|
-
- Excludes block length checks for specs
|
|
151
|
-
- Enables NewCops by default
|
|
152
|
-
|
|
153
|
-
## Key Implementation Details
|
|
154
|
-
|
|
155
|
-
### Retry Logic
|
|
156
|
-
- **Disabled by default** for predictable behavior in time-sensitive trading
|
|
157
|
-
- When enabled: max 2 retries, 0.5s base interval, exponential backoff (2x), ±50% randomness
|
|
158
|
-
- Retries on: connection failures, timeouts, 429 (rate limit), 5xx errors
|
|
159
|
-
|
|
160
|
-
### API Endpoints
|
|
161
|
-
- Info requests POST to `/info` endpoint
|
|
162
|
-
- Exchange requests POST to `/exchange` endpoint
|
|
163
|
-
- Request body includes `type` field indicating the operation
|
|
164
|
-
|
|
165
|
-
### Time Parameters
|
|
166
|
-
- All timestamps are in **milliseconds** (not seconds)
|
|
167
|
-
- Methods with time ranges support optional `end_time` parameter
|
|
168
|
-
- `expires_after` is an absolute timestamp in milliseconds
|
|
169
|
-
|
|
170
|
-
### Signature Generation (Python SDK Parity)
|
|
171
|
-
The signing implementation matches the official Python SDK exactly:
|
|
172
|
-
- **Action hash**: `keccak256(msgpack(action) + nonce(8B BE) + vault_flag + [vault_addr] + [expires_flag + expires_after])`
|
|
173
|
-
- **Phantom agent**: `{ source: 'a'|'b', connectionId: action_hash }`
|
|
174
|
-
- **EIP-712 signature** over phantom agent with Exchange domain
|
|
175
|
-
|
|
176
|
-
### Float to Wire Format
|
|
177
|
-
Numeric values are converted to strings matching Python SDK `float_to_wire`:
|
|
178
|
-
- 8 decimal precision
|
|
179
|
-
- Rounding tolerance validation (1e-12)
|
|
180
|
-
- Trailing zero normalization (no scientific notation)
|
|
181
|
-
|
|
182
|
-
### Market Order Price Calculation
|
|
183
|
-
Market orders use Python SDK `_slippage_price` algorithm:
|
|
184
|
-
- Apply slippage to mid price
|
|
185
|
-
- Round to 5 significant figures
|
|
186
|
-
- Round to asset-specific decimal places: `(6 for perp, 8 for spot) - szDecimals`
|
|
187
|
-
|
|
188
|
-
### Client Order IDs (Cloid)
|
|
189
|
-
- Must be 16 bytes in hex format: `0x` + 32 hex characters
|
|
190
|
-
- Use `Hyperliquid::Cloid` class for type safety and validation
|
|
191
|
-
- Factory methods: `from_int(n)`, `from_str(s)`, `from_uuid(uuid)`, `random`
|
|
192
|
-
|
|
193
|
-
## Development Workflow
|
|
194
|
-
|
|
195
|
-
1. Make changes to library code in `lib/hyperliquid/`
|
|
196
|
-
2. Add/update tests in `spec/`
|
|
197
|
-
3. Run tests: `rake spec`
|
|
198
|
-
4. Run linter: `rake rubocop`
|
|
199
|
-
5. Test in console: `bin/console`
|
|
200
|
-
6. Run example script: `ruby example.rb`
|
|
201
|
-
|
|
5
|
+
AGENTS.md is the canonical source of truth; this file exists only as a Claude Code convenience entrypoint.
|
|
6
|
+
For comprehensive architecture documentation and implementation details, see **[AGENTS.md](./AGENTS.md)**.
|
data/lib/hyperliquid/exchange.rb
CHANGED
|
@@ -355,34 +355,18 @@ module Hyperliquid
|
|
|
355
355
|
# @return [Hash] Order response
|
|
356
356
|
def market_close(coin:, size: nil, slippage: DEFAULT_SLIPPAGE, cloid: nil, vault_address: nil, builder: nil)
|
|
357
357
|
address = vault_address || @signer.address
|
|
358
|
-
|
|
359
|
-
state = dex_prefix ? @info.user_state(address, dex: dex_prefix) : @info.user_state(address)
|
|
360
|
-
|
|
361
|
-
position = state['assetPositions']&.find do |pos|
|
|
362
|
-
pos.dig('position', 'coin') == coin
|
|
363
|
-
end
|
|
358
|
+
position = find_position(coin, address)
|
|
364
359
|
raise ArgumentError, "No open position found for #{coin}" unless position
|
|
365
360
|
|
|
366
361
|
szi = position.dig('position', 'szi').to_f
|
|
367
362
|
is_buy = szi.negative?
|
|
368
363
|
close_size = size || szi.abs
|
|
369
|
-
|
|
370
|
-
mids = dex_prefix ? @info.all_mids(dex: dex_prefix) : @info.all_mids
|
|
371
|
-
mid = mids[coin]&.to_f
|
|
372
|
-
raise ArgumentError, "Unknown asset or no price available: #{coin}" unless mid&.positive?
|
|
373
|
-
|
|
374
|
-
slippage_price = calculate_slippage_price(coin, mid, is_buy, slippage)
|
|
364
|
+
slippage_price = calculate_slippage_price(coin, get_mid_price(coin), is_buy, slippage)
|
|
375
365
|
|
|
376
366
|
order(
|
|
377
|
-
coin: coin,
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
limit_px: slippage_price,
|
|
381
|
-
order_type: { limit: { tif: 'Ioc' } },
|
|
382
|
-
reduce_only: true,
|
|
383
|
-
cloid: cloid,
|
|
384
|
-
vault_address: vault_address,
|
|
385
|
-
builder: builder
|
|
367
|
+
coin: coin, is_buy: is_buy, size: close_size, limit_px: slippage_price,
|
|
368
|
+
order_type: { limit: { tif: 'Ioc' } }, reduce_only: true,
|
|
369
|
+
cloid: cloid, vault_address: vault_address, builder: builder
|
|
386
370
|
)
|
|
387
371
|
end
|
|
388
372
|
|
|
@@ -718,6 +702,23 @@ module Hyperliquid
|
|
|
718
702
|
(Time.now.to_f * 1000).to_i
|
|
719
703
|
end
|
|
720
704
|
|
|
705
|
+
# Find a position for a coin
|
|
706
|
+
def find_position(coin, address)
|
|
707
|
+
dex_prefix = extract_dex_prefix(coin)
|
|
708
|
+
state = dex_prefix ? @info.user_state(address, dex: dex_prefix) : @info.user_state(address)
|
|
709
|
+
state['assetPositions']&.find { |pos| pos.dig('position', 'coin') == coin }
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
# Get mid price for a coin
|
|
713
|
+
def get_mid_price(coin)
|
|
714
|
+
dex_prefix = extract_dex_prefix(coin)
|
|
715
|
+
mids = dex_prefix ? @info.all_mids(dex: dex_prefix) : @info.all_mids
|
|
716
|
+
mid = mids[coin]&.to_f
|
|
717
|
+
raise ArgumentError, "Unknown asset or no price available: #{coin}" unless mid&.positive?
|
|
718
|
+
|
|
719
|
+
mid
|
|
720
|
+
end
|
|
721
|
+
|
|
721
722
|
# Get asset index for a coin symbol
|
|
722
723
|
# @param coin [String] Asset symbol (supports HIP-3 prefixed names like "xyz:GOLD")
|
|
723
724
|
# @return [Integer] Asset index
|
|
@@ -766,30 +767,27 @@ module Hyperliquid
|
|
|
766
767
|
@asset_cache = { indices: {}, metadata: {} }
|
|
767
768
|
@loaded_dexes = Set.new
|
|
768
769
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
is_spot: false
|
|
777
|
-
}
|
|
770
|
+
load_perp_assets
|
|
771
|
+
load_spot_assets
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
def load_perp_assets
|
|
775
|
+
@info.meta['universe'].each_with_index do |asset, index|
|
|
776
|
+
cache_asset(asset['name'], index, asset['szDecimals'], is_spot: false)
|
|
778
777
|
end
|
|
778
|
+
end
|
|
779
779
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
name = pair['name']
|
|
784
|
-
spot_index = index + SPOT_ASSET_THRESHOLD
|
|
785
|
-
@asset_cache[:indices][name] = spot_index
|
|
786
|
-
@asset_cache[:metadata][name] = {
|
|
787
|
-
sz_decimals: pair['szDecimals'] || 0,
|
|
788
|
-
is_spot: true
|
|
789
|
-
}
|
|
780
|
+
def load_spot_assets
|
|
781
|
+
@info.spot_meta['universe'].each_with_index do |pair, index|
|
|
782
|
+
cache_asset(pair['name'], index + SPOT_ASSET_THRESHOLD, pair['szDecimals'] || 0, is_spot: true)
|
|
790
783
|
end
|
|
791
784
|
end
|
|
792
785
|
|
|
786
|
+
def cache_asset(name, index, sz_decimals, is_spot:, dex: nil)
|
|
787
|
+
@asset_cache[:indices][name] = index
|
|
788
|
+
@asset_cache[:metadata][name] = { sz_decimals: sz_decimals, is_spot: is_spot, dex: dex }.compact
|
|
789
|
+
end
|
|
790
|
+
|
|
793
791
|
# Load asset metadata for a HIP-3 dex
|
|
794
792
|
# HIP-3 asset IDs use formula: 100000 + perp_dex_index * 10000 + index_in_meta
|
|
795
793
|
# @param dex [String] Dex name (e.g., "xyz")
|
|
@@ -803,17 +801,9 @@ module Hyperliquid
|
|
|
803
801
|
perp_dex_index = perp_dexs.index { |d| d && d['name'] == dex }
|
|
804
802
|
return unless perp_dex_index
|
|
805
803
|
|
|
806
|
-
|
|
807
|
-
meta['universe']&.each_with_index do |asset, index|
|
|
808
|
-
name = asset['name']
|
|
809
|
-
# HIP-3 asset ID: 100000 + perp_dex_index * 10000 + index_in_meta
|
|
804
|
+
@info.meta(dex: dex)['universe']&.each_with_index do |asset, index|
|
|
810
805
|
hip3_asset_id = 100_000 + (perp_dex_index * 10_000) + index
|
|
811
|
-
|
|
812
|
-
@asset_cache[:metadata][name] = {
|
|
813
|
-
sz_decimals: asset['szDecimals'],
|
|
814
|
-
is_spot: false,
|
|
815
|
-
dex: dex
|
|
816
|
-
}
|
|
806
|
+
cache_asset(asset['name'], hip3_asset_id, asset['szDecimals'], is_spot: false, dex: dex)
|
|
817
807
|
end
|
|
818
808
|
end
|
|
819
809
|
|
data/lib/hyperliquid/info.rb
CHANGED
|
@@ -12,7 +12,8 @@ module Hyperliquid
|
|
|
12
12
|
# ============================
|
|
13
13
|
|
|
14
14
|
# Get all market mid prices
|
|
15
|
-
# @param dex [String, nil] Optional perp dex name (defaults to first perp dex;
|
|
15
|
+
# @param dex [String, nil] Optional perp dex name (defaults to first perp dex;
|
|
16
|
+
# spot mids only included with first perp dex)
|
|
16
17
|
# @return [Hash] Hash containing mid prices for all markets
|
|
17
18
|
def all_mids(dex: nil)
|
|
18
19
|
body = { type: 'allMids' }
|
data/lib/hyperliquid/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hyperliquid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- carter2099
|
|
@@ -71,14 +71,14 @@ dependencies:
|
|
|
71
71
|
requirements:
|
|
72
72
|
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 1.0.
|
|
74
|
+
version: 1.0.1
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 1.0.
|
|
81
|
+
version: 1.0.1
|
|
82
82
|
description: A Ruby SDK for interacting with Hyperliquid's decentralized exchange
|
|
83
83
|
API
|
|
84
84
|
email:
|
|
@@ -90,6 +90,7 @@ files:
|
|
|
90
90
|
- ".rspec"
|
|
91
91
|
- ".rubocop.yml"
|
|
92
92
|
- ".ruby-version"
|
|
93
|
+
- AGENTS.md
|
|
93
94
|
- CHANGELOG.md
|
|
94
95
|
- CLAUDE.md
|
|
95
96
|
- CODE_OF_CONDUCT.md
|
|
@@ -148,14 +149,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
148
149
|
requirements:
|
|
149
150
|
- - ">="
|
|
150
151
|
- !ruby/object:Gem::Version
|
|
151
|
-
version: 3.
|
|
152
|
+
version: 3.3.0
|
|
152
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
154
|
requirements:
|
|
154
155
|
- - ">="
|
|
155
156
|
- !ruby/object:Gem::Version
|
|
156
157
|
version: '0'
|
|
157
158
|
requirements: []
|
|
158
|
-
rubygems_version: 3.6.
|
|
159
|
+
rubygems_version: 3.6.9
|
|
159
160
|
specification_version: 4
|
|
160
161
|
summary: Ruby SDK for Hyperliquid API
|
|
161
162
|
test_files: []
|