hyperliquid 1.0.1 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e1cb7c8ae1c1b83ab34eaba6f6bf9ce34b620ca1af4500912d62e54d75a95ab
4
- data.tar.gz: 9d026ad803f2fe0d2983c3dd242ee5d901cf56677e7c32cf756b5da38eb39c68
3
+ metadata.gz: a9976736621e86406eb3de9e8e4827b59d1c96c86aac1efcff2ee700afa78429
4
+ data.tar.gz: 79c0a9f8587b1af017f02539e2c35b27e7311ba7e00328c0147db636483aed28
5
5
  SHA512:
6
- metadata.gz: 99a8f5cf7847c9236f3b4b48cfb83734ecb6ae8b7679d8d5cc1aef003b1a510df3edefdf9f6481d7bdb4ff7d22546549247b9aa17771e95d58307eb93bdd0448
7
- data.tar.gz: d649b243e0aab4ae25ffcd3c452878cce1be94dd86dde1aeb151b9478bba1c42fe534ec485f4ddd896e0f358b705d4b063180b26e23fcf7d09d42a9f71ffbc64
6
+ metadata.gz: 89e3b1c854bdb152494abc51ed5f7a3dcfe3c354226d7d92ed994ef8f99d9d5fabcf91d81ddedb18bf083bcc9f3cc4952578b2bfe1d95cc2d8c35b359eb392b1
7
+ data.tar.gz: c8fd08574cfa29c927bd5c848ca5bd578914bc82150af2ab0305c38ea84785b22f4f92bed0ca07e49f86f31c8dde089fd83c47e73c58678c807a0dacf5dc9b75
data/.rubocop.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  AllCops:
2
2
  NewCops: enable
3
- TargetRubyVersion: 3.4.3
3
+ TargetRubyVersion: 3.3
4
4
  SuggestExtensions: false
5
5
  Exclude:
6
6
  - 'test_*.rb' # Exclude ad-hoc integration test scripts
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.4.3
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,31 @@
1
1
  ## [Ruby Hyperliquid SDK Changelog]
2
2
 
3
+ ## [1.1.0] - 2026-04-24
4
+
5
+ ### New Info endpoints
6
+
7
+ - `Info#validator_summaries` — validator status/stake summaries
8
+ - `Info#exchange_status` — exchange-wide status
9
+ - `Info#max_market_order_ntls` — per-coin max market order notionals
10
+ - `Info#pre_transfer_check` — pre-flight checks for transfers
11
+ - `Info#vip?` — VIP status lookup
12
+ - `Info#liquidatable` — open positions flagged liquidatable
13
+ - `Info#recent_trades(coin)` — recent trades feed
14
+ - `Info#block_details(height)` — block detail lookup by height
15
+ - `Info#user_abstraction` — account abstraction state (unifiedAccount, portfolioMargin, dexAbstraction, etc.)
16
+ - `Info#vault_summaries` — vaults less than 2 hours old
17
+ - `Info#user_fills_by_time` now accepts `aggregate_by_time` and `reversed` kwargs (matches upstream Python/TS SDKs)
18
+
19
+ ### Fixes
20
+
21
+ - Fix `TypeError` in `dump_status`/`check_result` when `response.data` is a String (e.g. `usdClassTransfer`, `approveBuilderFee` style actions)
22
+
23
+ ## [1.0.2] - 2026-02-05
24
+
25
+ - Lower minimum Ruby requirement to 3.3 and align RuboCop target
26
+ - Expand CI matrix to Ruby 3.3, 3.4, and 4.0
27
+ - Bump `ws_lite` dependency to `~> 1.0.1`
28
+
3
29
  ## [1.0.1] - 2026-02-03
4
30
 
5
31
  - Minor refactors to reduce method complexity
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
- ## Overview
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)**.
@@ -52,10 +52,15 @@ module Hyperliquid
52
52
  # @param user [String] Wallet address
53
53
  # @param start_time [Integer] Start timestamp in milliseconds
54
54
  # @param end_time [Integer, nil] Optional end timestamp in milliseconds
55
+ # @param aggregate_by_time [Boolean, nil] If true, partial fills are aggregated when a
56
+ # crossing order fills multiple resting orders
57
+ # @param reversed [Boolean, nil] If true, fills are returned in reverse chronological order (newest first)
55
58
  # @return [Array]
56
- def user_fills_by_time(user, start_time, end_time = nil)
59
+ def user_fills_by_time(user, start_time, end_time = nil, aggregate_by_time: nil, reversed: nil)
57
60
  body = { type: 'userFillsByTime', user: user, startTime: start_time }
58
61
  body[:endTime] = end_time if end_time
62
+ body[:aggregateByTime] = aggregate_by_time unless aggregate_by_time.nil?
63
+ body[:reversed] = reversed unless reversed.nil?
59
64
  @client.post(Constants::INFO_ENDPOINT, body)
60
65
  end
61
66
 
