hyperliquid 1.4.0 → 1.5.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: c7969eed04a0b822b7be2c29c3ab57f97f077eaf8ed245bc48cb4916fd6b5836
4
- data.tar.gz: d37e1acbf31a1e26454071ede7c83fcccf842bf9524835def63a652e77fff1af
3
+ metadata.gz: 3bf3db383f0da2f70b1d7e98e8901f29fbb4cde940a18859c57c98592c4ffbf3
4
+ data.tar.gz: 0055af5f445d241193e27189a585423e3410d296a7df96ba447827299a9b9cd4
5
5
  SHA512:
6
- metadata.gz: 1a7bc66c9acd82975bb1e5929d2f4b77469c5e52b3c9824f7ce5306ad642c1e065531d6f4c20134cdab85c350b2f694736c5a414ee6e7a564d35abc658ed1074
7
- data.tar.gz: 9898cba2cbf564dff73f950a29423dd5f42ab2fddf62458418d365546893dabdc5f3ddf159f1af31c7e6254ff02aeaa1a77ca0c63f6198931ee291319daaab82
6
+ metadata.gz: 32986974696870940a6ca517f963be23faf84c3dfc7adbfe14f0bcfb5d919118c683ab7f3faa9fd3cfa3249c95c92d89f240cc15917e3e18092331e6141a59de
7
+ data.tar.gz: 9a2d495448ba88243b14bfae7f0fe81ddebab3dbc743dce21742b58955196ff9cdd7a6e6a45cea2d958e00cd023748250c923d203258e32d346390638dd4e9de
data/.rubocop.yml CHANGED
@@ -26,10 +26,11 @@ Metrics/BlockLength:
26
26
  - 'spec/**/*'
27
27
  - '*.gemspec'
28
28
 
29
- # Exchange API methods require many parameters
29
+ # Exchange API methods (and multi-sig co-signer helpers that pass through to them) require many parameters
30
30
  Metrics/ParameterLists:
31
31
  Exclude:
32
32
  - 'lib/hyperliquid/exchange.rb'
33
+ - 'lib/hyperliquid/signing/multi_sig.rb'
33
34
 
34
35
  # Allow higher complexity for order type conversion logic and WS message handling
35
36
  Metrics/CyclomaticComplexity:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Ruby Hyperliquid SDK Changelog]
2
2
 
3
+ ## [1.5.0] - 2026-05-08
4
+
5
+ ### New Exchange actions
6
+
7
+ - `Exchange#multi_sig(multi_sig_user:, inner_action:, signatures:, nonce:, vault_address:)` — wraps any inner action with N pre-collected co-signer signatures and submits via the user-signed multi-sig envelope. Adds `MULTI_SIG_TYPES` (first EIP-712 type using `bytes32`).
8
+ - `Exchange#create_vault(name:, description:, initial_usd:, ...)` — L1 action that creates a new vault with the calling wallet as leader. Float-USD scaled to integer micro-USD via `float_to_usd_int`.
9
+
10
+ ### New signing primitives
11
+
12
+ - `Signing::MultiSig` module with `build_envelope`, `envelope_action_hash`, `sign_as_co_signer_l1` (for L1 inner actions, phantom-agent flow), and `sign_as_co_signer_user_signed` (enriches the inner action's typed-data spec with `payloadMultiSigUser` + `outerSigner` fields). Co-signature collection remains the caller's responsibility.
13
+ - `Signer.compute_action_hash` exposed as a public class method (refactored out of `construct_phantom_agent` for reuse from multi-sig).
14
+
15
+ ### Tests
16
+
17
+ - Fixture-based byte-parity specs against Python `eth_account` 0.13.7 + `msgpack` 1.1.2 covering: outer multi-sig signature with no co-signers, outer + L1 co-signer signatures over an order action, and a user-signed co-signer signature over a sendAsset action.
18
+
3
19
  ## [1.4.0] - 2026-05-05
4
20
 
5
21
  ### New Exchange actions
data/CLAUDE.md CHANGED
@@ -65,6 +65,8 @@ Any change to signing must maintain parity with the Python SDK or transactions w
65
65
 
66
66
  User-signed actions (`usd_send`, `withdraw_from_bridge`, `send_to_evm_with_data`, etc.) use direct EIP-712 typed-data signing with the `HyperliquidSignTransaction` domain (chain ID 421614) — not the phantom-agent flow. Each has a typed-data spec in `Signing::EIP712`. The `eth` gem's typed-data signer handles primitive types (`string`, `uint*`, `address`, `bool`) and dynamic `bytes` correctly — `send_to_evm_with_data` was the first to use `bytes`, and its spec includes a fixture-based signature parity test against `eth_account` to lock that in. When adding new user-signed actions with non-string types, add a similar fixture to catch eth-gem regressions.
67
67
 
68
+ Multi-sig actions (`Exchange#multi_sig`) wrap any inner action with N co-signer signatures. The submitter's outer signature uses `MULTI_SIG_TYPES` over `{hyperliquidChain, multiSigActionHash, nonce}`; the `multiSigActionHash` is `Signer.compute_action_hash` of the multi-sig envelope (with `:type` stripped). Co-signer signing is exposed via `Signing::MultiSig.sign_as_co_signer_l1` (for L1 inner actions — signs `[multi_sig_user, outer_signer, action]` via phantom-agent) and `Signing::MultiSig.sign_as_co_signer_user_signed` (enriches the inner action's typed-data spec with `payloadMultiSigUser`+`outerSigner` address fields). Both mirror the Python SDK byte-for-byte; specs include fixture-based parity tests captured against `eth_account`+`msgpack`. Co-signature *collection* is the caller's responsibility — the SDK does not coordinate signing rooms.
69
+
68
70
  ### Numeric Conversion
