hyperliquid 1.6.0 → 1.7.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: ea2358a056d774b7c16f5630111fe847204db819d4cdb6c0c9a3c9d601e9977d
4
- data.tar.gz: cd896dd17790c385765d0484c5d1d57c8589ac4b8b8b238eae624dde135f47b1
3
+ metadata.gz: fa1051cb2277e69795819ed2ae8564e89ac3e6b34139d9112a8273f0604d2fa1
4
+ data.tar.gz: 072416d6751fa766f0b4eeb5c416365ea96652b980301932d3ab32a549750b24
5
5
  SHA512:
6
- metadata.gz: dce41aa6805c512465cba2a66a33a277ad84b6130b06ca80641f45b45ecd8cea6e89d30a1ad592fd30d93f90ef06c4369633ba35df98b6b0429ccd3bfb1377c0
7
- data.tar.gz: 913c99238363b115273cfd31e2ec3ae8fe61d3de9b2e7367cd0a295b771d75e3b5f5dc050f97d535dfa66b10bae6fcda52dc54835c0e61ffee8b5f14fea2ba2a
6
+ metadata.gz: 41059a1ef505d93e061fdd575f42ca340c6eb1e8100f14adf176c9512bd65ce4c1afdd1ddeeb831a1833bce63b9ca065f602681c673bba9b96f7a298130b05a0
7
+ data.tar.gz: 9cfb58786186bafc873dc9dd1747c2b87a645770fddc8d759ea3b5420e7367f1118de056de8e470dbe8bff06e44e55033ce063d839a3c81803fc418e3be68890
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Ruby Hyperliquid SDK Changelog]
2
2
 
3
+ ## [1.7.0] - 2026-06-11
4
+
5
+ ### New Exchange actions
6
+
7
+ - `Exchange#authorize_aqav2_role(token:, role:)` — L1 action authorizing an AQAv2 role (e.g. `"treasury"`); supports `expires_after`.
8
+ - `Exchange#staking_link_disable_trading_user(trading_user:)` — user-signed action linking a staking account to a trading user (irreversible). Adds `STAKING_LINK_DISABLE_TRADING_USER_TYPES`.
9
+ - `Exchange#finalize_evm_contract(input:)` — L1 action linking a HyperCore spot token to a HyperEVM ERC-20 contract. Accepts a `Hash` (`{create: {nonce:}}`) or string variant (`"firstStorageSlot"` / `"customStorageSlot"`).
10
+ - HIP-4 `userOutcome` variants (L1 actions, not user-signed): `split_outcome(question:, outcome:, amount:)`, `merge_outcome(question:, amount:)`, `merge_question(question:, amount:)`, `negate_outcome(question:, outcome:, amount:)`. `merge_outcome` and `merge_question` accept `amount: nil` for the max-available case.
11
+
12
+ ### New Info methods
13
+
14
+ - `Info#settled_outcome(outcome:)` — returns settled prediction-market outcome data.
15
+
16
+ ### Fixes
17
+
18
+ - `Signing::MultiSig.payload_action` now normalizes `userSetAbstraction` long-form abstraction values (`"disabled"`, `"unifiedAccount"`, `"portfolioMargin"`) to their wire enum equivalents (`"i"`, `"u"`, `"p"`) in the L1 payload posted to `/exchange`, matching Python SDK 0.24.0. Pre-translated short codes pass through unchanged.
19
+
3
20
  ## [1.6.0] - 2026-05-26
4
21
 
5
22
  ### New Exchange actions
@@ -1017,6 +1017,31 @@ module Hyperliquid
1017
1017
  post_action(action, signature, nonce, nil)
1018
1018
  end
1019
1019
 
