hyperliquid 0.7.0 → 1.0.1

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.
@@ -1,49 +1,55 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # Test 3: Perp Market Roundtrip (BTC Long)
5
- # Open a long BTC position, then close it.
4
+ # Test 3: Perp Market Roundtrip (Long)
5
+ # Open a long perp position, then close it.
6
6
 
7
7
  require_relative 'test_helpers'
8
8
 
9
9
  sdk = build_sdk
10
- separator('TEST 3: Perp Market Roundtrip (BTC Long)')
10
+ perp_coin = 'ETH'
11
+ separator("TEST 3: Perp Market Roundtrip (#{perp_coin} Long)")
11
12
 
12
- perp_coin = 'BTC'
13
13
  mids = sdk.info.all_mids
14
- btc_price = mids[perp_coin]&.to_f
14
+ perp_coin_price = mids[perp_coin]&.to_f
15
15
 
16
- if btc_price&.positive?
16
+ if perp_coin_price&.positive?
17
17
  meta = sdk.info.meta
18
- btc_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
- sz_decimals = btc_meta['szDecimals']
18
+ perp_coin_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
+ sz_decimals = perp_coin_meta['szDecimals']
20
20
 
21
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
21
+ perp_size = (20.0 / perp_coin_price).ceil(sz_decimals)
22
22
 
23
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
24
- puts "Size: #{perp_size} BTC (~$#{(perp_size * btc_price).round(2)})"
25
- puts "Slippage: #{(PERP_SLIPPAGE * 100).to_i}%"
23
+ puts "#{perp_coin} mid: $#{perp_coin_price.round(2)}"
24
+ puts "Size: #{perp_size} #{perp_coin} (~$#{(perp_size * perp_coin_price).round(2)})"
25
+ puts "Slippage: #{(PERP_SLIPPAGE * 100).to_i}% (with retry up to #{((PERP_SLIPPAGE + ORACLE_SLIPPAGE_INCREMENT * (ORACLE_RETRY_ATTEMPTS - 1)) * 100).to_i}%)"
26
26
  puts
27
27
 
28
28
  puts 'Opening LONG position (market buy)...'