69
71
 
70
72
  - **`float_to_wire`** (in Exchange): converts to string with 8-decimal precision, validates rounding tolerance (`1e-12`), normalizes trailing zeros. No scientific notation.
@@ -793,6 +793,40 @@ module Hyperliquid
793
793
  post_action(action, signature, nonce, nil)
794
794
  end
795
795
 
796
+ # Submit a multi-signature action wrapping any inner exchange action with N pre-collected
797
+ # co-signer signatures (`multiSig` user-signed envelope). The submitter's outer signature
798
+ # authorises execution; co-signer signatures must be collected externally via
799
+ # `Signing::MultiSig.sign_as_co_signer_l1` (for L1 inner actions) or
800
+ # `Signing::MultiSig.sign_as_co_signer_user_signed` (for user-signed inner actions).
801
+ # @param multi_sig_user [String] Address of the multi-sig user being acted on
802
+ # @param inner_action [Hash] The wrapped action body
803
+ # @param signatures [Array<Hash>] Co-signer signatures (each :r, :s, :v)
804
+ # @param nonce [Integer, nil] Nonce timestamp; defaults to `timestamp_ms`. Must match the
805
+ # nonce used by every co-signer when they signed.
806
+ # @param vault_address [String, nil] Optional vault address (must match co-signer hashes)
807
+ # @return [Hash] Exchange response
808
+ def multi_sig(multi_sig_user:, inner_action:, signatures:, nonce: nil, vault_address: nil)
809
+ nonce ||= timestamp_ms
810
+ envelope = Signing::MultiSig.build_envelope(
811
+ inner_action: inner_action,
812
+ multi_sig_user: multi_sig_user,
813
+ outer_signer: @signer.address,
814
+ signatures: signatures
815
+ )
816
+ multi_sig_action_hash = Signing::MultiSig.envelope_action_hash(
817
+ envelope: envelope,
818
+ nonce: nonce,
819
+ vault_address: vault_address,
820
+ expires_after: @expires_after
821
+ )
822
+ signature = @signer.sign_user_signed_action(
823
+ { multiSigActionHash: multi_sig_action_hash, nonce: nonce },
824
+ Signing::MultiSig::OUTER_PRIMARY_TYPE,
825
+ Signing::EIP712::MULTI_SIG_TYPES
826
+ )
827
+ post_action(envelope, signature, nonce, vault_address)
828
+ end
829
+
796
830
  # Claim accrued referral-program rewards (`claimRewards` L1 action).
797
831
  # @return [Hash] Exchange response
798
832
  def claim_rewards
@@ -893,6 +927,29 @@ module Hyperliquid
893
927
  post_action(action, signature, nonce, nil)
894
928
  end
895
929
 