1020
+ # Permanently disable a linked trading user, locking its funds
1021
+ # (`stakingLinkDisableTradingUser` user-signed action). Sent by the staking user.
1022
+ # After 1 year of locking, funds from the trading user are automatically transferred
1023
+ # to the staking user. **This action is irreversible.** The `trading_user` address is
1024
+ # lowercased to match the address-field convention used by other user-signed actions.
1025
+ # @param trading_user [String] Trading user address to disable
1026
+ # @return [Hash] Exchange response
1027
+ def staking_link_disable_trading_user(trading_user:)
1028
+ nonce = timestamp_ms
1029
+ trading_user_lower = trading_user.downcase
1030
+ action = {
1031
+ type: 'stakingLinkDisableTradingUser',
1032
+ signatureChainId: '0x66eee',
1033
+ hyperliquidChain: Signing::EIP712.hyperliquid_chain(testnet: @testnet),
1034
+ tradingUser: trading_user_lower,
1035
+ nonce: nonce
1036
+ }
1037
+ signature = @signer.sign_user_signed_action(
1038
+ { tradingUser: trading_user_lower, nonce: nonce },
1039
+ 'HyperliquidTransaction:StakingLinkDisableTradingUser',
1040
+ Signing::EIP712::STAKING_LINK_DISABLE_TRADING_USER_TYPES
1041
+ )
1042
+ post_action(action, signature, nonce, nil)
1043
+ end
1044
+
1020
1045
  # Move assets between DEX instances on behalf of an agent's principal
1021
1046
  # (`agentSendAsset` L1 action). Unlike `send_asset` (which is user-signed),
1022
1047
  # this is signed by an agent and the destination must equal the agent's
@@ -1237,6 +1262,104 @@ module Hyperliquid
1237
1262
  post_action(action, signature, nonce, nil)
1238
1263
  end
1239
1264
 