29
- result = sdk.exchange.market_order(
29
+ result = market_order_with_retry(
30
+ sdk,
30
31
  coin: perp_coin,
31
32
  is_buy: true,
32
33
  size: perp_size,
33
- slippage: PERP_SLIPPAGE
34
+ base_slippage: PERP_SLIPPAGE
34
35
  )
35
- check_result(result, 'Long open')
36
-
37
- wait_with_countdown(WAIT_SECONDS, 'Position open. Waiting before close...')
38
-
39
- puts 'Closing LONG position (market sell)...'
40
- result = sdk.exchange.market_order(
41
- coin: perp_coin,
42
- is_buy: false,
43
- size: perp_size,
44
- slippage: PERP_SLIPPAGE
45
- )
46
- check_result(result, 'Long close')
36
+ open_success = check_result(result, 'Long open')
37
+
38
+ if open_success
39
+ wait_with_countdown(WAIT_SECONDS, 'Position open. Waiting before close...')
40
+
41
+ puts 'Closing LONG position (market sell)...'
42
+ result = market_order_with_retry(
43
+ sdk,
44
+ coin: perp_coin,
45
+ is_buy: false,
46
+ size: perp_size,
47
+ base_slippage: PERP_SLIPPAGE
48
+ )
49
+ check_result(result, 'Long close')
50
+ else
51
+ puts red('Skipping close - position was not opened')
52
+ end
47
53
  else
48
54
  puts red("SKIPPED: Could not get #{perp_coin} price")
49
55
  end
@@ -3,6 +3,7 @@
3
3
 
4
4
  # Test 5: Update Leverage (BTC)
5
5
  # Set cross, isolated, then reset leverage.
6
+ # Requires no open BTC position (cannot switch leverage type with open position).
6
7
 
7
8
  require_relative 'test_helpers'
8
9
 
@@ -14,8 +15,16 @@ mids = sdk.info.all_mids
14
15
  btc_price = mids[perp_coin]&.to_f
15
16
 
16
17
  if btc_price&.positive?
18
+ # Check for open position - cannot switch leverage type with open position
19
+ unless check_position_and_prompt(sdk, perp_coin, timeout: 10)
20
+ puts
21
+ puts green('Test 5 Update Leverage skipped (open position).')
22
+ exit 0
23
+ end
24
+
17
25
  puts 'Setting BTC to 5x cross leverage...'
18
26
  result = sdk.exchange.update_leverage(coin: perp_coin, leverage: 5, is_cross: true)
27
+ dump_status(result)
19
28
  api_error?(result) || puts(green('5x cross leverage set'))
20
29
  puts
21
30
 
@@ -23,6 +32,7 @@ if btc_price&.positive?
23
32
 
24
33
  puts 'Setting BTC to 3x isolated leverage...'
25
34
  result = sdk.exchange.update_leverage(coin: perp_coin, leverage: 3, is_cross: false)
35
+ dump_status(result)
26
36
  api_error?(result) || puts(green('3x isolated leverage set'))
27
37
  puts
28
38
 
@@ -30,6 +40,7 @@ if btc_price&.positive?
30
40
 
31
41
  puts 'Resetting BTC to 1x cross leverage...'
32
42
  result = sdk.exchange.update_leverage(coin: perp_coin, leverage: 1, is_cross: true)
43
+ dump_status(result)
33
44
  api_error?(result) || puts(green('1x cross leverage set'))
34
45
  else
35
46
  puts red("SKIPPED: Could not get #{perp_coin} price")
@@ -1,46 +1,52 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # Test 7: Market Close (BTC)
4
+ # Test 7: Market Close (PERP)
5
5
  # Open a long position, then close it using market_close (auto-detect size).
6
6
 
7
7
  require_relative 'test_helpers'
8
8
 
9
9
  sdk = build_sdk
10
- separator('TEST 7: Market Close (BTC)')
10
+ perp_coin = 'ETH'
11
+ separator("TEST 7: Market Close (#{perp_coin})")
11
12
 
12
- perp_coin = 'BTC'
13
13
  mids = sdk.info.all_mids
14
- btc_price = mids[perp_coin]&.to_f
14
+ perp_coin_price = mids[perp_coin]&.to_f
15
15
 
16
- if btc_price&.positive?
16
+ if perp_coin_price&.positive?
17
17
  meta = sdk.info.meta
18
- btc_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
- sz_decimals = btc_meta['szDecimals']
18
+ perp_coin_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
+ sz_decimals = perp_coin_meta['szDecimals']
20
20
 
21
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
21
+ perp_size = (20.0 / perp_coin_price).ceil(sz_decimals)
22
22
 
23
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
24
- puts "Size: #{perp_size} BTC"
23
+ puts "#{perp_coin} mid: $#{perp_coin_price.round(2)}"
24
+ puts "Size: #{perp_size} #{perp_coin}"
25
+ puts "Slippage: #{(PERP_SLIPPAGE * 100).to_i}% (with retry up to #{((PERP_SLIPPAGE + ORACLE_SLIPPAGE_INCREMENT * (ORACLE_RETRY_ATTEMPTS - 1)) * 100).to_i}%)"
25
26
  puts
26
27
 
27
28
  puts 'Opening LONG position (market buy)...'
28
- result = sdk.exchange.market_order(
29
+ result = market_order_with_retry(
30
+ sdk,
29
31
  coin: perp_coin,
30
32
  is_buy: true,
31
33
  size: perp_size,
32
- slippage: PERP_SLIPPAGE
34
+ base_slippage: PERP_SLIPPAGE
33
35
  )
34
- check_result(result, 'Long open')
35
-
36
- wait_with_countdown(WAIT_SECONDS, 'Position open. Waiting before market_close...')
37
-
38
- puts 'Closing position using market_close (auto-detect size)...'
39
- result = sdk.exchange.market_close(
40
- coin: perp_coin,
41
- slippage: PERP_SLIPPAGE
42
- )
43
- check_result(result, 'Market close')
36
+ open_success = check_result(result, 'Long open')
37
+
38
+ if open_success
39
+ wait_with_countdown(WAIT_SECONDS, 'Position open. Waiting before market_close...')
40
+
41
+ puts 'Closing position using market_close (auto-detect size)...'
42
+ result = sdk.exchange.market_close(
43
+ coin: perp_coin,
44
+ slippage: PERP_SLIPPAGE + ORACLE_SLIPPAGE_INCREMENT # Use higher slippage for close
45
+ )
46
+ check_result(result, 'Market close')
47
+ else
48
+ puts red('Skipping market_close - position was not opened')
49
+ end
44
50
  else
45
51
  puts red("SKIPPED: Could not get #{perp_coin} price")
46
52
  end
@@ -11,6 +11,7 @@ separator('TEST 8: USD Class Transfer (Perp <-> Spot)')
11
11
 
12
12
  puts 'Transferring $10 from perp to spot...'
13
13
  result = sdk.exchange.usd_class_transfer(amount: '10', to_perp: false)
14
+ dump_status(result)
14
15
  api_error?(result) || puts(green('Transfer to spot successful!'))
15
16
  puts
16
17
 
@@ -18,6 +19,7 @@ wait_with_countdown(WAIT_SECONDS, 'Waiting before transferring back...')
18
19
 
19
20
  puts 'Transferring $10 from spot to perp...'
20
21
  result = sdk.exchange.usd_class_transfer(amount: '10', to_perp: true)
22
+ dump_status(result)
21
23
  api_error?(result) || puts(green('Transfer to perp successful!'))
22
24
 
23
25
  test_passed('Test 8 USD Class Transfer')
@@ -42,6 +42,7 @@ when 'deposit'
42
42
  is_deposit: true,
43
43
  usd: 10
44
44
  )
45
+ dump_status(result)
45
46
  api_error?(result) || puts(green('Vault deposit successful!'))
46
47
  when 'withdraw'
47
48
  equity_f = follower&.dig('vaultEquity')&.to_f || 0
@@ -53,6 +54,7 @@ when 'withdraw'
53
54
  is_deposit: false,
54
55
  usd: withdraw_amount
55
56
  )