930
+ # Create a new vault with the calling wallet as leader (`createVault` L1 action).
931
+ # @param name [String] Vault name (server-enforced 3–50 characters)
932
+ # @param description [String] Vault description (server-enforced 10–250 characters)
933
+ # @param initial_usd [Numeric] Initial USD seed (server-enforced $100 minimum);
934
+ # scaled internally to integer 1e6 micro-USD
935
+
936
+ # @return [Hash] Exchange response — on success `response.data` is the new vault address
937
+ def create_vault(name:, description:, initial_usd:)
938
+ nonce = timestamp_ms
939
+ action = {
940
+ type: 'createVault',
941
+ name: name,
942
+ description: description,
943
+ initialUsd: float_to_usd_int(initial_usd),
944
+ nonce: nonce
945
+ }
946
+ signature = @signer.sign_l1_action(
947
+ action, nonce,
948
+ expires_after: @expires_after
949
+ )
950
+ post_action(action, signature, nonce, nil)
951
+ end
952
+
896
953
  # Borrow, lend, supply, or withdraw HIP-2 borrow/lend assets (`borrowLend` L1 action).
897
954
  # Companion to the four HIP-2 info methods (`borrow_lend_user_state` etc.).
898
955
  # @param operation [String] One of 'supply', 'withdraw', 'repay', 'borrow'
@@ -130,6 +130,14 @@ module Hyperliquid
130
130
  ]
131
131
  }.freeze
132
132
 