@@ -89,6 +94,20 @@ module Hyperliquid
89
94
  @client.post(Constants::INFO_ENDPOINT, { type: 'l2Book', coin: coin })
90
95
  end
91
96
 
97
+ # Get recent trades for a coin
98
+ # @param coin [String] Asset symbol (e.g., "BTC")
99
+ # @return [Array] Recent trades with coin, side, px, sz, time, hash, tid, users (maker, taker)
100
+ def recent_trades(coin)
101
+ @client.post(Constants::INFO_ENDPOINT, { type: 'recentTrades', coin: coin })
102
+ end
103
+
104
+ # Get block details by block height
105
+ # @param height [Integer] Block height
106
+ # @return [Hash] Block details including blockTime, hash, height, numTxs, proposer, txs
107
+ def block_details(height)
108
+ @client.post(Constants::INFO_ENDPOINT, { type: 'blockDetails', height: height })
109
+ end
110
+
92
111
  # Get candlestick data
93
112
  # @param coin [String] Coin symbol
94
113
  # @param interval [String] Time interval (e.g., "1m", "1h", "1d")
@@ -163,6 +182,13 @@ module Hyperliquid
163
182
  @client.post(Constants::INFO_ENDPOINT, { type: 'userVaultEquities', user: user })
164
183
  end
165
184
 
185
+ # Retrieve a list of vaults less than 2 hours old
186
+ # @return [Array] Recently created vaults with name, address, leader, tvl, isClosed,
187
+ # relationship, createTimeMillis
188
+ def vault_summaries
189
+ @client.post(Constants::INFO_ENDPOINT, { type: 'vaultSummaries' })
190
+ end
191
+
166
192
  # Query a user's role
167
193
  # @param user [String]
168
194
  # @return [Hash]
@@ -240,6 +266,56 @@ module Hyperliquid
240
266
  @client.post(Constants::INFO_ENDPOINT, { type: 'userDexAbstraction', user: user })
241
267
  end
242
268
 
269
+ # Query a user's abstraction state
270
+ # @param user [String] Wallet address
271
+ # @return [String] Abstraction state (e.g., "unifiedAccount", "portfolioMargin", "disabled",
272
+ # "default", "dexAbstraction")
273
+ def user_abstraction(user)
274
+ @client.post(Constants::INFO_ENDPOINT, { type: 'userAbstraction', user: user })
275
+ end
276
+
277
+ # Check user existence, activation fee, and sanctions status before a transfer
278
+ # @param user [String] Destination user address
279
+ # @param source [String] Source (funding) address
280
+ # @return [Hash] Keys: fee (String), isSanctioned (Boolean), userExists (Boolean),
281
+ # userHasSentTx (Boolean)
282
+ def pre_transfer_check(user, source)
283
+ @client.post(Constants::INFO_ENDPOINT, { type: 'preTransferCheck', user: user, source: source })
284
+ end
285
+
286
+ # Check whether a user is a VIP
287
+ # @param user [String] Wallet address
288
+ # @return [Boolean, nil] True/false VIP status, or nil if the user is unknown
289
+ def vip?(user)
290
+ @client.post(Constants::INFO_ENDPOINT, { type: 'isVip', user: user })
291
+ end
292
+
293
+ # Retrieve addresses of currently liquidatable users
294
+ # @return [Array] Array of liquidatable user entries
295
+ def liquidatable
296
+ @client.post(Constants::INFO_ENDPOINT, { type: 'liquidatable' })
297
+ end
298
+
299
+ # Retrieve validator performance summaries
300
+ # @return [Array] Array of validator entries with validator, signer, name, description,
301
+ # nRecentBlocks, stake, isJailed, unjailableAfter, isActive, commission, and stats
302
+ # (day/week/month uptime fraction, predicted APR, and sample count)
303
+ def validator_summaries
304
+ @client.post(Constants::INFO_ENDPOINT, { type: 'validatorSummaries' })
305
+ end
306
+
307
+ # Retrieve exchange system status information
308
+ # @return [Hash] Keys: time (Integer, ms since epoch), specialStatuses (Object or nil)
309
+ def exchange_status
310
+ @client.post(Constants::INFO_ENDPOINT, { type: 'exchangeStatus' })
311
+ end
312
+
313
+ # Retrieve maximum market order notionals per asset
314
+ # @return [Array<Array>] Array of [notional (Numeric), symbol (String)] tuples
315
+ def max_market_order_ntls
316
+ @client.post(Constants::INFO_ENDPOINT, { type: 'maxMarketOrderNtls' })
317
+ end
318
+
243
319
  # ============================
244
320
  # Info: Perpetuals