57
+ dump_status(result)
56
58
  api_error?(result) || puts(green('Vault withdrawal successful!'))
57
59
  else
58
60
  puts red("Insufficient vault equity to withdraw ($#{equity_f})")
@@ -16,6 +16,7 @@ perp_coin = 'BTC'
16
16
  # Step 1: Approve builder fee
17
17
  puts "Approving builder fee for #{builder_address} (max #{max_fee_rate})..."
18
18
  result = sdk.exchange.approve_builder_fee(builder: builder_address, max_fee_rate: max_fee_rate)
19
+ dump_status(result)
19
20
  api_error?(result) || puts(green('Builder fee approved'))
20
21
  puts
21
22
 
@@ -50,6 +50,7 @@ when 'delegate'
50
50
  wei: delegate_amount,
51
51
  is_undelegate: false
52
52
  )
53
+ dump_status(result)
53
54
  api_error?(result) || puts(green('Delegation successful!'))
54
55
  when 'undelegate'
55
56
  puts "Undelegating 0.1 HYPE from #{validator}..."
@@ -58,6 +59,7 @@ when 'undelegate'
58
59
  wei: delegate_amount,
59
60
  is_undelegate: true
60
61
  )
62
+ dump_status(result)
61
63
  api_error?(result) || puts(green('Undelegation successful!'))
62
64
  else
