hyperliquid 1.9.2 → 2.0.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +26 -0
  4. data/docs/API.md +374 -152
  5. data/docs/CONFIGURATION.md +25 -11
  6. data/docs/DEVELOPMENT.md +93 -15
  7. data/docs/ERRORS.md +2 -0
  8. data/docs/EXAMPLES.md +253 -2
  9. data/docs/WS.md +78 -20
  10. data/lib/hyperliquid/client.rb +19 -10
  11. data/lib/hyperliquid/exchange.rb +844 -22
  12. data/lib/hyperliquid/info.rb +23 -11
  13. data/lib/hyperliquid/signing/signer.rb +18 -1
  14. data/lib/hyperliquid/version.rb +1 -1
  15. data/lib/hyperliquid/ws/client.rb +192 -78
  16. data/lib/hyperliquid.rb +6 -0
  17. metadata +16 -34
  18. data/.rspec +0 -3
  19. data/.rubocop.yml +0 -49
  20. data/.ruby-version +0 -1
  21. data/CLAUDE.md +0 -108
  22. data/CODE_OF_CONDUCT.md +0 -132
  23. data/Rakefile +0 -12
  24. data/example.rb +0 -161
  25. data/scripts/test_01_spot_market_roundtrip.rb +0 -48
  26. data/scripts/test_02_spot_limit_order.rb +0 -48
  27. data/scripts/test_03_perp_market_roundtrip.rb +0 -58
  28. data/scripts/test_04_perp_limit_order.rb +0 -52
  29. data/scripts/test_05_update_leverage.rb +0 -50
  30. data/scripts/test_06_modify_order.rb +0 -67
  31. data/scripts/test_07_market_close.rb +0 -55
  32. data/scripts/test_08_usd_class_transfer.rb +0 -36
  33. data/scripts/test_09_sub_account_lifecycle.rb +0 -51
  34. data/scripts/test_10_vault.rb +0 -68
  35. data/scripts/test_11_builder_fee.rb +0 -81
  36. data/scripts/test_12_staking.rb +0 -70
  37. data/scripts/test_13_ws_l2_book.rb +0 -83
  38. data/scripts/test_14_ws_candle.rb +0 -81
  39. data/scripts/test_15_explorer.rb +0 -71
  40. data/scripts/test_16_send_to_evm_with_data.rb +0 -79
  41. data/scripts/test_17_create_vault.rb +0 -73
  42. data/scripts/test_18_user_portfolio_margin.rb +0 -72
  43. data/scripts/test_19_spot_user.rb +0 -55
  44. data/scripts/test_20_explorer_ws.rb +0 -92
  45. data/scripts/test_all.rb +0 -96
  46. data/scripts/test_automated.rb +0 -82
  47. data/scripts/test_helpers.rb +0 -238
  48. data/sig/hyperliquid.rbs +0 -4
  49. data/test_integration.rb +0 -17
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperliquid
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - carter2099
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bigdecimal
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '3.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '3.1'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: eth
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -87,15 +101,9 @@ executables: []
87
101
  extensions: []
88
102
  extra_rdoc_files: []
89
103
  files:
90
- - ".rspec"
91
- - ".rubocop.yml"
92
- - ".ruby-version"
93
104
  - CHANGELOG.md
94
- - CLAUDE.md
95
- - CODE_OF_CONDUCT.md
96
105
  - LICENSE.txt
97
106
  - README.md
98
- - Rakefile
99
107
  - SECURITY.md
100
108
  - docs/API.md
101
109
  - docs/CONFIGURATION.md
@@ -103,7 +111,6 @@ files:
103
111
  - docs/ERRORS.md
104
112
  - docs/EXAMPLES.md
105
113
  - docs/WS.md
106
- - example.rb
107
114
  - lib/hyperliquid.rb
108
115
  - lib/hyperliquid/client.rb
109
116
  - lib/hyperliquid/cloid.rb
