hyperliquid 0.4.1 → 0.6.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.
data/test_integration.rb CHANGED
@@ -1,255 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # Hyperliquid Ruby SDK - Testnet Integration Test
4
+ # Hyperliquid Ruby SDK - Testnet Integration Tests
5
5
  #
6
- # This script tests the Exchange API against the live testnet:
7
- # 1. Spot market roundtrip (buy PURR, sell PURR)
8
- # 2. Spot limit order (place and cancel)
9
- # 3. Perp market roundtrip (long BTC, close position)
10
- # 4. Perp limit order (place short, cancel)
11
- #
12
- # Prerequisites:
13
- # - Testnet wallet with USDC balance
14
- # - Get testnet funds from: https://app.hyperliquid-testnet.xyz
6
+ # This is a convenience wrapper that runs all integration tests.
7
+ # Individual tests live in scripts/ and can be run standalone.
15
8
  #
16
9
  # Usage:
17
10
  # HYPERLIQUID_PRIVATE_KEY=0x... ruby test_integration.rb
18
11
  #
19
- # Note: This script executes real trades on testnet. No real funds are at risk.
20
-
21
- require_relative 'lib/hyperliquid'
22
- require 'json'
23
-
24
- WAIT_SECONDS = 10
25
- SPOT_SLIPPAGE = 0.40 # 40% for illiquid testnet spot markets
26
- PERP_SLIPPAGE = 0.05 # 5% for perp markets
27
-
28
- def separator(title)
29
- puts
30
- puts '=' * 60
31
- puts title
32
- puts '=' * 60
33
- puts
34
- end
35
-
36
- def wait_with_countdown(seconds, message)
37
- puts message
38
- seconds.downto(1) do |i|
39
- print "\r #{i} seconds remaining... "
40
- sleep 1
41
- end
42
- puts "\r Done! "
43
- puts
44
- end
45
-
46
- def check_result(result, operation)
47
- status = result.dig('response', 'data', 'statuses', 0)
48
-
49
- if status.is_a?(Hash) && status['error']
50
- puts "FAILED: #{status['error']}"
51
- return false
52
- end
53
-
54
- if status.is_a?(Hash) && status['resting']
55
- puts "Order resting with OID: #{status['resting']['oid']}"
56
- return status['resting']['oid']
57
- end
58
-
59
- if status == 'success' || (status.is_a?(Hash) && status['filled'])
60
- puts "#{operation} successful!"
61
- return true
62
- end
63
-
64
- puts "Result: #{status.inspect}"
65
- true
66
- end
67
-
68
- # --- Main Script ---
69
-
70
- private_key = ENV['HYPERLIQUID_PRIVATE_KEY']
71
- unless private_key
72
- puts 'Error: Set HYPERLIQUID_PRIVATE_KEY environment variable'
73
- puts 'Usage: HYPERLIQUID_PRIVATE_KEY=0x... ruby test_integration.rb'
74
- exit 1
75
- end
76
-
77
- sdk = Hyperliquid.new(
78
- testnet: true,
79
- private_key: private_key
80
- )
81
-
82
- puts 'Hyperliquid Ruby SDK - Testnet Integration Test'
83
- puts '=' * 60
84
- puts "Wallet: #{sdk.exchange.address}"
85
- puts 'Network: Testnet'
86
- puts "Testnet UI: https://app.hyperliquid-testnet.xyz"
87
-
88
- # ============================================================
89
- # TEST 1: Spot Market Roundtrip (PURR/USDC)
90
- # ============================================================
91
- separator('TEST 1: Spot Market Roundtrip (PURR/USDC)')
92
-
93
- spot_coin = 'PURR/USDC'
94
- spot_size = 5 # PURR has 0 decimals
95
-
96
- mids = sdk.info.all_mids
97
- spot_price = mids[spot_coin]&.to_f
98
-
99
- if spot_price&.positive?
100
- puts "#{spot_coin} mid: $#{spot_price}"
101
- puts "Size: #{spot_size} PURR (~$#{(spot_size * spot_price).round(2)})"
102
- puts "Slippage: #{(SPOT_SLIPPAGE * 100).to_i}%"
103
- puts
104
-
105
- # Buy
106
- puts 'Placing market BUY...'
107
- result = sdk.exchange.market_order(
108
- coin: spot_coin,
109
- is_buy: true,
110
- size: spot_size,
111
- slippage: SPOT_SLIPPAGE
112
- )
113
- check_result(result, 'Buy')
114
-
115
- wait_with_countdown(WAIT_SECONDS, 'Waiting before sell...')
116
-
117
- # Sell
118
- puts 'Placing market SELL...'
119
- result = sdk.exchange.market_order(
120
- coin: spot_coin,
121
- is_buy: false,
122
- size: spot_size,
123
- slippage: SPOT_SLIPPAGE
124
- )
125
- check_result(result, 'Sell')
126
- else
127
- puts "SKIPPED: Could not get #{spot_coin} price"
128
- end
129
-
130
- # ============================================================
131
- # TEST 2: Spot Limit Order (Place and Cancel)
132
- # ============================================================
133
- separator('TEST 2: Spot Limit Order (Place and Cancel)')
134
-
135
- if spot_price&.positive?
136
- # Place limit buy well below market (won't fill)
137
- limit_price = (spot_price * 0.50).round(2) # 50% below mid
138
- puts "#{spot_coin} mid: $#{spot_price}"
139
- puts "Limit price: $#{limit_price} (50% below mid - won't fill)"
140
- puts "Size: #{spot_size} PURR"
141
- puts
142
-
143
- puts 'Placing limit BUY order...'
144
- result = sdk.exchange.order(
145
- coin: spot_coin,
146
- is_buy: true,
147
- size: spot_size,
148
- limit_px: limit_price,
149
- order_type: { limit: { tif: 'Gtc' } },
150
- reduce_only: false
151
- )
152
- oid = check_result(result, 'Limit order')
153
-
154
- if oid.is_a?(Integer)
155
- wait_with_countdown(WAIT_SECONDS, 'Order resting. Waiting before cancel...')
156
-
157
- puts "Canceling order #{oid}..."
158
- result = sdk.exchange.cancel(coin: spot_coin, oid: oid)
159
- check_result(result, 'Cancel')
160
- end
161
- else
162
- puts "SKIPPED: Could not get #{spot_coin} price"
163
- end
164
-
165
- # ============================================================
166
- # TEST 3: Perp Market Roundtrip (BTC Long)
167
- # ============================================================
168
- separator('TEST 3: Perp Market Roundtrip (BTC Long)')
169
-
170
- perp_coin = 'BTC'
171
- btc_price = mids[perp_coin]&.to_f
172
-
173
- if btc_price&.positive?
174
- # Get BTC metadata for size precision
175
- meta = sdk.info.meta
176
- btc_meta = meta['universe'].find { |a| a['name'] == perp_coin }
177
- sz_decimals = btc_meta['szDecimals']
178
-
179
- # Calculate size for ~$20 notional
180
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
181
-
182
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
183
- puts "Size: #{perp_size} BTC (~$#{(perp_size * btc_price).round(2)})"
184
- puts "Slippage: #{(PERP_SLIPPAGE * 100).to_i}%"
185
- puts
186
-
187
- # Open long
188
- puts 'Opening LONG position (market buy)...'
189
- result = sdk.exchange.market_order(
190
- coin: perp_coin,
191
- is_buy: true,
192
- size: perp_size,
193
- slippage: PERP_SLIPPAGE
194
- )
195
- check_result(result, 'Long open')
196
-
197
- wait_with_countdown(WAIT_SECONDS, 'Position open. Waiting before close...')
198
-
199
- # Close long (sell to close)
200
- puts 'Closing LONG position (market sell)...'
201
- result = sdk.exchange.market_order(
202
- coin: perp_coin,
203
- is_buy: false,
204
- size: perp_size,
205
- slippage: PERP_SLIPPAGE
206
- )
207
- check_result(result, 'Long close')
208
- else
209
- puts "SKIPPED: Could not get #{perp_coin} price"
210
- end
211
-
212
- # ============================================================
213
- # TEST 4: Perp Limit Order (Short, then Cancel)
214
- # ============================================================
215
- separator('TEST 4: Perp Limit Order (Short, then Cancel)')
216
-
217
- if btc_price&.positive?
218
- # Place limit sell well above market (won't fill)
219
- limit_price = (btc_price * 1.50).round(0).to_i # 50% above mid, whole number tick
220
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
221
-
222
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
223
- puts "Limit price: $#{limit_price} (50% above mid - won't fill)"
224
- puts "Size: #{perp_size} BTC"
225
- puts
226
-
227
- puts 'Placing limit SELL order (short)...'
228
- result = sdk.exchange.order(
229
- coin: perp_coin,
230
- is_buy: false,
231
- size: perp_size,
232
- limit_px: limit_price,
233
- order_type: { limit: { tif: 'Gtc' } },
234
- reduce_only: false
235
- )
236
- oid = check_result(result, 'Limit short')
237
-
238
- if oid.is_a?(Integer)
239
- wait_with_countdown(WAIT_SECONDS, 'Order resting. Waiting before cancel...')
240
-
241
- puts "Canceling order #{oid}..."
242
- result = sdk.exchange.cancel(coin: perp_coin, oid: oid)
243
- check_result(result, 'Cancel')
244
- end
245
- else
246
- puts "SKIPPED: Could not get #{perp_coin} price"
247
- end
12
+ # Run a single test:
13
+ # HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_08_usd_class_transfer.rb
14
+ #
15
+ # See scripts/test_all.rb for the full list.
248
16
 