63
65
  puts 'Pass "delegate" or "undelegate" as an argument to perform an action.'
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test 13: WebSocket l2Book Subscription
5
+ #
6
+ # Subscribes to ETH perp l2Book on testnet, prints 3 updates
7
+ # with top-of-book (best bid/ask), then cleanly disconnects.
8
+ #
9
+ # No private key required (read-only WebSocket).
10
+ #
11
+ # Usage:
12
+ # ruby scripts/test_13_ws_l2_book.rb
13
+
14
+ require_relative '../lib/hyperliquid'
15
+
16
+ def green(text)
17
+ "\e[32m#{text}\e[0m"
18
+ end
19
+
20
+ def red(text)
21
+ "\e[31m#{text}\e[0m"
22
+ end
23
+
24
+ puts
25
+ puts '=' * 60
26
+ puts 'TEST 13: WebSocket l2Book Subscription'
27
+ puts '=' * 60
28
+ puts
29
+ puts 'Network: Testnet'
30
+ puts 'Subscribing to ETH l2Book (3 updates, then disconnect)'
31
+ puts
32
+
33
+ sdk = Hyperliquid.new(testnet: true)
34
+ updates = []
35
+ mutex = Mutex.new
36
+ done = ConditionVariable.new
37
+
38
+ sdk.ws.on(:open) { puts 'WebSocket connected.' }
39
+ sdk.ws.on(:error) { |e| puts red("WebSocket error: #{e}") }
40
+
41
+ sdk.ws.subscribe({ type: 'l2Book', coin: 'ETH' }) do |data|
42
+ mutex.synchronize do
43
+ next if updates.length >= 3
44
+
45
+ levels = data['levels']
46
+ bids = levels&.dig(0) || []
47
+ asks = levels&.dig(1) || []
48
+ best_bid = bids.first
49
+ best_ask = asks.first
50
+
51
+ update_num = updates.length + 1
52
+ puts "Update #{update_num}/3:"
53
+ puts " Best bid: #{best_bid ? "#{best_bid['px']} (#{best_bid['sz']})" : 'n/a'}"
54
+ puts " Best ask: #{best_ask ? "#{best_ask['px']} (#{best_ask['sz']})" : 'n/a'}"
55
+ puts " Bid levels: #{bids.length}, Ask levels: #{asks.length}"
56
+ puts
57
+
58
+ updates << data
59
+ done.signal if updates.length >= 3
60
+ end
61
+ end
62
+
63
+ # Wait for 3 updates or timeout after 30 seconds
64
+ success = false
65
+ mutex.synchronize do
66
+ deadline = Time.now + 30
67
+ while updates.length < 3 && Time.now < deadline
68
+ remaining = deadline - Time.now
69
+ break if remaining <= 0
70
+
71
+ done.wait(mutex, remaining)
72
+ end
73
+ success = updates.length >= 3
74
+ end
75
+
76
+ sdk.ws.close
77
+
78
+ if success
79
+ puts green('Test 13 WebSocket l2Book passed!')
80
+ else
81
+ puts red("Test 13 FAILED: only received #{updates.length}/3 updates within 30s")
82
+ exit 1
83
+ end
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test 14: WebSocket candle Subscription
5
+ #
6
+ # Subscribes to ETH 1m candles on testnet, prints 3 updates
7
+ # with OHLCV data, then cleanly disconnects.
8
+ #
9
+ # No private key required (read-only WebSocket).
10
+ #
11
+ # Usage:
12
+ # ruby scripts/test_14_ws_candle.rb
13
+
14
+ require_relative '../lib/hyperliquid'
15
+
16
+ def green(text)
17
+ "\e[32m#{text}\e[0m"
18
+ end
19
+
20
+ def red(text)
21
+ "\e[31m#{text}\e[0m"
22
+ end
23
+
24
+ puts
25
+ puts '=' * 60
26
+ puts 'TEST 14: WebSocket candle Subscription'
27
+ puts '=' * 60
28
+ puts
29
+ puts 'Network: Testnet'
30
+ puts 'Subscribing to ETH 1m candles (3 updates, then disconnect)'
31
+ puts
32
+
33
+ sdk = Hyperliquid.new(testnet: true)
34
+ updates = []
35
+ mutex = Mutex.new
36
+ done = ConditionVariable.new
37
+
38
+ sdk.ws.on(:open) { puts 'WebSocket connected.' }
39
+ sdk.ws.on(:error) { |e| puts red("WebSocket error: #{e}") }
40
+
41
+ sdk.ws.subscribe({ type: 'candle', coin: 'ETH', interval: '1m' }) do |data|
42
+ mutex.synchronize do
43
+ next if updates.length >= 3
44
+
45
+ update_num = updates.length + 1
46
+ puts "Update #{update_num}/3:"
47
+ puts " Symbol: #{data['s']}"
48
+ puts " Interval: #{data['i']}"
49
+ puts " Open: #{data['o']}"
50
+ puts " High: #{data['h']}"
51
+ puts " Low: #{data['l']}"
52
+ puts " Close: #{data['c']}"
53
+ puts " Volume: #{data['v']}"
54
+ puts
55
+
56
+ updates << data
57
+ done.signal if updates.length >= 3
58
+ end
59
+ end
60
+
61
+ # Wait for 3 updates or timeout after 90 seconds (candles can be slow)
62
+ success = false
63
+ mutex.synchronize do
64
+ deadline = Time.now + 90
65
+ while updates.length < 3 && Time.now < deadline
66
+ remaining = deadline - Time.now
67
+ break if remaining <= 0
68
+
69
+ done.wait(mutex, remaining)
70
+ end
71
+ success = updates.length >= 3
72
+ end
73
+
74
+ sdk.ws.close
75
+
76
+ if success
77
+ puts green('Test 14 WebSocket candle passed!')
78
+ else
79
+ puts red("Test 14 FAILED: only received #{updates.length}/3 updates within 90s")
80
+ exit 1
81
+ end
data/scripts/test_all.rb CHANGED
@@ -30,7 +30,9 @@ SCRIPTS = [
30
30
  'test_09_sub_account_lifecycle.rb',
31
31
  'test_10_vault.rb',
32
32
  'test_11_builder_fee.rb',
33
- 'test_12_staking.rb'
33
+ 'test_12_staking.rb',
34
+ 'test_13_ws_l2_book.rb',
35
+ 'test_14_ws_candle.rb'
34
36
  ].freeze
