hyperliquid 1.9.2 → 2.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/docs/API.md +374 -152
  4. data/docs/CONFIGURATION.md +25 -11
  5. data/docs/DEVELOPMENT.md +93 -15
  6. data/docs/ERRORS.md +2 -0
  7. data/docs/EXAMPLES.md +256 -3
  8. data/docs/WS.md +78 -20
  9. data/lib/hyperliquid/client.rb +19 -10
  10. data/lib/hyperliquid/exchange.rb +844 -22
  11. data/lib/hyperliquid/info.rb +27 -14
  12. data/lib/hyperliquid/signing/signer.rb +18 -1
  13. data/lib/hyperliquid/version.rb +1 -1
  14. data/lib/hyperliquid/ws/client.rb +192 -78
  15. data/lib/hyperliquid.rb +6 -0
  16. metadata +36 -34
  17. data/.rspec +0 -3
  18. data/.rubocop.yml +0 -49
  19. data/.ruby-version +0 -1
  20. data/CLAUDE.md +0 -108
  21. data/CODE_OF_CONDUCT.md +0 -132
  22. data/Rakefile +0 -12
  23. data/example.rb +0 -161
  24. data/scripts/test_01_spot_market_roundtrip.rb +0 -48
  25. data/scripts/test_02_spot_limit_order.rb +0 -48
  26. data/scripts/test_03_perp_market_roundtrip.rb +0 -58
  27. data/scripts/test_04_perp_limit_order.rb +0 -52
  28. data/scripts/test_05_update_leverage.rb +0 -50
  29. data/scripts/test_06_modify_order.rb +0 -67
  30. data/scripts/test_07_market_close.rb +0 -55
  31. data/scripts/test_08_usd_class_transfer.rb +0 -36
  32. data/scripts/test_09_sub_account_lifecycle.rb +0 -51
  33. data/scripts/test_10_vault.rb +0 -68
  34. data/scripts/test_11_builder_fee.rb +0 -81
  35. data/scripts/test_12_staking.rb +0 -70
  36. data/scripts/test_13_ws_l2_book.rb +0 -83
  37. data/scripts/test_14_ws_candle.rb +0 -81
  38. data/scripts/test_15_explorer.rb +0 -71
  39. data/scripts/test_16_send_to_evm_with_data.rb +0 -79
  40. data/scripts/test_17_create_vault.rb +0 -73
  41. data/scripts/test_18_user_portfolio_margin.rb +0 -72
  42. data/scripts/test_19_spot_user.rb +0 -55
  43. data/scripts/test_20_explorer_ws.rb +0 -92
  44. data/scripts/test_all.rb +0 -96
  45. data/scripts/test_automated.rb +0 -82
  46. data/scripts/test_helpers.rb +0 -238
  47. data/sig/hyperliquid.rbs +0 -4
  48. data/test_integration.rb +0 -17
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 2: Spot Limit Order (Place and Cancel)
5
- # Place a limit buy well below market, then cancel it.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 2: Spot Limit Order (Place and Cancel)')
11
-
12
- spot_coin = 'PURR/USDC'
13
- spot_size = 5
14
-
15
- mids = sdk.info.all_mids
16
- spot_price = mids[spot_coin]&.to_f
17
-
18
- if spot_price&.positive?
19
- limit_price = (spot_price * 0.50).round(2)
20
- puts "#{spot_coin} mid: $#{spot_price}"
21
- puts "Limit price: $#{limit_price} (50% below mid - won't fill)"
22
- puts "Size: #{spot_size} PURR"
23
- puts
24
-
25
- puts 'Placing limit BUY order...'
26
- result = sdk.exchange.order(
27
- coin: spot_coin,
28
- is_buy: true,
29
- size: spot_size,
30
- limit_px: limit_price,
31
- order_type: { limit: { tif: 'Gtc' } },
32
- reduce_only: false
33
- )
34
- oid = check_result(result, 'Limit order')
35
-
36
- if oid.is_a?(Integer)
37
- wait_with_countdown(WAIT_SECONDS, 'Order resting. Waiting before cancel...')
38
-
39
- puts "Canceling order #{oid}..."
40
- result = sdk.exchange.cancel(coin: spot_coin, oid: oid)
41
- check_result(result, 'Cancel')
42
- end
43
- else
44
- puts red("SKIPPED: Could not get #{spot_coin} price")
45
- end
46
-
47
- test_passed('Test 2 Spot Limit Order')
48
-
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 3: Perp Market Roundtrip (Long)
5
- # Open a long perp position, then close it.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- perp_coin = 'ETH'
11
- separator("TEST 3: Perp Market Roundtrip (#{perp_coin} Long)")
12
-
13
- mids = sdk.info.all_mids
14
- perp_coin_price = mids[perp_coin]&.to_f
15
-
16
- if perp_coin_price&.positive?
17
- meta = sdk.info.meta
18
- perp_coin_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
- sz_decimals = perp_coin_meta['szDecimals']
20
-
21
- perp_size = (20.0 / perp_coin_price).ceil(sz_decimals)
22
-
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
- puts
27
-
28
- puts 'Opening LONG position (market buy)...'
29
- result = market_order_with_retry(
30
- sdk,
31
- coin: perp_coin,
32
- is_buy: true,
33
- size: perp_size,
34
- base_slippage: PERP_SLIPPAGE
35
- )
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
53
- else
54
- puts red("SKIPPED: Could not get #{perp_coin} price")
55
- end
56
-
57
- test_passed('Test 3 Perp Market Roundtrip')
58
-
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 4: Perp Limit Order (Short, then Cancel)
5
- # Place a limit sell well above market, then cancel it.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 4: Perp Limit Order (Short, then Cancel)')
11
-
12
- perp_coin = 'BTC'
13
- mids = sdk.info.all_mids
14
- btc_price = mids[perp_coin]&.to_f
15
-
16
- if btc_price&.positive?
17
- meta = sdk.info.meta
18
- btc_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
- sz_decimals = btc_meta['szDecimals']
20
-
21
- limit_price = (btc_price * 1.50).round(0).to_i
22
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
23
-
24
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
25
- puts "Limit price: $#{limit_price} (50% above mid - won't fill)"
26
- puts "Size: #{perp_size} BTC"
27
- puts
28
-
29
- puts 'Placing limit SELL order (short)...'
30
- result = sdk.exchange.order(
31
- coin: perp_coin,
32
- is_buy: false,
33
- size: perp_size,
34
- limit_px: limit_price,
35
- order_type: { limit: { tif: 'Gtc' } },
36
- reduce_only: false
37
- )
38
- oid = check_result(result, 'Limit short')
39
-
40
- if oid.is_a?(Integer)
41
- wait_with_countdown(WAIT_SECONDS, 'Order resting. Waiting before cancel...')
42
-
43
- puts "Canceling order #{oid}..."
44
- result = sdk.exchange.cancel(coin: perp_coin, oid: oid)
45
- check_result(result, 'Cancel')
46
- end
47
- else
48
- puts red("SKIPPED: Could not get #{perp_coin} price")
49
- end
50
-
51
- test_passed('Test 4 Perp Limit Order')
52
-
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 5: Update Leverage (BTC)
5
- # Set cross, isolated, then reset leverage.
6
- # Requires no open BTC position (cannot switch leverage type with open position).
7
-
8
- require_relative 'test_helpers'
9
-
10
- sdk = build_sdk
11
- separator('TEST 5: Update Leverage (BTC)')
12
-
13
- perp_coin = 'BTC'
14
- mids = sdk.info.all_mids
15
- btc_price = mids[perp_coin]&.to_f
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
-
25
- puts 'Setting BTC to 5x cross leverage...'
26
- result = sdk.exchange.update_leverage(coin: perp_coin, leverage: 5, is_cross: true)
27
- dump_status(result)
28
- api_error?(result) || puts(green('5x cross leverage set'))
29
- puts
30
-
31
- wait_with_countdown(WAIT_SECONDS, 'Waiting before next leverage update...')
32
-
33
- puts 'Setting BTC to 3x isolated leverage...'
34
- result = sdk.exchange.update_leverage(coin: perp_coin, leverage: 3, is_cross: false)
35
- dump_status(result)
36
- api_error?(result) || puts(green('3x isolated leverage set'))
37
- puts
38
-
39
- wait_with_countdown(WAIT_SECONDS, 'Waiting before resetting leverage...')
40
-
41
- puts 'Resetting BTC to 1x cross leverage...'
42
- result = sdk.exchange.update_leverage(coin: perp_coin, leverage: 1, is_cross: true)
43
- dump_status(result)
44
- api_error?(result) || puts(green('1x cross leverage set'))
45
- else
46
- puts red("SKIPPED: Could not get #{perp_coin} price")
47
- end
48
-
49
- test_passed('Test 5 Update Leverage')
50
-
@@ -1,67 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 6: Modify Order (BTC)
5
- # Place a limit buy, modify its price, then cancel.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 6: Modify Order (BTC)')
11
-
12
- perp_coin = 'BTC'
13
- mids = sdk.info.all_mids
14
- btc_price = mids[perp_coin]&.to_f
15
-
16
- if btc_price&.positive?
17
- meta = sdk.info.meta
18
- btc_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
- sz_decimals = btc_meta['szDecimals']
20
-
21
- original_price = (btc_price * 0.50).round(0).to_i
22
- modified_price = (btc_price * 0.51).round(0).to_i
23
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
24
-
25
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
26
- puts "Original limit: $#{original_price} (50% below mid)"
27
- puts "Modified limit: $#{modified_price} (49% below mid)"
28
- puts "Size: #{perp_size} BTC"
29
- puts
30
-
31
- puts 'Placing limit BUY order...'
32
- result = sdk.exchange.order(
33
- coin: perp_coin,
34
- is_buy: true,
35
- size: perp_size,
36
- limit_px: original_price,
37
- order_type: { limit: { tif: 'Gtc' } }
38
- )
39
- oid = check_result(result, 'Limit buy')
40
-
41
- if oid.is_a?(Integer)
42
- wait_with_countdown(WAIT_SECONDS, 'Order resting. Waiting before modify...')
43
-
44
- puts "Modifying order #{oid} (price: $#{original_price} -> $#{modified_price})..."
45
- result = sdk.exchange.modify_order(
46
- oid: oid,
47
- coin: perp_coin,
48
- is_buy: true,
49
- size: perp_size,
50
- limit_px: modified_price
51
- )
52
- new_oid = check_result(result, 'Modify')
53
- new_oid = oid unless new_oid.is_a?(Integer)
54
- puts
55
-
56
- wait_with_countdown(WAIT_SECONDS, 'Waiting before cancel...')
57
-
58
- puts "Canceling modified order #{new_oid}..."
59
- result = sdk.exchange.cancel(coin: perp_coin, oid: new_oid)
60
- check_result(result, 'Cancel')
61
- end
62
- else
63
- puts red("SKIPPED: Could not get #{perp_coin} price")
64
- end
65
-
66
- test_passed('Test 6 Modify Order')
67
-
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 7: Market Close (PERP)
5
- # Open a long position, then close it using market_close (auto-detect size).
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- perp_coin = 'ETH'
11
- separator("TEST 7: Market Close (#{perp_coin})")
12
-
13
- mids = sdk.info.all_mids
14
- perp_coin_price = mids[perp_coin]&.to_f
15
-
16
- if perp_coin_price&.positive?
17
- meta = sdk.info.meta
18
- perp_coin_meta = meta['universe'].find { |a| a['name'] == perp_coin }
19
- sz_decimals = perp_coin_meta['szDecimals']
20
-
21
- perp_size = (20.0 / perp_coin_price).ceil(sz_decimals)
22
-
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}%)"
26
- puts
27
-
28
- puts 'Opening LONG position (market buy)...'
29
- result = market_order_with_retry(
30
- sdk,
31
- coin: perp_coin,
32
- is_buy: true,
33
- size: perp_size,
34
- base_slippage: PERP_SLIPPAGE
35
- )
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
50
- else
51
- puts red("SKIPPED: Could not get #{perp_coin} price")
52
- end
53
-
54
- test_passed('Test 7 Market Close')
55
-
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 8: USD Class Transfer (Perp <-> Spot)
5
- # Transfer $10 from perp to spot, then back.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 8: USD Class Transfer (Perp <-> Spot)')
11
-
12
- # Unified-account wallets cannot use usdClassTransfer — perp and spot balances
13
- # are merged, so the action is disabled at the exchange layer. Detect this up
14
- # front and skip rather than hitting a predictable "Action disabled" failure.
15
- abstraction = sdk.info.user_abstraction(sdk.exchange.address)
16
- if abstraction == 'unifiedAccount'
17
- puts "SKIPPED: Wallet has unified account active (abstraction=#{abstraction.inspect})."
18
- puts ' usdClassTransfer is disabled by the exchange when perp/spot balances are unified.'
19
- test_passed('Test 8 USD Class Transfer')
20
- exit 0
21
- end
22
-
23
- puts 'Transferring $10 from perp to spot...'
24
- result = sdk.exchange.usd_class_transfer(amount: '10', to_perp: false)
25
- dump_status(result)
26
- api_error?(result) || puts(green('Transfer to spot successful!'))
27
- puts
28
-
29
- wait_with_countdown(WAIT_SECONDS, 'Waiting before transferring back...')
30
-
31
- puts 'Transferring $10 from spot to perp...'
32
- result = sdk.exchange.usd_class_transfer(amount: '10', to_perp: true)
33
- dump_status(result)
34
- api_error?(result) || puts(green('Transfer to perp successful!'))
35
-
36
- test_passed('Test 8 USD Class Transfer')
@@ -1,51 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 9: Sub Account Lifecycle
5
- # Create a sub-account, deposit $10, then withdraw $10.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 9: Sub Account Lifecycle')
11
-
12
- puts 'Creating sub-account "ruby-sdk-test"...'
13
- result = sdk.exchange.create_sub_account(name: 'ruby-sdk-test')
14
-
15
- if api_error?(result)
16
- exit 1
17
- end
18
-
19
- puts green('Sub-account created!')
20
- puts
21
-
22
- sub_account_address = result.dig('response', 'data', 'subAccountUser')
23
- if sub_account_address
24
- puts "Sub-account address: #{sub_account_address}"
25
- puts
26
-
27
- wait_with_countdown(WAIT_SECONDS, 'Waiting before deposit...')
28
-
29
- puts 'Depositing $10 to sub-account...'
30
- result = sdk.exchange.sub_account_transfer(
31
- sub_account_user: sub_account_address,
32
- is_deposit: true,
33
- usd: 10
34
- )
35
- api_error?(result) || puts(green('Deposit successful!'))
36
- puts
37
-
38
- wait_with_countdown(WAIT_SECONDS, 'Waiting before withdrawal...')
39
-
40
- puts 'Withdrawing $10 from sub-account...'
41
- result = sdk.exchange.sub_account_transfer(
42
- sub_account_user: sub_account_address,
43
- is_deposit: false,
44
- usd: 10
45
- )
46
- api_error?(result) || puts(green('Withdrawal successful!'))
47
- else
48
- puts red('SKIPPED: Could not extract sub-account address from response')
49
- end
50
-
51
- test_passed('Test 9 Sub Account Lifecycle')
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 10: Vault Status / Deposit / Withdraw
5
- #
6
- # Default: Show vault status (equity, entry date, unlock date)
7
- # Options: ruby test_10_vault_transfer.rb deposit
8
- # ruby test_10_vault_transfer.rb withdraw
9
-
10
- require_relative 'test_helpers'
11
-
12
- sdk = build_sdk
13
- separator('TEST 10: Vault Status / Deposit / Withdraw')
14
-
15
- vault_addr = '0xa15099a30bbf2e68942d6f4c43d70d04faeab0a0'
16
- action = ARGV[0] # nil, "deposit", or "withdraw"
17
-
18
- puts "Vault: #{vault_addr}"
19
- puts
20
-
21
- vault = sdk.info.vault_details(vault_addr, sdk.exchange.address)
22
- follower = vault['followerState']
23
-
24
- if follower
25
- equity = follower['vaultEquity']
26
- entry_time = follower['vaultEntryTime']
27
- lockup_until = follower['lockupUntil']
28
-
29
- puts "Vault equity: $#{equity}"
30
- puts "Entry date: #{Time.at(entry_time / 1000.0).utc}" if entry_time
31
- puts "Unlock date: #{Time.at(lockup_until / 1000.0).utc}" if lockup_until
32
- else
33
- puts 'No position in this vault.'
34
- end
35
- puts
36
-
37
- case action
38
- when 'deposit'
39
- puts 'Depositing $10 to vault...'
40
- result = sdk.exchange.vault_transfer(
41
- vault_address: vault_addr,
42
- is_deposit: true,
43
- usd: 10
44
- )
45
- dump_status(result)
46
- api_error?(result) || puts(green('Vault deposit successful!'))
47
- when 'withdraw'
48
- equity_f = follower&.dig('vaultEquity')&.to_f || 0
49
- if equity_f > 1
50
- withdraw_amount = equity_f.floor
51
- puts "Withdrawing $#{withdraw_amount} from vault..."
52
- result = sdk.exchange.vault_transfer(
53
- vault_address: vault_addr,
54
- is_deposit: false,
55
- usd: withdraw_amount
56
- )
57
- dump_status(result)
58
- api_error?(result) || puts(green('Vault withdrawal successful!'))
59
- else
60
- puts red("Insufficient vault equity to withdraw ($#{equity_f})")
61
- end
62
- else
63
- puts 'Pass "deposit" or "withdraw" as an argument to perform a transfer.'
64
- puts ' ruby scripts/test_10_vault_transfer.rb deposit'
65
- puts ' ruby scripts/test_10_vault_transfer.rb withdraw'
66
- end
67
-
68
- test_passed('Test 10 Vault Status')
@@ -1,81 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 11: Builder Fee (Approve + Order with Builder)
5
- # Approve a builder fee, then place an order with builder param, then cancel.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 11: Builder Fee (Approve + Order with Builder)')
11
-
12
- builder_address = '0x250F311Ae04D3CEA03443C76340069eD26C47D7D'
13
- max_fee_rate = '0.01%'
14
- perp_coin = 'BTC'
15
-
16
- # Step 1: Approve builder fee
17
- # On testnet, the builder may not meet the exchange's minimum balance for approval.
18
- # That precondition failure is not an SDK bug — we downgrade it to a warning and
19
- # continue, since the order-with-builder-fee flow (the thing we actually ship)
20
- # can still be exercised if a prior approval is in place.
21
- puts "Approving builder fee for #{builder_address} (max #{max_fee_rate})..."
22
- result = sdk.exchange.approve_builder_fee(builder: builder_address, max_fee_rate: max_fee_rate)
23
- if result.is_a?(Hash) && result['status'] == 'err' &&
24
- result['response'].to_s.include?('insufficient balance')
25
- puts red("WARNING: #{result['response']}")
26
- puts ' Continuing — this is a testnet precondition, not an SDK failure.'
27
- else
28
- dump_status(result)
29
- api_error?(result) || puts(green('Builder fee approved'))
30
- end
31
- puts
32
-
33
- wait_with_countdown(WAIT_SECONDS, 'Waiting before placing order with builder...')
34
-
35
- # Step 2: Verify approval via Info API
36
- puts 'Checking builder fee approval...'
37
- approval = sdk.info.max_builder_fee(sdk.exchange.address, builder_address)
38
- puts "Max builder fee: #{approval.inspect}"
39
- puts
40
-
41
- # Step 3: Place order with builder param
42
- mids = sdk.info.all_mids
43
- btc_price = mids[perp_coin]&.to_f
44
-
45
- if btc_price&.positive?
46
- meta = sdk.info.meta
47
- btc_meta = meta['universe'].find { |a| a['name'] == perp_coin }
48
- sz_decimals = btc_meta['szDecimals']
49
-
50
- limit_price = (btc_price * 1.50).round(0).to_i
51
- perp_size = (20.0 / btc_price).ceil(sz_decimals)
52
-
53
- puts "#{perp_coin} mid: $#{btc_price.round(2)}"
54
- puts "Limit price: $#{limit_price} (50% above mid - won't fill)"
55
- puts "Size: #{perp_size} BTC"
56
- puts "Builder: #{builder_address} (fee: 10 = 1bp)"
57
- puts
58
-
59
- puts 'Placing limit SELL order with builder fee...'
60
- result = sdk.exchange.order(
61
- coin: perp_coin,
62
- is_buy: false,
63
- size: perp_size,
64
- limit_px: limit_price,
65
- order_type: { limit: { tif: 'Gtc' } },
66
- builder: { b: builder_address, f: 10 }
67
- )
68
- oid = check_result(result, 'Limit short with builder')
69
-
70
- if oid.is_a?(Integer)
71
- wait_with_countdown(WAIT_SECONDS, 'Order resting. Waiting before cancel...')
72
-
73
- puts "Canceling order #{oid}..."
74
- result = sdk.exchange.cancel(coin: perp_coin, oid: oid)
75
- check_result(result, 'Cancel')
76
- end
77
- else
78
- puts red("SKIPPED: Could not get #{perp_coin} price")
79
- end
80
-
81
- test_passed('Test 11 Builder Fee')
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 12: Staking Status / Delegate / Undelegate
5
- #
6
- # Default: Show staking summary and delegations
7
- # Options: ruby test_12_staking.rb delegate
8
- # ruby test_12_staking.rb undelegate
9
-
10
- require_relative 'test_helpers'
11
-
12
- sdk = build_sdk
13
- separator('TEST 12: Staking Status / Delegate / Undelegate')
14
-
15
- validator = '0x946bf3135c7d15e4462b510f74b6e304aabb5b21'
16
- action = ARGV[0] # nil, "delegate", or "undelegate"
17
- delegate_amount = 10_000_000 # 0.1 HYPE (wei = float * 1e8)
18
-
19
- puts "Validator: #{validator}"
20
- puts
21
-
22
- # Show staking summary
23
- summary = sdk.info.delegator_summary(sdk.exchange.address)
24
- puts "Staking summary:"
25
- puts " Delegated: #{summary['delegated']}" if summary['delegated']
26
- puts " Undelegatable: #{summary['undelegatable']}" if summary['undelegatable']
27
- puts " Total pending: #{summary['totalPending']}" if summary['totalPending']
28
- puts " N delegations: #{summary['nDelegations']}" if summary['nDelegations']
29
- puts
30
-
31
- # Show delegations for this validator
32
- delegations = sdk.info.delegations(sdk.exchange.address)
33
- validator_delegation = delegations&.find { |d| d['validator']&.downcase == validator.downcase }
34
-
35
- if validator_delegation
36
- puts "Delegation to #{validator}:"
37
- puts " Amount: #{validator_delegation['amount']}"
38
- lockup = validator_delegation['lockedUntilTimestamp']
39
- puts " Locked until: #{Time.at(lockup / 1000.0).utc}" if lockup
40
- else
41
- puts "No active delegation to #{validator}."
42
- end
43
- puts
44
-
45
- case action
46
- when 'delegate'
47
- puts "Delegating 0.1 HYPE to #{validator}..."
48
- result = sdk.exchange.token_delegate(
49
- validator: validator,
50
- wei: delegate_amount,
51
- is_undelegate: false
52
- )
53
- dump_status(result)
54
- api_error?(result) || puts(green('Delegation successful!'))
55
- when 'undelegate'
56
- puts "Undelegating 0.1 HYPE from #{validator}..."
57
- result = sdk.exchange.token_delegate(
58
- validator: validator,
59
- wei: delegate_amount,
60
- is_undelegate: true
61
- )
62
- dump_status(result)
63
- api_error?(result) || puts(green('Undelegation successful!'))
64
- else
65
- puts 'Pass "delegate" or "undelegate" as an argument to perform an action.'
66
- puts ' ruby scripts/test_12_staking.rb delegate'
67
- puts ' ruby scripts/test_12_staking.rb undelegate'
68
- end
69
-
70
- test_passed('Test 12 Staking')