245
321
  # ============================
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hyperliquid
4
- VERSION = '1.0.1'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Hyperliquid Ruby SDK - Automated Integration Test Runner
5
+ #
6
+ # Same as test_all.rb but excludes tests unsuitable for unattended runs:
7
+ # - test_09_sub_account_lifecycle.rb: requires $100k traded volume on testnet to create sub-accounts
8
+ # - test_12_staking.rb: requires HYPE token balance (locking issues)
9
+ #
10
+ # Usage:
11
+ # HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_automated.rb
12
+
13
+ SCRIPTS = [
14
+ 'test_01_spot_market_roundtrip.rb',
15
+ 'test_02_spot_limit_order.rb',
16
+ 'test_03_perp_market_roundtrip.rb',
17
+ 'test_04_perp_limit_order.rb',
18
+ 'test_05_update_leverage.rb',
19
+ 'test_06_modify_order.rb',
20
+ 'test_07_market_close.rb',
21
+ 'test_08_usd_class_transfer.rb',
22
+ 'test_10_vault.rb',
23
+ 'test_11_builder_fee.rb',
24
+ 'test_13_ws_l2_book.rb',
25
+ 'test_14_ws_candle.rb'
26
+ ].freeze
27
+
28
+ def green(text)
29
+ "\e[32m#{text}\e[0m"
30
+ end
31
+
32
+ def red(text)
33
+ "\e[31m#{text}\e[0m"
34
+ end
35
+
36
+ unless ENV['HYPERLIQUID_PRIVATE_KEY']
37
+ puts red('Error: Set HYPERLIQUID_PRIVATE_KEY environment variable')
38
+ puts 'Usage: HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_automated.rb'
39
+ exit 1
40
+ end
41
+
42
+ scripts_dir = __dir__
43
+ passed = []
44
+ failed = []
45
+
46
+ SCRIPTS.each do |script|
47
+ path = File.join(scripts_dir, script)
48
+ puts
49
+ puts '#' * 60
50
+ puts "# Running: #{script}"
51
+ puts '#' * 60
52
+
53
+ success = system(RbConfig.ruby, path)
54
+
55
+ if success
56
+ passed << script
57
+ else
58
+ failed << script
59
+ puts red("!!! #{script} exited with error !!!")
60
+ end
61
+ end
62
+
63
+ puts
64
+ puts '=' * 60
65
+ puts 'INTEGRATION TEST SUMMARY'
66
+ puts '=' * 60
67
+ puts
68
+ puts "Passed: #{passed.length}/#{SCRIPTS.length}"
69
+ passed.each { |s| puts green(" [PASS] #{s}") }
70
+ if failed.any?
71
+ puts
72
+ puts "Failed: #{failed.length}/#{SCRIPTS.length}"
73
+ failed.each { |s| puts red(" [FAIL] #{s}") }
74
+ end
75
+ puts
76
+ puts 'Check your testnet wallet for trade history:'
77
+ puts 'https://app.hyperliquid-testnet.xyz'
78
+ puts
79
+
80
+ exit(failed.empty? ? 0 : 1)
@@ -49,7 +49,13 @@ end
49
49
  def dump_status(result)
50
50
  return unless result.is_a?(Hash)
51
51
 
52
- status = result.dig('response', 'data', 'statuses', 0)
52
+ response = result['response']
53
+ return unless response.is_a?(Hash)
54
+
55
+ data = response['data']
56
+ return unless data.is_a?(Hash)
57
+
58
+ status = data.dig('statuses', 0)
53
59
  return unless status
54
60
 
55
61
  puts " API status: #{status.inspect}"
@@ -60,7 +66,9 @@ def check_result(result, operation)
60
66
 
61
67
  return false if api_error?(result)
62
68
 
63
- status = result.dig('response', 'data', 'statuses', 0)
69
+ response = result['response']
70
+ data = response.is_a?(Hash) ? response['data'] : nil
71
+ status = data.is_a?(Hash) ? data.dig('statuses', 0) : nil
64
72
 
65
73
  if status.is_a?(Hash) && status['error']
66
74
  $test_failed = true
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.1
4
+ version: 1.1.0
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.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.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
@@ -130,6 +131,7 @@ files:
130
131
  - scripts/test_13_ws_l2_book.rb
131
132
  - scripts/test_14_ws_candle.rb
132
133
  - scripts/test_all.rb
134
+ - scripts/test_automated.rb
133
135
  - scripts/test_helpers.rb
134
136
  - sig/hyperliquid.rbs
135
137
  - test_integration.rb
@@ -148,14 +150,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
150
  requirements:
149
151
  - - ">="
150
152
  - !ruby/object:Gem::Version
151
- version: 3.4.0
153
+ version: 3.3.0
152
154
  required_rubygems_version: !ruby/object:Gem::Requirement
153
155
  requirements:
154
156
  - - ">="
155
157
  - !ruby/object:Gem::Version
156
158
  version: '0'
157
159
  requirements: []
158
- rubygems_version: 3.6.7
160
+ rubygems_version: 3.6.9
159
161
  specification_version: 4
160
162
  summary: Ruby SDK for Hyperliquid API
161
163
  test_files: []