35
37
 
36
38
  def green(text)
@@ -5,7 +5,9 @@ require 'json'
5
5
 
6
6
  WAIT_SECONDS = 3
7
7
  SPOT_SLIPPAGE = 0.40 # 40% for illiquid testnet spot markets
8
- PERP_SLIPPAGE = 0.05 # 5% for perp markets
8
+ PERP_SLIPPAGE = 0.15
9
+ ORACLE_RETRY_ATTEMPTS = 3
10
+ ORACLE_SLIPPAGE_INCREMENT = 0.10 # Increase slippage by 10% on each retry
9
11
 
10
12
  def green(text)
11
13
  "\e[32m#{text}\e[0m"
@@ -43,7 +45,19 @@ def api_error?(result)
43
45
  true
44
46
  end
45
47
 
48
+ # Extract and display the status from an API response
49
+ def dump_status(result)
50
+ return unless result.is_a?(Hash)
51
+
52
+ status = result.dig('response', 'data', 'statuses', 0)
53
+ return unless status
54
+
55
+ puts " API status: #{status.inspect}"
56
+ end
57
+
46
58
  def check_result(result, operation)
59
+ dump_status(result)
60
+
47
61
  return false if api_error?(result)
48
62
 
49
63
  status = result.dig('response', 'data', 'statuses', 0)
@@ -98,3 +112,119 @@ def build_sdk
98
112
 
99
113
  sdk
100
114
  end