@@ -116,31 +123,6 @@ files:
116
123
  - lib/hyperliquid/signing/signer.rb
117
124
  - lib/hyperliquid/version.rb
118
125
  - lib/hyperliquid/ws/client.rb
119
- - scripts/test_01_spot_market_roundtrip.rb
120
- - scripts/test_02_spot_limit_order.rb
121
- - scripts/test_03_perp_market_roundtrip.rb
122
- - scripts/test_04_perp_limit_order.rb
123
- - scripts/test_05_update_leverage.rb
124
- - scripts/test_06_modify_order.rb
125
- - scripts/test_07_market_close.rb
126
- - scripts/test_08_usd_class_transfer.rb
127
- - scripts/test_09_sub_account_lifecycle.rb
128
- - scripts/test_10_vault.rb
129
- - scripts/test_11_builder_fee.rb
130
- - scripts/test_12_staking.rb
131
- - scripts/test_13_ws_l2_book.rb
132
- - scripts/test_14_ws_candle.rb
133
- - scripts/test_15_explorer.rb
134
- - scripts/test_16_send_to_evm_with_data.rb
135
- - scripts/test_17_create_vault.rb
136
- - scripts/test_18_user_portfolio_margin.rb
137
- - scripts/test_19_spot_user.rb
138
- - scripts/test_20_explorer_ws.rb
139
- - scripts/test_all.rb
140
- - scripts/test_automated.rb
141
- - scripts/test_helpers.rb
142
- - sig/hyperliquid.rbs
143
- - test_integration.rb
144
126
  homepage: https://github.com/carter2099/hyperliquid
145
127
  licenses:
146
128
  - MIT
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,49 +0,0 @@
1
- AllCops:
2
- NewCops: enable
3
- TargetRubyVersion: 3.3
4
- SuggestExtensions: false
5
- Exclude:
6
- - 'test_*.rb' # Exclude ad-hoc integration test scripts
7
- - 'scripts/**/*' # Exclude integration test scripts
8
- - 'local/**/*' # Exclude local test scripts
9
- - 'vendor/**/*' # Exclude vendored gems (CI bundles here)
10
-
11
- # Allow longer methods for complex logic
12
- Metrics/MethodLength:
13
- Max: 50
14
-
15
- # Allow higher complexity for response handling
16
- Metrics/AbcSize:
17
- Max: 25
18
-
19
- # Disable class length checks so rubocop doesn't complain that we implement all of Hyperliquid's endpoints
20
- Metrics/ClassLength:
21
- Enabled: false
22
-
23
- # Allow longer blocks in specs and gemspec - this is normal for tests and gem configs
24
- Metrics/BlockLength:
25
- Exclude:
26
- - 'spec/**/*'
27
- - '*.gemspec'
28
-
29
- # Exchange API methods (and multi-sig co-signer helpers that pass through to them) require many parameters
30
- Metrics/ParameterLists:
31
- Exclude:
32
- - 'lib/hyperliquid/exchange.rb'
33
- - 'lib/hyperliquid/signing/multi_sig.rb'
34
-
35
- # Allow higher complexity for order type conversion logic and WS message handling
36
- Metrics/CyclomaticComplexity:
37
- Exclude:
38
- - 'lib/hyperliquid/exchange.rb'
39
- - 'lib/hyperliquid/ws/client.rb'
40
-
41
- Metrics/PerceivedComplexity:
42
- Exclude:
43
- - 'lib/hyperliquid/exchange.rb'
44
- - 'lib/hyperliquid/ws/client.rb'
45
-
46
- # Empty blocks are intentional in specs (no-op callbacks for subscription tests)
47
- Lint/EmptyBlock:
48
- Exclude:
49
- - 'spec/**/*'
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.4.10
data/CLAUDE.md DELETED
@@ -1,108 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to AI coding agents working with this repository. It is the canonical source of truth — keep it in sync as the SDK evolves.
4
-
5
- ## Overview
6
-
7
- Ruby SDK for the Hyperliquid decentralized exchange API. Three API surfaces: **Info** (read-only market data), **Exchange** (authenticated trading), and **WebSocket** (real-time streaming). Built on Faraday for HTTP, the `eth` gem for EIP-712 signing, `msgpack` for action serialization, and `ws_lite` for WebSocket connections.
8
-
9
- Version is the single source of truth in `lib/hyperliquid/version.rb`; required Ruby version is in the gemspec.
10
-
11
- ## Commands
12
-
13
- ```bash
14
- bin/setup # install dependencies
15
- rake # run tests + linting (CI default)
16
- rake spec # tests only
17
- rake rubocop # linting only
18
- bundle exec rspec spec/hyperliquid/cloid_spec.rb # single file
19
- bundle exec rspec spec/hyperliquid/cloid_spec.rb:62 # single test by line
20
- bin/console # IRB with SDK loaded
21
- ruby example.rb # example usage script
22
- ```
23
-
24
- ### Integration Tests (Testnet)
25
-
26
- Integration scripts live in `scripts/` as standalone files (`test_NN_<name>.rb`). They require a real testnet private key and hit the live testnet API.
27
-
28
- ```bash
29
- HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_all.rb # all 20
30
- HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_automated.rb # CI-friendly subset (14)
31
- HYPERLIQUID_PRIVATE_KEY=0x... ruby scripts/test_08_usd_class_transfer.rb # single
32
- ```
33
-
34
- `test_automated.rb` is the unattended runner — same as `test_all.rb` but excludes scripts that require manual testnet preconditions (e.g. `test_09_sub_account_lifecycle` needs $100k traded volume; `test_12_staking` needs HYPE balance). Some included tests (e.g. `test_08`, `test_11`) are also coded to skip-with-warning when known testnet preconditions aren't met, so the suite stays green on a stable wallet.
35
-
36
- `test_integration.rb` at the project root is a thin convenience wrapper.
37
-
38
- ## Architecture
39
-
40
- ### Request Flow
41
-
42
- All three API surfaces are reached through `Hyperliquid::SDK` (`lib/hyperliquid.rb`):
43
-
44
- ```
45
- Hyperliquid.new(...)
46
- ├── sdk.info → Info → Client → POST /info (always available)
47
- ├── sdk.exchange → Exchange → Client → POST /exchange (requires private_key)
48
- └── sdk.ws → WS::Client → WSS /ws (real-time streaming)
49
- ```
50
-
51
- - **Info path**: method builds `{ type: 'someType', ... }` body → `Client` POSTs to `/info` → parsed JSON returned.
52
- - **Exchange path**: method builds action payload → `Signer` generates EIP-712 signature over msgpack-encoded action → `Client` POSTs signed payload to `/exchange` → parsed JSON returned.
53
- - **Explorer RPC path** (`tx_details`, `user_details`): a separate base URL (`rpc.hyperliquid.xyz` / `rpc.hyperliquid-testnet.xyz`) with endpoint `/explorer`. `Client` holds a second Faraday connection for this, built lazily on first use; methods opt in via `client.post(EXPLORER_ENDPOINT, body, target: :explorer)`. The SDK wires this up automatically based on `testnet:`. Calling `target: :explorer` on a `Client` constructed without `explorer_base_url:` raises `ConfigurationError`. Don't add a public connection accessor — `target:` is the contract.
54
- - **WebSocket path**: `WS::Client` manages two independent WebSocket connections:
55
- - **Main API WS** (`wss://api.hyperliquid.xyz/ws`): subscribes to market data channels (`l2Book`, `trades`, `candle`, etc.). Messages arrive as `{channel, data}` envelopes; `compute_identifier` extracts routing keys (e.g. `l2Book:eth`, `candle:btc:1h`). Callbacks are dispatched via a bounded queue (1024, drops on overflow) on a dedicated thread.
56
- - **Explorer WS** (`wss://rpc.hyperliquid.xyz/ws`): subscribes to block/transaction streams (`explorerBlock`, `explorerTxs`). Messages arrive as **bare arrays** (no envelope), so `identify_explorer_array` duck-types by field presence (`blockTime`/`height` for blocks, `action`/`hash` for txs). Uses a separate queue, dispatch thread, and subscription ID namespace to avoid cross-contamination with main-API WS. Both connections share the same 50s ping keepalive, automatic reconnection (exp backoff, 30s cap), and lifecycle hooks (`on(:open)`, `on(:close)`, `on(:error)`).
57
-
58
- ### Signing (Python SDK Parity)
59
-
60
- The signing chain in `lib/hyperliquid/signing/` must exactly match the official Python SDK:
61
-
62
- 1. **Action hash**: `keccak256(msgpack(action) + nonce(8B big-endian) + vault_flag + [vault_addr] + [expires_flag + expires_after])`
63
- 2. **Phantom agent**: `{ source: 'a'|'b', connectionId: action_hash }` (`a`=mainnet, `b`=testnet)
64
- 3. **EIP-712 signature** over phantom agent with Exchange domain (chain ID 1337)
65
-
66
- Any change to signing must maintain parity with the Python SDK or transactions will be rejected by the exchange.
67
-
68
- 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.
69
-
70
- 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.
71
-
72
- ### Numeric Conversion
73
-
74
- - **`float_to_wire`** (in Exchange): converts to string with 8-decimal precision, validates rounding tolerance (`1e-12`), normalizes trailing zeros. No scientific notation.
75
- - **Market order pricing** (`_slippage_price`): apply slippage (default 5%) to mid price → round to 5 significant figures → round to `(6 for perp, 8 for spot) - szDecimals` decimal places.
76
- - **Spot vs perp**: assets with index `>= 10_000` are spot (`SPOT_ASSET_THRESHOLD` in Exchange). This affects decimal place calculations.
77
-
78
- ### HIP-3 (Builder-Deployed Perps)
79
-
80
- Many Info methods accept a `dex:` kwarg (e.g. `meta(dex: 'foo')`, `user_state(user, dex: 'foo')`) to query a builder-deployed perp dex rather than the canonical perp market. `Info#perp_dexs` enumerates available dexes; `Info#perp_dex_limits(dex)` returns per-dex risk parameters.
81
-
82
- ### Testing
83
-
84
- - **Unit tests** (`spec/`): RSpec + WebMock. WebMock resets between tests. Monkey-patching disabled. Test files mirror `lib/` structure. No live HTTP calls in unit tests. The WS client spec (`spec/hyperliquid/ws/client_spec.rb`) includes comprehensive isolation tests verifying that explorer WS messages never route to main-API callbacks and vice versa — this is critical because the two transports share the same `WS::Client` class.
85
- - **Integration tests** (`scripts/`): run against testnet with a real private key. Each script is self-contained. Helpers (separators, status dumping, retry-on-oracle-bounce) live in `scripts/test_helpers.rb`. `test_20_explorer_ws.rb` subscribes to `explorerBlock` on testnet and collects 3 block events (60s timeout) to verify the explorer WS transport works end-to-end.
86
- - **`dump_status` / `check_result` helpers** in `test_helpers.rb` must guard against `result['response']` *itself* being a String for transfer-style actions (`usdClassTransfer`, `approveBuilderFee`) — not just `result['response']['data']`. This was a real bug fixed in 1.1.0; preserve the guards if refactoring those helpers.
87
-
88
- ### Code Style
89
-
90
- RuboCop targets Ruby 3.3. Key relaxations: methods up to 50 lines, no class length limit (Info/Exchange are large by design), no block length limit in specs, no parameter list limit in Exchange, empty blocks allowed in specs (intentional no-op callbacks). `scripts/`, `test_*.rb`, `local/`, and `vendor/` are excluded from linting. The WS client's `initialize` method was refactored to extract `init_main_ws_state` and `init_explorer_ws_state` helpers to reduce ABC size (33 assignments across two transports).
91
-
92
- Predicate methods follow Ruby style (`vip?`, `connected?`, `testnet?`) — not `is_vip` / `is_connected`. RuboCop's `Naming/PredicateName` enforces this.
93
-
94
- ### CI
95
-
96
- GitHub Actions (`.github/workflows/main.yml`): runs `bundle exec rake` (tests + lint) on the Ruby matrix defined in that workflow, for pushes to `main` and on all PRs. The release workflow creates GitHub releases from `CHANGELOG.md` on version tags. Dependabot checks Bundler and GitHub Actions dependencies weekly with a 14-day default cooldown; Bundler major updates use a 30-day cooldown.
97
-
98
- ### rbsecp256k1 git source
99
-
100
- The `Gemfile` pins `rbsecp256k1` to Carter's fork (`carter2099/rbsecp256k1`, full-SHA `ref:`, version 6.1.0) because rubygems only has 6.0.0, which requires `rubyzip ~> 2.3` (GHSA-47m2-wp7j-p9vc); the fork requires `rubyzip >= 3.4, < 4` and builds libsecp256k1 0.8.0. This affects only the dev/CI lockfile — a gemspec cannot declare git sources, so consumers of the published gem still resolve rubygems rbsecp256k1 6.0.0 via `eth ~> 0.5`. Dependabot is not expected to bump a SHA-pinned git ref; a Dependabot PR touching rbsecp256k1's source/ref or moving rubyzip below 3.4 must not be applied without Carter. Never `bundle update` it or drop the declaration; moving the ref is a deliberate, reviewed change (re-run the signature-parity specs in `spec/hyperliquid/signing/`). Remove the git source once an upstream rbsecp256k1 release on rubygems allows rubyzip 3.
101
-
102
- ## Release Flow
103
-
104
- Releases happen from `main`. Day-to-day work lands on `dev`, then `dev` is merged into `main` and the version commit is pushed. `CHANGELOG.md` follows Keep-a-Changelog conventions; `lib/hyperliquid/version.rb` is the single source of version truth (gemspec reads it). Releases are atomic: only after the `Ruby` workflow is green on main and the gem is built is the RubyGems OTP requested; `gem push` goes first and the `vX.Y.Z` tag is pushed only after it succeeds. The tag push triggers the GitHub release workflow, so a failed gem push leaves no tag and no GitHub Release.
105
-
106
- ## Additional Docs
107
-
108
- Detailed API reference, examples, WebSocket guide, configuration, and error handling in `docs/` (`API.md`, `EXAMPLES.md`, `WS.md`, `CONFIGURATION.md`, `ERRORS.md`, `DEVELOPMENT.md`).
data/CODE_OF_CONDUCT.md DELETED
@@ -1,132 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- We as members, contributors, and leaders pledge to make participation in our
6
- community a harassment-free experience for everyone, regardless of age, body
7
- size, visible or invisible disability, ethnicity, sex characteristics, gender
8
- identity and expression, level of experience, education, socio-economic status,
9
- nationality, personal appearance, race, caste, color, religion, or sexual
10
- identity and orientation.
11
-
12
- We pledge to act and interact in ways that contribute to an open, welcoming,
13
- diverse, inclusive, and healthy community.
14
-
15
- ## Our Standards
16
-
17
- Examples of behavior that contributes to a positive environment for our
18
- community include:
19
-
20
- * Demonstrating empathy and kindness toward other people
21
- * Being respectful of differing opinions, viewpoints, and experiences
22
- * Giving and gracefully accepting constructive feedback
23
- * Accepting responsibility and apologizing to those affected by our mistakes,
24
- and learning from the experience
25
- * Focusing on what is best not just for us as individuals, but for the overall
26
- community
27
-
28
- Examples of unacceptable behavior include:
29
-
30
- * The use of sexualized language or imagery, and sexual attention or advances of
31
- any kind
32
- * Trolling, insulting or derogatory comments, and personal or political attacks
33
- * Public or private harassment
34
- * Publishing others' private information, such as a physical or email address,
35
- without their explicit permission
36
- * Other conduct which could reasonably be considered inappropriate in a
37
- professional setting
38
-
39
- ## Enforcement Responsibilities
40
-
41
- Community leaders are responsible for clarifying and enforcing our standards of
42
- acceptable behavior and will take appropriate and fair corrective action in
43
- response to any behavior that they deem inappropriate, threatening, offensive,
44
- or harmful.
45
-
46
- Community leaders have the right and responsibility to remove, edit, or reject
47
- comments, commits, code, wiki edits, issues, and other contributions that are
48
- not aligned to this Code of Conduct, and will communicate reasons for moderation
49
- decisions when appropriate.
50
-
51
- ## Scope
52
-
53
- This Code of Conduct applies within all community spaces, and also applies when
54
- an individual is officially representing the community in public spaces.
55
- Examples of representing our community include using an official email address,
56
- posting via an official social media account, or acting as an appointed
57
- representative at an online or offline event.
58
-
59
- ## Enforcement
60
-
61
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
- reported to the community leaders responsible for enforcement at
63
- [INSERT CONTACT METHOD].
64
- All complaints will be reviewed and investigated promptly and fairly.
65
-
66
- All community leaders are obligated to respect the privacy and security of the
67
- reporter of any incident.
68
-
69
- ## Enforcement Guidelines
70
-
71
- Community leaders will follow these Community Impact Guidelines in determining
72
- the consequences for any action they deem in violation of this Code of Conduct:
73
-
74
- ### 1. Correction
75
-
76
- **Community Impact**: Use of inappropriate language or other behavior deemed
77
- unprofessional or unwelcome in the community.
78
-
79
- **Consequence**: A private, written warning from community leaders, providing
80
- clarity around the nature of the violation and an explanation of why the
81
- behavior was inappropriate. A public apology may be requested.
82
-
83
- ### 2. Warning
84
-
85
- **Community Impact**: A violation through a single incident or series of
86
- actions.
87
-
88
- **Consequence**: A warning with consequences for continued behavior. No
89
- interaction with the people involved, including unsolicited interaction with
90
- those enforcing the Code of Conduct, for a specified period of time. This
91
- includes avoiding interactions in community spaces as well as external channels
92
- like social media. Violating these terms may lead to a temporary or permanent
93
- ban.
94
-
95
- ### 3. Temporary Ban
96
-
97
- **Community Impact**: A serious violation of community standards, including
98
- sustained inappropriate behavior.
99
-
100
- **Consequence**: A temporary ban from any sort of interaction or public
101
- communication with the community for a specified period of time. No public or
102
- private interaction with the people involved, including unsolicited interaction
103
- with those enforcing the Code of Conduct, is allowed during this period.
104
- Violating these terms may lead to a permanent ban.
105
-
106
- ### 4. Permanent Ban
107
-
108
- **Community Impact**: Demonstrating a pattern of violation of community
109
- standards, including sustained inappropriate behavior, harassment of an
110
- individual, or aggression toward or disparagement of classes of individuals.
111
-
112
- **Consequence**: A permanent ban from any sort of public interaction within the
113
- community.
114
-
115
- ## Attribution
116
-
117
- This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
- version 2.1, available at
119
- [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
-
121
- Community Impact Guidelines were inspired by
122
- [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
-
124
- For answers to common questions about this code of conduct, see the FAQ at
125
- [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
- [https://www.contributor-covenant.org/translations][translations].
127
-
128
- [homepage]: https://www.contributor-covenant.org
129
- [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
- [Mozilla CoC]: https://github.com/mozilla/diversity
131
- [FAQ]: https://www.contributor-covenant.org/faq
132
- [translations]: https://www.contributor-covenant.org/translations
data/Rakefile DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- require 'rubocop/rake_task'
9
-
10
- RuboCop::RakeTask.new
11
-
12
- task default: %i[spec rubocop]
data/example.rb DELETED
@@ -1,161 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative 'lib/hyperliquid'
5
-
6
- # Example usage of the Hyperliquid Ruby SDK
7
-
8
- puts 'Hyperliquid Ruby SDK v0.4.0 - API Examples'
9
- puts '=' * 50
10
-
11
- # =============================================================================
12
- # INFO API (Read-only, no authentication required)
13
- # =============================================================================
14
-
15
- # Create a new SDK instance (defaults to mainnet)
16
- sdk = Hyperliquid.new
17
-
18
- puts "\n--- INFO API EXAMPLES ---\n"
19
-
20
- # Example 1: Get all market mid prices
21
- begin
22
- puts '1. Getting all market mid prices...'
23
- mids = sdk.info.all_mids
24
- puts " Found #{mids.length} markets" if mids.is_a?(Hash)
25
- puts " BTC mid: #{mids['BTC']}" if mids['BTC']
26
- rescue Hyperliquid::Error => e
27
- puts " Error: #{e.message}"
28
- end
29
-
30
- # Example 2: Get metadata for all perpetual assets
31
- begin
32
- puts "\n2. Getting perpetual asset metadata..."
33
- meta = sdk.info.meta
34
- universe = meta['universe'] || []
35
- puts " Found #{universe.length} perpetual assets"
36
- puts " First asset: #{universe.first['name']}" if universe.any?
37
- rescue Hyperliquid::Error => e
38
- puts " Error: #{e.message}"
39
- end
40
-
41
- # Example 3: Get L2 order book
42
- begin
43
- puts "\n3. Getting L2 order book for BTC..."
44
- book = sdk.info.l2_book('BTC')
45
- levels = book['levels'] || []
46
- puts " Bid levels: #{levels[0]&.length || 0}, Ask levels: #{levels[1]&.length || 0}"
47
- rescue Hyperliquid::Error => e
48
- puts " Error: #{e.message}"
49
- end
50
-
51
- # Example 4: Get spot metadata
52
- begin
53
- puts "\n4. Getting spot asset metadata..."
54
- spot_meta = sdk.info.spot_meta
55
- tokens = spot_meta['tokens'] || []
56
- puts " Found #{tokens.length} spot tokens"
57
- rescue Hyperliquid::Error => e
58
- puts " Error: #{e.message}"
59
- end
60
-
61
- # Example 5: Use testnet
62
- puts "\n5. Creating testnet SDK..."
63
- testnet_sdk = Hyperliquid.new(testnet: true)
64
- puts " Testnet base URL: #{testnet_sdk.base_url}"
65
-
66
- # Example 6: User-specific endpoints (requires valid wallet address)
67
- wallet_address = "0x#{'0' * 40}" # Placeholder address
68
-
69
- begin
70
- puts "\n6. Getting user state for #{wallet_address[0..13]}..."
71
- state = sdk.info.user_state(wallet_address)
72
- puts " Account value: #{state.dig('marginSummary', 'accountValue') || 'N/A'}"
73
- rescue Hyperliquid::Error => e
74
- puts " Error: #{e.message}"
75
- end
76
-
77
- # =============================================================================
78
- # EXCHANGE API (Authenticated, requires private key)
79
- # =============================================================================
80
-
81
- puts "\n--- EXCHANGE API EXAMPLES ---\n"
82
- puts "(These examples are commented out to prevent accidental execution)\n"
83
-
84
- # To use the Exchange API, create an SDK with your private key:
85
- #
86
- # sdk = Hyperliquid.new(
87
- # testnet: true, # Use testnet for testing!
88
- # private_key: ENV['HYPERLIQUID_PRIVATE_KEY']
89
- # )
90
- #
91
- # Your wallet address:
92
- # puts sdk.exchange.address
93
- #
94
- # Place a limit order:
95
- # result = sdk.exchange.order(
96
- # coin: 'BTC',
97
- # is_buy: true,
98
- # size: 0.001,
99
- # limit_px: 50000.0,
100
- # order_type: { limit: { tif: 'Gtc' } },
101
- # reduce_only: false
102
- # )
103
- #
104
- # Place a market order (uses slippage):
105
- # result = sdk.exchange.market_order(
106
- # coin: 'BTC',
107
- # is_buy: true,
108
- # size: 0.001,
109
- # slippage: 0.01 # 1% slippage
110
- # )
111
- #
112
- # Place a stop loss order:
113
- # result = sdk.exchange.order(
114
- # coin: 'BTC',
115
- # is_buy: false,
116
- # size: 0.001,
117
- # limit_px: 48000.0,
118
- # order_type: {
119
- # trigger: {
120
- # trigger_px: 49000.0,
121
- # is_market: false,
122
- # tpsl: 'sl'
123
- # }
124
- # },
125
- # reduce_only: true
126
- # )
127
- #
128
- # Cancel an order by OID:
129
- # result = sdk.exchange.cancel(coin: 'BTC', oid: 123456789)
130
- #
131
- # Cancel an order by client order ID:
132
- # result = sdk.exchange.cancel_by_cloid(coin: 'BTC', cloid: '0x...')
133
- #
134
- # Bulk cancel multiple orders:
135
- # result = sdk.exchange.bulk_cancel([
136
- # { coin: 'BTC', oid: 123 },
137
- # { coin: 'ETH', oid: 456 }
138
- # ])
139
- #
140
- # Use client order IDs for tracking:
141
- # cloid = Hyperliquid::Cloid.random
142
- # result = sdk.exchange.order(
143
- # coin: 'BTC',
144
- # is_buy: true,
145
- # size: 0.001,
146
- # limit_px: 50000.0,
147
- # cloid: cloid
148
- # )
149
- # puts "Order placed with cloid: #{cloid}"
150
- #
151
- # Trade on behalf of a vault:
152
- # result = sdk.exchange.order(
153
- # coin: 'BTC',
154
- # is_buy: true,
155
- # size: 0.001,
156
- # limit_px: 50000.0,
157
- # vault_address: '0x...'
158
- # )
159
-
160
- puts 'See commented code above for Exchange API usage patterns.'
161
- puts "\nSDK examples completed!"
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Test 1: Spot Market Roundtrip (PURR/USDC)
5
- # Buy and sell PURR at market price.
6
-
7
- require_relative 'test_helpers'
8
-
9
- sdk = build_sdk
10
- separator('TEST 1: Spot Market Roundtrip (PURR/USDC)')
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
- puts "#{spot_coin} mid: $#{spot_price}"
20
- puts "Size: #{spot_size} PURR (~$#{(spot_size * spot_price).round(2)})"
21
- puts "Slippage: #{(SPOT_SLIPPAGE * 100).to_i}%"
22
- puts
23
-
24
- puts 'Placing market BUY...'
25
- result = sdk.exchange.market_order(
26
- coin: spot_coin,
27
- is_buy: true,
28
- size: spot_size,
29
- slippage: SPOT_SLIPPAGE
30
- )
31
- check_result(result, 'Buy')
32
-
33
- wait_with_countdown(WAIT_SECONDS, 'Waiting before sell...')
34
-
35
- puts 'Placing market SELL...'
36
- result = sdk.exchange.market_order(
37
- coin: spot_coin,
38
- is_buy: false,
39
- size: spot_size,
40
- slippage: SPOT_SLIPPAGE
41
- )
42
- check_result(result, 'Sell')
43
- else
44
- puts red("SKIPPED: Could not get #{spot_coin} price")
45
- end
46
-
47
- test_passed('Test 1 Spot Market Roundtrip')
48
-
@@ -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
-