133
+ MULTI_SIG_TYPES = {
134
+ 'HyperliquidTransaction:SendMultiSig': [
135
+ { name: :hyperliquidChain, type: 'string' },
136
+ { name: :multiSigActionHash, type: 'bytes32' },
137
+ { name: :nonce, type: 'uint64' }
138
+ ]
139
+ }.freeze
140
+
133
141
  SEND_TO_EVM_WITH_DATA_TYPES = {
134
142
  'HyperliquidTransaction:SendToEvmWithData': [
135
143
  { name: :hyperliquidChain, type: 'string' },
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'msgpack'
4
+
5
+ module Hyperliquid
6
+ module Signing
7
+ # Multi-signature action helpers — submitter envelope construction and co-signer signing.
8
+ #
9
+ # Mirrors the official Python SDK's three multi-sig flows:
10
+ # 1. `Exchange#multi_sig` (the submitter — signs the outer envelope)
11
+ # 2. `sign_as_co_signer_l1` — co-signer for L1 inner actions (orders, cancels, etc.)
12
+ # 3. `sign_as_co_signer_user_signed` — co-signer for user-signed inner actions
13
+ # (sendAsset, usdSend, etc.)
14
+ #
15
+ # Co-signature collection is the caller's responsibility — these helpers produce a single
16
+ # co-signer signature; the submitter then assembles the array and posts the envelope.
17
+ module MultiSig
18
+ OUTER_PRIMARY_TYPE = 'HyperliquidTransaction:SendMultiSig'
19
+
20
+ # Build the outer multi-sig envelope (the action body posted to /exchange).
21
+ # @param inner_action [Hash] The wrapped action (any L1 or user-signed action body)
22
+ # @param multi_sig_user [String] Address of the multi-sig user (lowercased)
23
+ # @param outer_signer [String] Address of the submitter (lowercased)
24
+ # @param signatures [Array<Hash>] Pre-collected co-signer signatures
25
+ # @return [Hash] Multi-sig envelope ready for signing + posting
26
+ def self.build_envelope(inner_action:, multi_sig_user:, outer_signer:, signatures:)
27
+ {
28
+ type: 'multiSig',
29
+ signatureChainId: '0x66eee',
30
+ signatures: signatures,
31
+ payload: {
32
+ multiSigUser: multi_sig_user.downcase,
33
+ outerSigner: outer_signer.downcase,
34
+ action: inner_action
35
+ }
36
+ }
37
+ end
38
+
39
+ # Compute the multiSigActionHash that the submitter signs over.
40
+ # Mirrors Python's `sign_multi_sig_action`: action_hash(envelope - type, vault, nonce, expires).
41
+ # @param envelope [Hash] The multi-sig envelope (will have :type stripped before hashing)
42
+ # @param nonce [Integer] Nonce timestamp (ms)
43
+ # @param vault_address [String, nil] Optional vault address
44
+ # @param expires_after [Integer, nil] Optional expiration timestamp (ms)
45
+ # @return [String] 0x-prefixed 32-byte hex hash
46
+ def self.envelope_action_hash(envelope:, nonce:, vault_address: nil, expires_after: nil)
47
+ without_type = envelope.dup
48
+ without_type.delete(:type)
49
+ Signer.compute_action_hash(without_type, nonce, vault_address: vault_address,
50
+ expires_after: expires_after)
51
+ end
52
+
53
+ # Co-signer flow for L1 inner actions (orders, cancels, leverage, etc.).
54
+ # The signed payload is the list `[multi_sig_user, outer_signer, action]`, hashed and
55
+ # signed via the L1 phantom-agent flow.
56
+ #
57
+ # @param signer [Signer] Co-signer's wallet
58
+ # @param inner_action [Hash] The wrapped L1 action
59
+ # @param multi_sig_user [String] Multi-sig user address
60
+ # @param outer_signer [String] Submitter address (NOT the co-signer's address)
61
+ # @param nonce [Integer] Nonce timestamp (ms)
62
+ # @param vault_address [String, nil] Optional vault address
63
+ # @param expires_after [Integer, nil] Optional expiration timestamp (ms)
64
+ # @return [Hash] Signature with :r, :s, :v
65
+ def self.sign_as_co_signer_l1(signer:, inner_action:, multi_sig_user:, outer_signer:, nonce:,
66
+ vault_address: nil, expires_after: nil)
67
+ envelope = [multi_sig_user.downcase, outer_signer.downcase, inner_action]
68
+ signer.sign_l1_action(envelope, nonce, vault_address: vault_address,
69
+ expires_after: expires_after)
70
+ end
71
+
72
+ # Co-signer flow for user-signed inner actions (sendAsset, usdSend, etc.).
73
+ # Enriches the inner action with `payloadMultiSigUser` + `outerSigner` fields and the
74
+ # corresponding type entries, then signs via the user-signed typed-data flow.
75
+ #
76
+ # @param signer [Signer] Co-signer's wallet
77
+ # @param inner_action [Hash] The wrapped user-signed action body
78
+ # @param multi_sig_user [String] Multi-sig user address
79
+ # @param outer_signer [String] Submitter address
80
+ # @param primary_type [String] Inner action's EIP-712 primary type (e.g. 'HyperliquidTransaction:SendAsset')
81
+ # @param sign_types [Hash] Inner action's EIP-712 type definitions
82
+ # @return [Hash] Signature with :r, :s, :v
83
+ def self.sign_as_co_signer_user_signed(signer:, inner_action:, multi_sig_user:, outer_signer:,
84
+ primary_type:, sign_types:)
85
+ enriched_action = inner_action.merge(
86
+ payloadMultiSigUser: multi_sig_user.downcase,
87
+ outerSigner: outer_signer.downcase
88
+ )
89
+ enriched_types = enrich_user_signed_types(sign_types)
90
+ signer.sign_user_signed_action(enriched_action, primary_type, enriched_types)
91
+ end
92
+
93
+ # Insert payloadMultiSigUser + outerSigner type entries immediately after hyperliquidChain.
94
+ # Matches Python SDK's `add_multi_sig_types`.
95
+ def self.enrich_user_signed_types(sign_types)
96
+ sign_types.each_with_object({}) do |(key, fields), result|
97
+ new_fields = []
98
+ fields.each do |f|
99
+ new_fields << f
100
+ if f[:name].to_s == 'hyperliquidChain'
101
+ new_fields << { name: :payloadMultiSigUser, type: 'address' }
102
+ new_fields << { name: :outerSigner, type: 'address' }
103
+ end
104
+ end
105
+ result[key] = new_fields
106
+ end
107
+ end
108
+ private_class_method :enrich_user_signed_types
109
+ end
110
+ end
111
+ end
@@ -50,6 +50,33 @@ module Hyperliquid
50
50
  sign_typed_data(typed_data)
51
51
  end
52
52
 
53
+ # Compute the action hash used by the L1 phantom-agent flow and by the multi-sig
54
+ # outer-envelope flow. Mirrors the official Python SDK's `action_hash` byte layout:
55
+ # keccak256(msgpack(action) + nonce(8B BE) + vault_flag + [vault_addr] + [expires_flag + expires_after])
56
+ # @param action [Hash, Array] The action payload (or list-shaped envelope for multi-sig L1)
57
+ # @param nonce [Integer] Nonce timestamp (ms)
58
+ # @param vault_address [String, nil] Optional vault address (lowercased before hashing)
59
+ # @param expires_after [Integer, nil] Optional expiration timestamp (ms)
60
+ # @return [String] 0x-prefixed hex of the 32-byte keccak256 hash
61
+ def self.compute_action_hash(action, nonce, vault_address: nil, expires_after: nil)
62
+ data = action.to_msgpack
63
+ data += [nonce].pack('Q>')
64
+
65
+ if vault_address.nil?
66
+ data += "\x00"
67
+ else
68
+ data += "\x01"
69
+ data += [vault_address.sub(/\A0x/i, '').downcase].pack('H*')
70
+ end
71
+
72
+ unless expires_after.nil?
73
+ data += "\x00"
74
+ data += [expires_after].pack('Q>')
75
+ end
76
+
77
+ "0x#{Eth::Util.keccak256(data).unpack1('H*')}"
78
+ end
79
+
53
80
  # Sign a user-signed action (transfers, withdrawals, etc.)
54
81
  # Uses direct EIP-712 typed data signing with HyperliquidSignTransaction domain
55
82
  # @param action [Hash] The action message to sign (will have chain fields injected)
@@ -92,41 +119,14 @@ module Hyperliquid
92
119
  # @param expires_after [Integer, nil] Optional expiration timestamp
93
120
  # @return [Hash] Phantom agent with source and connectionId
94
121
  def construct_phantom_agent(action, nonce, vault_address, expires_after)
95
- # Compute action hash
96
- # Maintains parity with official Python SDK
97
- # data = msgpack(action) + nonce(8 bytes BE) + vault_flag + [vault_addr] + [expires_flag + expires_after]
98
- # - Note: expires_flag is only included if expires_after exists. A bit odd but that's what the
99
- # Python SDK does.
100
- data = action.to_msgpack
101
- data += [nonce].pack('Q>') # 8-byte big-endian uint64
102
-
103
- if vault_address.nil?
104
- data += "\x00" # no vault flag
105
- else
106
- data += "\x01" # has vault flag
107
- data += address_to_bytes(vault_address.downcase)
108
- end
109
-
110
- unless expires_after.nil?
111
- data += "\x00" # expiration flag
112
- data += [expires_after].pack('Q>') # 8-byte big-endian uint64
113
- end
114
-
115
- connection_id = Eth::Util.keccak256(data)
116
-
117
122
  {
118
123
  source: EIP712.source(testnet: @testnet),
119
- connectionId: bin_to_hex(connection_id)
124
+ connectionId: self.class.compute_action_hash(action, nonce,
125
+ vault_address: vault_address,
126
+ expires_after: expires_after)
120
127
  }
121
128
  end
122
129
 
123
- # Convert hex address to 20-byte binary
124
- # @param address [String] Ethereum address with 0x prefix
125
- # @return [String] 20-byte binary representation
126
- def address_to_bytes(address)
127
- [address.sub(/\A0x/i, '')].pack('H*')
128
- end
129
-
130
130
  # Sign EIP-712 typed data using eth gem's built-in method
131
131
  # @param typed_data [Hash] Complete EIP-712 structure
132
132
  # @return [Hash] Signature components :r, :s, :v
@@ -141,13 +141,6 @@ module Hyperliquid
141
141
  v: signature[128, 2].to_i(16)
142
142
  }
143
143
  end
144
-
145
- # Convert binary data to hex string with 0x prefix
146
- # @param bin [String] Binary data
147
- # @return [String] Hex string with 0x prefix
148
- def bin_to_hex(bin)
149
- "0x#{bin.unpack1('H*')}"
150
- end
151
144
  end
152
145
  end
153
146
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hyperliquid
4
- VERSION = '1.4.0'
4
+ VERSION = '1.5.0'
5
5
  end
data/lib/hyperliquid.rb CHANGED
@@ -8,6 +8,7 @@ require_relative 'hyperliquid/info'
8
8
  require_relative 'hyperliquid/cloid'
9
9
  require_relative 'hyperliquid/signing/eip712'
10
10
  require_relative 'hyperliquid/signing/signer'
11
+ require_relative 'hyperliquid/signing/multi_sig'
11
12
  require_relative 'hyperliquid/exchange'
12
13
  require_relative 'hyperliquid/ws/client'
13
14
 
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test 17: createVault (L1 exchange action)
5
+ #
6
+ # Creates a new vault with the calling wallet as leader, using a $100 testnet
7
+ # USDC seed (server-enforced minimum). On success, prints the new vault address
8
+ # from response.data.
9
+ #
10
+ # WARNING: This is a real testnet action. The $100 seed is locked into the
11
+ # created vault per Hyperliquid's vault lockup rules. Run intentionally —
12
+ # do NOT wire into test_automated.rb.
13
+ #
14
+ # Skips with a warning if the wallet has < $100 perp USDC available.
15
+ #
16
+ # Usage:
17
+ # HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_17_create_vault.rb
18
+
19
+ require_relative 'test_helpers'
20
+
21
+ sdk = build_sdk
22
+ separator('TEST 17: createVault')
23
+
24
+ state = sdk.info.user_state(sdk.exchange.address)
25
+ withdrawable = state['withdrawable'].to_f
26
+ puts "Wallet: #{sdk.exchange.address}"
27
+ puts "Withdrawable: $#{format('%.2f', withdrawable)}"
28
+ puts
29
+
30
+ if withdrawable < 100
31
+ puts red("SKIPPED: Need >= $100 perp USDC to seed a vault (have $#{format('%.2f', withdrawable)}).")
32
+ test_passed('Test 17 createVault')
33
+ exit 0
34
+ end
35
+
36
+ vault_name = "AgentVault#{Time.now.to_i}"
37
+ vault_description = 'Vault created by hyperliquid-run integration test (test_17).'
38
+
39
+ puts "Creating vault \"#{vault_name}\" with $100 seed..."
40
+ result = sdk.exchange.create_vault(
41
+ name: vault_name,
42
+ description: vault_description,
43
+ initial_usd: 100
44
+ )
45
+
46
+ if api_error?(result)
47
+ puts red("createVault FAILED: #{result.inspect}")
48
+ test_passed('Test 17 createVault')
49
+ exit 1
50
+ end
51
+
52
+ unless result.is_a?(Hash) && result['status'] == 'ok'
53
+ $test_failed = true
54
+ puts red("Unexpected status: #{result.inspect}")
55
+ end
56
+
57
+ response_type = result.dig('response', 'type')
58
+ unless response_type == 'createVault'
59
+ $test_failed = true
60
+ puts red("Expected response.type 'createVault', got: #{response_type.inspect}")
61
+ end
62
+
63
+ vault_address = result.dig('response', 'data')
64
+ unless vault_address.is_a?(String) && vault_address.start_with?('0x') && vault_address.length == 42
65
+ $test_failed = true
66
+ puts red("Expected response.data to be a 0x-prefixed 40-hex-char vault address, got: #{vault_address.inspect}")
67
+ end
68
+
69
+ unless $test_failed
70
+ puts green("createVault OK: status=ok, response.type=#{response_type}, vault=#{vault_address}")
71
+ end
72
+
73
+ test_passed('Test 17 createVault')
data/scripts/test_all.rb CHANGED
@@ -34,7 +34,8 @@ SCRIPTS = [
34
34
  'test_13_ws_l2_book.rb',
35
35
  'test_14_ws_candle.rb',
36
36
  'test_15_explorer.rb',
37
- 'test_16_send_to_evm_with_data.rb'
37
+ 'test_16_send_to_evm_with_data.rb',
38
+ 'test_17_create_vault.rb'
38
39
  ].freeze
39
40
 
40
41
  def green(text)
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.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - carter2099
@@ -112,6 +112,7 @@ files:
112
112
  - lib/hyperliquid/exchange.rb
113
113
  - lib/hyperliquid/info.rb
114
114
  - lib/hyperliquid/signing/eip712.rb
115
+ - lib/hyperliquid/signing/multi_sig.rb
115
116
  - lib/hyperliquid/signing/signer.rb
116
117
  - lib/hyperliquid/version.rb
117
118
  - lib/hyperliquid/ws/client.rb
@@ -131,6 +132,7 @@ files:
131
132
  - scripts/test_14_ws_candle.rb
132
133
  - scripts/test_15_explorer.rb
133
134
  - scripts/test_16_send_to_evm_with_data.rb
135
+ - scripts/test_17_create_vault.rb
134
136
  - scripts/test_all.rb
135
137
  - scripts/test_automated.rb
136
138
  - scripts/test_helpers.rb