1265
+ # HIP-4: split `amount` quote tokens into `amount` Yes and `amount` No shares
1266
+ # of an outcome (`userOutcome` L1 action, splitOutcome variant).
1267
+ # @param outcome [Integer] Outcome identifier
1268
+ # @param amount [String, Numeric] Amount of quote tokens to split (UnsignedDecimal, coerced via to_s)
1269
+ # @return [Hash] Exchange response
1270
+ def split_outcome(outcome:, amount:)
1271
+ nonce = timestamp_ms
1272
+ action = {
1273
+ type: 'userOutcome',
1274
+ splitOutcome: { outcome: outcome, amount: amount.to_s }
1275
+ }
1276
+ signature = @signer.sign_l1_action(
1277
+ action, nonce,
1278
+ expires_after: @expires_after
1279
+ )
1280
+ post_action(action, signature, nonce, nil)
1281
+ end
1282
+
1283
+ # HIP-4: merge `amount` Yes and `amount` No shares of an outcome back into
1284
+ # `amount` quote tokens (`userOutcome` L1 action, mergeOutcome variant).
1285
+ # Pass `amount: nil` to merge the maximum available.
1286
+ # @param outcome [Integer] Outcome identifier
1287
+ # @param amount [String, Numeric, nil] Amount of shares to merge; nil = maximum available
1288
+ # @return [Hash] Exchange response
1289
+ def merge_outcome(outcome:, amount: nil)
1290
+ nonce = timestamp_ms
1291
+ action = {
1292
+ type: 'userOutcome',
1293
+ mergeOutcome: { outcome: outcome, amount: amount&.to_s }
1294
+ }
1295
+ signature = @signer.sign_l1_action(
1296
+ action, nonce,
1297
+ expires_after: @expires_after
1298
+ )
1299
+ post_action(action, signature, nonce, nil)
1300
+ end
1301
+
1302
+ # HIP-4: merge `amount` Yes shares from every outcome of a question into
1303
+ # `amount` quote tokens (`userOutcome` L1 action, mergeQuestion variant).
1304
+ # Pass `amount: nil` to merge the maximum available.
1305
+ # @param question [Integer] Question identifier
1306
+ # @param amount [String, Numeric, nil] Amount of shares to merge; nil = maximum available
1307
+ # @return [Hash] Exchange response
1308
+ def merge_question(question:, amount: nil)
1309
+ nonce = timestamp_ms
1310
+ action = {
1311
+ type: 'userOutcome',
1312
+ mergeQuestion: { question: question, amount: amount&.to_s }
1313
+ }
1314
+ signature = @signer.sign_l1_action(
1315
+ action, nonce,
1316
+ expires_after: @expires_after
1317
+ )
1318
+ post_action(action, signature, nonce, nil)
1319
+ end
1320
+
1321
+ # HIP-4: convert `amount` No shares from one outcome of a question into
1322
+ # `amount` Yes shares of every other outcome associated with that question
1323
+ # (`userOutcome` L1 action, negateOutcome variant).
1324
+ # @param question [Integer] Question identifier
1325
+ # @param outcome [Integer] Outcome identifier whose No shares are being negated
1326
+ # @param amount [String, Numeric] Amount of No shares to negate (UnsignedDecimal, coerced via to_s)
1327
+ # @return [Hash] Exchange response
1328
+ def negate_outcome(question:, outcome:, amount:)
1329
+ nonce = timestamp_ms
1330
+ action = {
1331
+ type: 'userOutcome',
1332
+ negateOutcome: { question: question, outcome: outcome, amount: amount.to_s }
1333
+ }
1334
+ signature = @signer.sign_l1_action(
1335
+ action, nonce,
1336
+ expires_after: @expires_after
1337
+ )
1338
+ post_action(action, signature, nonce, nil)
1339
+ end
1340
+
1341
+ # Finalize the link between a HyperCore spot token and an ERC-20 contract on
1342
+ # HyperEVM (`finalizeEvmContract` L1 action). `input` selects the verification method
1343
+ # and is passed through verbatim — accepts a Hash `{ create: { nonce: <int> } }` for an
1344
+ # EOA-deployed contract, or one of the strings `"firstStorageSlot"` / `"customStorageSlot"`
1345
+ # for contracts that store the finalizer address in a known storage slot.
1346
+ # @param token [Integer] HyperCore spot token identifier to link
1347
+ # @param input [Hash, String] Verification method (see above)
1348
+ # @return [Hash] Exchange response
1349
+ def finalize_evm_contract(token:, input:)
1350
+ nonce = timestamp_ms
1351
+ action = {
1352
+ type: 'finalizeEvmContract',
1353
+ token: token,
1354
+ input: input
1355
+ }
1356
+ signature = @signer.sign_l1_action(
1357
+ action, nonce,
1358
+ expires_after: @expires_after
1359
+ )
1360
+ post_action(action, signature, nonce, nil)
1361
+ end
1362
+
1240
1363
  # Opt in or out of spot dusting (`spotUser` L1 action).
1241
1364
  # Spot dusting is the protocol's automatic conversion of small spot balances.
1242
1365
  # Despite the generic action name, this method exclusively toggles that opt-out flag.
@@ -1252,6 +1375,20 @@ module Hyperliquid
1252
1375
  post_action(action, signature, nonce, nil)
1253
1376
  end
1254
1377
 
1378
+ # Authorize an AQAv2 role (`authorizeAqav2Role` L1 action).
1379
+ # @param token [Integer] Token identifier
1380
+ # @param role [String] Role to authorize ("technical" or "treasury")
1381
+ # @return [Hash] Exchange response
1382
+ def authorize_aqav2_role(token:, role:)
1383
+ nonce = timestamp_ms
1384
+ action = { type: 'authorizeAqav2Role', token: token.to_i, role: role }
1385
+ signature = @signer.sign_l1_action(
1386
+ action, nonce,
1387
+ expires_after: @expires_after
1388
+ )
1389
+ post_action(action, signature, nonce, nil)
1390
+ end
1391
+
1255
1392
  # Clear the asset metadata cache
1256
1393
  # Call this if metadata has been updated
1257
1394
  def reload_metadata!
@@ -515,6 +515,13 @@ module Hyperliquid
515
515
  @client.post(Constants::INFO_ENDPOINT, { type: 'outcomeMeta' })
516
516
  end
517
517
 