249
- # ============================================================
250
- # Summary
251
- # ============================================================
252
- separator('INTEGRATION TEST COMPLETE')
253
- puts 'All tests executed. Check your testnet wallet for trade history:'
254
- puts 'https://app.hyperliquid-testnet.xyz'
255
- puts
17
+ load File.join(__dir__, 'scripts', 'test_all.rb')
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.4.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - carter2099
@@ -82,6 +82,7 @@ files:
82
82
  - LICENSE.txt
83
83
  - README.md
84
84
  - Rakefile
85
+ - SECURITY.md
85
86
  - docs/API.md
86
87
  - docs/CONFIGURATION.md
87
88
  - docs/DEVELOPMENT.md
@@ -98,6 +99,18 @@ files:
98
99
  - lib/hyperliquid/signing/eip712.rb
99
100
  - lib/hyperliquid/signing/signer.rb
100
101
  - lib/hyperliquid/version.rb
102
+ - scripts/test_01_spot_market_roundtrip.rb
103
+ - scripts/test_02_spot_limit_order.rb
104
+ - scripts/test_03_perp_market_roundtrip.rb
105
+ - scripts/test_04_perp_limit_order.rb
106
+ - scripts/test_05_update_leverage.rb
107
+ - scripts/test_06_modify_order.rb
108
+ - scripts/test_07_market_close.rb
109
+ - scripts/test_08_usd_class_transfer.rb
110
+ - scripts/test_09_sub_account_lifecycle.rb
111
+ - scripts/test_10_vault_transfer.rb
112
+ - scripts/test_all.rb
113
+ - scripts/test_helpers.rb
101
114
  - sig/hyperliquid.rbs
102
115
  - test_integration.rb
103
116
  homepage: https://github.com/carter2099/hyperliquid