115
+
116
+ # Check if result has "Price too far from oracle" error
117
+ def oracle_error?(result)
118
+ return false unless result.is_a?(Hash)
119
+
120
+ if result['status'] == 'err' && result['response'].to_s.include?('Price too far from oracle')
121
+ return true
122
+ end
123
+
124
+ status = result.dig('response', 'data', 'statuses', 0)
125
+ status.is_a?(Hash) && status['error'].to_s.include?('Price too far from oracle')
126
+ end
127
+
128
+ # Execute a market order with retry logic for oracle errors
129
+ def market_order_with_retry(sdk, coin:, is_buy:, size:, base_slippage:)
130
+ slippage = base_slippage
131
+
132
+ ORACLE_RETRY_ATTEMPTS.times do |attempt|
133
+ result = sdk.exchange.market_order(
134
+ coin: coin,
135
+ is_buy: is_buy,
136
+ size: size,
137
+ slippage: slippage
138
+ )
139
+
140
+ unless oracle_error?(result)
141
+ return result
142
+ end
143
+
144
+ if attempt < ORACLE_RETRY_ATTEMPTS - 1
145
+ slippage += ORACLE_SLIPPAGE_INCREMENT
146
+ puts red("Oracle price error. Retrying with #{(slippage * 100).to_i}% slippage (attempt #{attempt + 2}/#{ORACLE_RETRY_ATTEMPTS})...")
147
+ sleep 1
148
+ else
149
+ return result
150
+ end
151
+ end
152
+ end
153
+
154
+ # Get position for a coin, returns nil if no position
155
+ def get_position(sdk, coin)
156
+ state = sdk.info.user_state(sdk.exchange.address)
157
+ positions = state['assetPositions'] || []
158
+ positions.find { |p| p.dig('position', 'coin') == coin }
159
+ end
160
+
161
+ # Check for open position and prompt user to clean up
162
+ # Returns true if test should continue, false if should skip
163
+ def check_position_and_prompt(sdk, coin, timeout: 10)
164
+ position = get_position(sdk, coin)
165
+ return true unless position
166
+
167
+ size = position.dig('position', 'szi').to_f
168
+ return true if size.zero?
169
+
170
+ puts red("WARNING: Open #{coin} position detected (size: #{size})")
171
+ puts "This test requires no open #{coin} position."
172
+ puts
173
+ puts "Options:"
174
+ puts " [c] Close the position and continue"
175
+ puts " [s] Skip this test"
176
+ puts
177
+ print "Choice (auto-skip in #{timeout}s): "
178
+ $stdout.flush
179
+
180
+ # Non-blocking read with timeout
181
+ require 'io/wait'
182
+ choice = nil
183
+ start = Time.now
184
+ loop do
185
+ if $stdin.ready?
186
+ choice = $stdin.gets&.strip&.downcase
187
+ break
188
+ end
189
+ elapsed = Time.now - start
190
+ remaining = (timeout - elapsed).ceil
191
+ if elapsed >= timeout
192
+ puts
193
+ puts "No response, skipping test..."
194
+ return false
195
+ end
196
+ print "\rChoice (auto-skip in #{remaining}s): "
197
+ $stdout.flush
198
+ sleep 0.5
199
+ end
200
+
201
+ case choice
202
+ when 'c'
203
+ puts "Closing #{coin} position..."
204
+ result = sdk.exchange.market_close(coin: coin, slippage: PERP_SLIPPAGE + 0.20)
205
+ dump_status(result)
206
+ if api_error?(result)
207
+ puts red("Failed to close position. Skipping test.")
208
+ return false
209
+ end
210
+ puts green("Position closed. Waiting for settlement...")
211
+
212
+ # Wait and verify position is actually closed
213
+ 5.times do |i|
214
+ sleep 2
215
+ position = get_position(sdk, coin)
216
+ remaining = position&.dig('position', 'szi').to_f.abs
217
+ if remaining < 0.000001
218
+ puts green("Position fully settled.")
219
+ return true
220
+ end
221
+ puts " Still settling... (#{remaining} remaining)"
222
+ end
223
+
224
+ puts red("Position did not fully close. Skipping test.")
225
+ false
226
+ else
227
+ puts "Skipping test."
228
+ false
229
+ end
230
+ end
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: 0.7.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - carter2099
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
67
  version: '1.7'
68
+ - !ruby/object:Gem::Dependency
69
+ name: ws_lite
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 1.0.0
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 1.0.0
68
82
  description: A Ruby SDK for interacting with Hyperliquid's decentralized exchange
69
83
  API
70
84
  email:
@@ -88,6 +102,7 @@ files:
88
102
  - docs/DEVELOPMENT.md
89
103
  - docs/ERRORS.md
90
104
  - docs/EXAMPLES.md
105
+ - docs/WS.md
91
106
  - example.rb
92
107
  - lib/hyperliquid.rb
93
108
  - lib/hyperliquid/client.rb
@@ -99,6 +114,7 @@ files:
99
114
  - lib/hyperliquid/signing/eip712.rb
100
115
  - lib/hyperliquid/signing/signer.rb
101
116
  - lib/hyperliquid/version.rb
117
+ - lib/hyperliquid/ws/client.rb
102
118
  - scripts/test_01_spot_market_roundtrip.rb
103
119
  - scripts/test_02_spot_limit_order.rb
104
120
  - scripts/test_03_perp_market_roundtrip.rb
@@ -111,6 +127,8 @@ files:
111
127
  - scripts/test_10_vault.rb
112
128
  - scripts/test_11_builder_fee.rb
113
129
  - scripts/test_12_staking.rb
130
+ - scripts/test_13_ws_l2_book.rb
131
+ - scripts/test_14_ws_candle.rb
114
132
  - scripts/test_all.rb
115
133
  - scripts/test_helpers.rb
116
134
  - sig/hyperliquid.rbs