518
+ # Retrieve information about a settled outcome
519
+ # @param outcome [Integer] Outcome identifier
520
+ # @return [Hash, nil] Hash with spec, settleFraction, and details; or nil if not settled
521
+ def settled_outcome(outcome:)
522
+ @client.post(Constants::INFO_ENDPOINT, { type: 'settledOutcome', outcome: outcome.to_i })
523
+ end
524
+
518
525
  # Retrieve a user's funding history
519
526
  # @param user [String]
520
527
  # @param start_time [Integer]
@@ -130,6 +130,14 @@ module Hyperliquid
130
130
  ]
131
131
  }.freeze
132
132
 
133
+ STAKING_LINK_DISABLE_TRADING_USER_TYPES = {
134
+ 'HyperliquidTransaction:StakingLinkDisableTradingUser': [
135
+ { name: :hyperliquidChain, type: 'string' },
136
+ { name: :tradingUser, type: 'address' },
137
+ { name: :nonce, type: 'uint64' }
138
+ ]
139
+ }.freeze
140
+
133
141
  MULTI_SIG_TYPES = {
134
142
  'HyperliquidTransaction:SendMultiSig': [
135
143
  { name: :hyperliquidChain, type: 'string' },
@@ -17,6 +17,16 @@ module Hyperliquid
17
17
  module MultiSig
18
18
  OUTER_PRIMARY_TYPE = 'HyperliquidTransaction:SendMultiSig'
19
19
 
20
+ # Wire-format normalization for userSetAbstraction inside multi_sig envelopes.
21
+ # Each co-signer's EIP-712 hash uses the human-readable abstraction string, but the
22
+ # L1 payload requires the single-char wire enum. Mirrors Python SDK 0.24.0's
23
+ # `_multi_sig_payload_action`.
24
+ USER_SET_ABSTRACTION_WIRE_VALUES = {
25
+ 'disabled' => 'i',
26
+ 'unifiedAccount' => 'u',
27
+ 'portfolioMargin' => 'p'
28
+ }.freeze
29
+
20
30
  # Build the outer multi-sig envelope (the action body posted to /exchange).
21
31
  # @param inner_action [Hash] The wrapped action (any L1 or user-signed action body)
22
32
  # @param multi_sig_user [String] Address of the multi-sig user (lowercased)
@@ -31,11 +41,26 @@ module Hyperliquid
31
41
  payload: {
32
42
  multiSigUser: multi_sig_user.downcase,
33
43
  outerSigner: outer_signer.downcase,
34
- action: inner_action
44
+ action: payload_action(inner_action)
35
45
  }
36
46
  }
37
47
  end
38
48
 
49
+ # Normalize an inner action for the L1 payload. Currently only userSetAbstraction
50
+ # needs translation (long-form abstraction string → wire enum); all other actions
51
+ # pass through verbatim.
52
+ # @param inner_action [Hash] Inner action (symbol or string keys)
53
+ # @return [Hash] Possibly-normalized copy (or the original if no change needed)
54
+ def self.payload_action(inner_action)
55
+ return inner_action unless (inner_action[:type] || inner_action['type']) == 'userSetAbstraction'
56
+
57
+ key = inner_action.key?(:abstraction) ? :abstraction : 'abstraction'
58
+ abstraction = inner_action[key]
59
+ return inner_action unless USER_SET_ABSTRACTION_WIRE_VALUES.key?(abstraction)
60
+
61
+ inner_action.merge(key => USER_SET_ABSTRACTION_WIRE_VALUES[abstraction])
62
+ end
63
+
39
64
  # Compute the multiSigActionHash that the submitter signs over.
40
65
  # Mirrors Python's `sign_multi_sig_action`: action_hash(envelope - type, vault, nonce, expires).
41
66
  # @param envelope [Hash] The multi-sig envelope (will have :type stripped before hashing)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hyperliquid
4
- VERSION = '1.6.0'
4
+ VERSION = '1.7.0'
5
5
  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: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - carter2099