hyperliquid 1.0.2 → 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: 749f15d29e4a3e03829a031352be5c151c83d178ef5b7ac4a03e4e6741d2c097
4
- data.tar.gz: 558db42547ec4f1a615b31e45730e868b84ee4a0641d56c3103257c8ff546707
3
+ metadata.gz: a9976736621e86406eb3de9e8e4827b59d1c96c86aac1efcff2ee700afa78429
4
+ data.tar.gz: 79c0a9f8587b1af017f02539e2c35b27e7311ba7e00328c0147db636483aed28
5
5
  SHA512:
6
- metadata.gz: 78163c112fb337a68f453fdca4d9ead9cd219e5919dd5d4c39697dde9d104d28ca32e37a3075e34eced886cc685845fb128b3b7196e418ab80db806ce28cb388
7
- data.tar.gz: cb5a6f2bd65e4b31235a200c970355dc20eb5050c74c334d03ee6bee694c0550680c02a86001ed2003cbd53eb1edac30d0c9747af3af6628ffcc37a5a893938f
6
+ metadata.gz: 89e3b1c854bdb152494abc51ed5f7a3dcfe3c354226d7d92ed994ef8f99d9d5fabcf91d81ddedb18bf083bcc9f3cc4952578b2bfe1d95cc2d8c35b359eb392b1
7
+ data.tar.gz: c8fd08574cfa29c927bd5c848ca5bd578914bc82150af2ab0305c38ea84785b22f4f92bed0ca07e49f86f31c8dde089fd83c47e73c58678c807a0dacf5dc9b75
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
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
+
3
23
  ## [1.0.2] - 2026-02-05
4
24
 
5
25
  - Lower minimum Ruby requirement to 3.3 and align RuboCop target
@@ -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.2'
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.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - carter2099
@@ -131,6 +131,7 @@ files:
131
131
  - scripts/test_13_ws_l2_book.rb
132
132
  - scripts/test_14_ws_candle.rb
133
133
  - scripts/test_all.rb
134
+ - scripts/test_automated.rb
134
135
  - scripts/test_helpers.rb
135
136
  - sig/hyperliquid.rbs
136
137
  - test_integration.rb