wayfinder-paths 0.1.19__py3-none-any.whl → 0.1.21__py3-none-any.whl

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.

Potentially problematic release.


This version of wayfinder-paths might be problematic. Click here for more details.

Files changed (98) hide show
  1. wayfinder_paths/__init__.py +0 -2
  2. wayfinder_paths/adapters/balance_adapter/README.md +59 -45
  3. wayfinder_paths/adapters/balance_adapter/adapter.py +1 -22
  4. wayfinder_paths/adapters/balance_adapter/test_adapter.py +0 -14
  5. wayfinder_paths/adapters/brap_adapter/README.md +61 -184
  6. wayfinder_paths/adapters/brap_adapter/__init__.py +0 -4
  7. wayfinder_paths/adapters/brap_adapter/adapter.py +1 -148
  8. wayfinder_paths/adapters/brap_adapter/test_adapter.py +0 -15
  9. wayfinder_paths/adapters/hyperlend_adapter/__init__.py +0 -4
  10. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +1 -10
  11. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +0 -17
  12. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +3 -312
  13. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +1 -71
  14. wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +0 -57
  15. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +0 -17
  16. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +2 -42
  17. wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +1 -9
  18. wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +15 -47
  19. wayfinder_paths/adapters/hyperliquid_adapter/utils.py +0 -7
  20. wayfinder_paths/adapters/ledger_adapter/README.md +54 -74
  21. wayfinder_paths/adapters/ledger_adapter/__init__.py +0 -4
  22. wayfinder_paths/adapters/ledger_adapter/adapter.py +0 -106
  23. wayfinder_paths/adapters/ledger_adapter/test_adapter.py +0 -12
  24. wayfinder_paths/adapters/moonwell_adapter/README.md +67 -106
  25. wayfinder_paths/adapters/moonwell_adapter/__init__.py +0 -4
  26. wayfinder_paths/adapters/moonwell_adapter/adapter.py +10 -122
  27. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +84 -83
  28. wayfinder_paths/adapters/pool_adapter/README.md +30 -51
  29. wayfinder_paths/adapters/pool_adapter/__init__.py +0 -4
  30. wayfinder_paths/adapters/pool_adapter/adapter.py +0 -19
  31. wayfinder_paths/adapters/pool_adapter/test_adapter.py +0 -8
  32. wayfinder_paths/adapters/token_adapter/README.md +41 -49
  33. wayfinder_paths/adapters/token_adapter/adapter.py +0 -32
  34. wayfinder_paths/adapters/token_adapter/test_adapter.py +1 -12
  35. wayfinder_paths/conftest.py +0 -8
  36. wayfinder_paths/core/__init__.py +0 -2
  37. wayfinder_paths/core/adapters/BaseAdapter.py +0 -22
  38. wayfinder_paths/core/adapters/__init__.py +0 -5
  39. wayfinder_paths/core/adapters/models.py +0 -5
  40. wayfinder_paths/core/analytics/__init__.py +0 -2
  41. wayfinder_paths/core/analytics/bootstrap.py +0 -16
  42. wayfinder_paths/core/analytics/stats.py +0 -7
  43. wayfinder_paths/core/analytics/test_analytics.py +5 -34
  44. wayfinder_paths/core/clients/BRAPClient.py +0 -35
  45. wayfinder_paths/core/clients/ClientManager.py +0 -51
  46. wayfinder_paths/core/clients/HyperlendClient.py +0 -77
  47. wayfinder_paths/core/clients/LedgerClient.py +2 -122
  48. wayfinder_paths/core/clients/PoolClient.py +0 -2
  49. wayfinder_paths/core/clients/TokenClient.py +0 -39
  50. wayfinder_paths/core/clients/WalletClient.py +0 -15
  51. wayfinder_paths/core/clients/WayfinderClient.py +0 -24
  52. wayfinder_paths/core/clients/__init__.py +0 -4
  53. wayfinder_paths/core/clients/protocols.py +25 -98
  54. wayfinder_paths/core/config.py +0 -24
  55. wayfinder_paths/core/constants/__init__.py +0 -7
  56. wayfinder_paths/core/constants/base.py +2 -9
  57. wayfinder_paths/core/constants/erc20_abi.py +0 -5
  58. wayfinder_paths/core/constants/hyperlend_abi.py +0 -7
  59. wayfinder_paths/core/constants/moonwell_abi.py +0 -35
  60. wayfinder_paths/core/engine/StrategyJob.py +0 -32
  61. wayfinder_paths/core/strategies/Strategy.py +0 -99
  62. wayfinder_paths/core/strategies/__init__.py +0 -2
  63. wayfinder_paths/core/utils/__init__.py +0 -1
  64. wayfinder_paths/core/utils/evm_helpers.py +0 -50
  65. wayfinder_paths/core/utils/{erc20_service.py → tokens.py} +25 -21
  66. wayfinder_paths/core/utils/transaction.py +0 -1
  67. wayfinder_paths/run_strategy.py +0 -46
  68. wayfinder_paths/scripts/create_strategy.py +0 -17
  69. wayfinder_paths/scripts/make_wallets.py +1 -4
  70. wayfinder_paths/strategies/basis_trading_strategy/README.md +71 -163
  71. wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +0 -24
  72. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +36 -400
  73. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +15 -64
  74. wayfinder_paths/strategies/basis_trading_strategy/types.py +0 -4
  75. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +65 -56
  76. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +4 -27
  77. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +0 -10
  78. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +71 -72
  79. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +23 -227
  80. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +120 -113
  81. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +64 -59
  82. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +4 -44
  83. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +2 -35
  84. wayfinder_paths/templates/adapter/README.md +107 -46
  85. wayfinder_paths/templates/adapter/adapter.py +0 -9
  86. wayfinder_paths/templates/adapter/test_adapter.py +0 -19
  87. wayfinder_paths/templates/strategy/README.md +113 -59
  88. wayfinder_paths/templates/strategy/strategy.py +0 -22
  89. wayfinder_paths/templates/strategy/test_strategy.py +0 -28
  90. wayfinder_paths/tests/test_test_coverage.py +2 -12
  91. wayfinder_paths/tests/test_utils.py +1 -31
  92. wayfinder_paths-0.1.21.dist-info/METADATA +355 -0
  93. wayfinder_paths-0.1.21.dist-info/RECORD +129 -0
  94. {wayfinder_paths-0.1.19.dist-info → wayfinder_paths-0.1.21.dist-info}/WHEEL +1 -1
  95. wayfinder_paths/core/adapters/base.py +0 -5
  96. wayfinder_paths-0.1.19.dist-info/METADATA +0 -592
  97. wayfinder_paths-0.1.19.dist-info/RECORD +0 -130
  98. {wayfinder_paths-0.1.19.dist-info → wayfinder_paths-0.1.21.dist-info}/LICENSE +0 -0
@@ -1,5 +1,3 @@
1
- """HyperliquidAdapter - wraps hyperliquid SDK for market data and order execution."""
2
-
3
1
  from __future__ import annotations
4
2
 
5
3
  import asyncio
@@ -31,8 +29,6 @@ except ImportError:
31
29
 
32
30
 
33
31
  class SimpleCache:
34
- """Simple in-memory cache with TTL for local caching."""
35
-
36
32
  def __init__(self):
37
33
  self._cache: dict[str, Any] = {}
38
34
  self._expiry: dict[str, float] = {}
@@ -56,18 +52,6 @@ class SimpleCache:
56
52
 
57
53
 
58
54
  class HyperliquidAdapter(BaseAdapter):
59
- """
60
- Adapter for Hyperliquid exchange operations.
61
-
62
- Wraps the hyperliquid SDK directly for market data access.
63
- Uses Hyperliquid's public API for:
64
- - Market metadata (perp and spot)
65
- - Funding rate history
66
- - Price candles
67
- - Order book snapshots
68
- - User positions and balances
69
- """
70
-
71
55
  adapter_type = "HYPERLIQUID"
72
56
 
73
57
  def __init__(
@@ -87,7 +71,6 @@ class HyperliquidAdapter(BaseAdapter):
87
71
  self._cache = SimpleCache()
88
72
  self._executor = executor
89
73
 
90
- # Initialize Hyperliquid Info client
91
74
  self.info = Info(constants.MAINNET_API_URL, skip_ws=True)
92
75
 
93
76
  # Cache asset mappings after first fetch
@@ -95,7 +78,6 @@ class HyperliquidAdapter(BaseAdapter):
95
78
  self._coin_to_asset: dict[str, int] | None = None
96
79
 
97
80
  async def connect(self) -> bool:
98
- """Verify connection by fetching market metadata."""
99
81
  try:
100
82
  meta = self.info.meta_and_asset_ctxs()
101
83
  if meta:
@@ -111,11 +93,6 @@ class HyperliquidAdapter(BaseAdapter):
111
93
  # ------------------------------------------------------------------ #
112
94
 
113
95
  async def get_meta_and_asset_ctxs(self) -> tuple[bool, Any]:
114
- """
115
- Get perpetual market metadata and asset contexts.
116
-
117
- Returns combined [meta, assetCtxs] from Hyperliquid API.
118
- """
119
96
  cache_key = "hl_meta_and_asset_ctxs"
120
97
  cached = self._cache.get(cache_key)
121
98
  if cached:
@@ -123,25 +100,19 @@ class HyperliquidAdapter(BaseAdapter):
123
100
 
124
101
  try:
125
102
  data = self.info.meta_and_asset_ctxs()
126
- self._cache.set(cache_key, data, timeout=60) # Cache for 1 minute
103
+ self._cache.set(cache_key, data, timeout=60)
127
104
  return True, data
128
105
  except Exception as exc:
129
106
  self.logger.error(f"Failed to fetch meta_and_asset_ctxs: {exc}")
130
107
  return False, str(exc)
131
108
 
132
109
  async def get_spot_meta(self) -> tuple[bool, Any]:
133
- """
134
- Get spot market metadata.
135
-
136
- Returns spot market information including tokens and pairs.
137
- """
138
110
  cache_key = "hl_spot_meta"
139
111
  cached = self._cache.get(cache_key)
140
112
  if cached:
141
113
  return True, cached
142
114
 
143
115
  try:
144
- # Handle both callable and property access patterns
145
116
  spot_meta = self.info.spot_meta
146
117
  if callable(spot_meta):
147
118
  data = spot_meta()
@@ -154,13 +125,6 @@ class HyperliquidAdapter(BaseAdapter):
154
125
  return False, str(exc)
155
126
 
156
127
  async def get_spot_assets(self) -> tuple[bool, dict[str, int]]:
157
- """
158
- Get mapping of spot pair names to asset IDs.
159
-
160
- Returns:
161
- Dict mapping "BASE/QUOTE" names to spot asset IDs (index + 10000).
162
- Example: {"PURR/USDC": 10000, "HYPE/USDC": 10107, ...}
163
- """
164
128
  cache_key = "hl_spot_assets"
165
129
  cached = self._cache.get(cache_key)
166
130
  if cached:
@@ -182,7 +146,6 @@ class HyperliquidAdapter(BaseAdapter):
182
146
 
183
147
  base_idx, quote_idx = pair_tokens[0], pair_tokens[1]
184
148
 
185
- # Get token names
186
149
  base_info = tokens[base_idx] if base_idx < len(tokens) else {}
187
150
  quote_info = tokens[quote_idx] if quote_idx < len(tokens) else {}
188
151
 
@@ -193,7 +156,7 @@ class HyperliquidAdapter(BaseAdapter):
193
156
  spot_asset_id = pair.get("index", 0) + 10000
194
157
  response[name] = spot_asset_id
195
158
 
196
- self._cache.set(cache_key, response, timeout=300) # Cache for 5 min
159
+ self._cache.set(cache_key, response, timeout=300)
197
160
  return True, response
198
161
 
199
162
  except Exception as exc:
@@ -201,16 +164,6 @@ class HyperliquidAdapter(BaseAdapter):
201
164
  return False, {}
202
165
 
203
166
  def get_spot_asset_id(self, base_coin: str, quote_coin: str = "USDC") -> int | None:
204
- """
205
- Synchronous helper to get spot asset ID from cached data.
206
-
207
- Args:
208
- base_coin: Base token name (e.g., "HYPE", "ETH", "BTC")
209
- quote_coin: Quote token name (default: "USDC")
210
-
211
- Returns:
212
- Spot asset ID or None if not found.
213
- """
214
167
  cache_key = "hl_spot_assets"
215
168
  cached = self._cache.get(cache_key)
216
169
  if cached:
@@ -224,17 +177,6 @@ class HyperliquidAdapter(BaseAdapter):
224
177
  start_time_ms: int,
225
178
  end_time_ms: int | None = None,
226
179
  ) -> tuple[bool, list[dict[str, Any]]]:
227
- """
228
- Get funding rate history for a perpetual.
229
-
230
- Args:
231
- coin: Coin symbol (e.g., "ETH", "BTC")
232
- start_time_ms: Start time in milliseconds
233
- end_time_ms: End time in milliseconds (optional)
234
-
235
- Returns:
236
- List of funding rate records with time and fundingRate fields.
237
- """
238
180
  try:
239
181
  data = self.info.funding_history(coin, start_time_ms, end_time_ms)
240
182
  return True, data
@@ -249,18 +191,6 @@ class HyperliquidAdapter(BaseAdapter):
249
191
  start_time_ms: int,
250
192
  end_time_ms: int | None = None,
251
193
  ) -> tuple[bool, list[dict[str, Any]]]:
252
- """
253
- Get OHLCV candle data.
254
-
255
- Args:
256
- coin: Coin symbol (e.g., "ETH", "BTC")
257
- interval: Candle interval (e.g., "1h", "4h", "1d")
258
- start_time_ms: Start time in milliseconds
259
- end_time_ms: End time in milliseconds (optional)
260
-
261
- Returns:
262
- List of candle records with t, o, h, l, c, v fields.
263
- """
264
194
  try:
265
195
  data = self.info.candles_snapshot(
266
196
  coin, interval, start_time_ms, end_time_ms
@@ -275,16 +205,6 @@ class HyperliquidAdapter(BaseAdapter):
275
205
  coin: str,
276
206
  n_levels: int = 20,
277
207
  ) -> tuple[bool, dict[str, Any]]:
278
- """
279
- Get L2 order book snapshot.
280
-
281
- Args:
282
- coin: Coin symbol (e.g., "ETH", "BTC", or spot pair like "HYPE/USDC")
283
- n_levels: Number of price levels to fetch
284
-
285
- Returns:
286
- Order book with levels containing px, sz, n fields.
287
- """
288
208
  try:
289
209
  data = self.info.l2_snapshot(coin)
290
210
  return True, data
@@ -293,15 +213,6 @@ class HyperliquidAdapter(BaseAdapter):
293
213
  return False, str(exc)
294
214
 
295
215
  async def get_user_state(self, address: str) -> tuple[bool, dict[str, Any]]:
296
- """
297
- Get user's perpetual account state including positions and margin.
298
-
299
- Args:
300
- address: Wallet address
301
-
302
- Returns:
303
- User state with assetPositions, crossMarginSummary, etc.
304
- """
305
216
  try:
306
217
  data = self.info.user_state(address)
307
218
  return True, data
@@ -310,15 +221,6 @@ class HyperliquidAdapter(BaseAdapter):
310
221
  return False, str(exc)
311
222
 
312
223
  async def get_spot_user_state(self, address: str) -> tuple[bool, dict[str, Any]]:
313
- """
314
- Get user's spot account balances.
315
-
316
- Args:
317
- address: Wallet address
318
-
319
- Returns:
320
- Spot balances for the user.
321
- """
322
224
  try:
323
225
  data = self.info.spot_user_state(address)
324
226
  return True, data
@@ -327,15 +229,6 @@ class HyperliquidAdapter(BaseAdapter):
327
229
  return False, str(exc)
328
230
 
329
231
  async def get_margin_table(self, margin_table_id: int) -> tuple[bool, list[dict]]:
330
- """
331
- Get tiered margin table for an asset.
332
-
333
- Args:
334
- margin_table_id: Margin table ID from asset context
335
-
336
- Returns:
337
- List of margin tiers with notional and maintenance rate.
338
- """
339
232
  cache_key = f"hl_margin_table_{margin_table_id}"
340
233
  cached = self._cache.get(cache_key)
341
234
  if cached:
@@ -350,22 +243,13 @@ class HyperliquidAdapter(BaseAdapter):
350
243
  except Exception: # noqa: BLE001 - try alternate payload key
351
244
  body = {"type": "marginTable", "marginTableId": int(margin_table_id)}
352
245
  data = self.info.post("/info", body)
353
- self._cache.set(cache_key, data, timeout=86400) # Cache for 24h
246
+ self._cache.set(cache_key, data, timeout=86400)
354
247
  return True, data
355
248
  except Exception as exc:
356
249
  self.logger.error(f"Failed to fetch margin_table {margin_table_id}: {exc}")
357
250
  return False, str(exc)
358
251
 
359
252
  async def get_spot_l2_book(self, spot_asset_id: int) -> tuple[bool, dict[str, Any]]:
360
- """
361
- Get L2 order book for a spot market by asset ID.
362
-
363
- Args:
364
- spot_asset_id: Spot asset ID (>= 10000)
365
-
366
- Returns:
367
- Order book with levels.
368
- """
369
253
  try:
370
254
  # Spot L2 uses different coin names based on spot index:
371
255
  # - Index 0 (PURR): use "PURR/USDC"
@@ -394,20 +278,17 @@ class HyperliquidAdapter(BaseAdapter):
394
278
 
395
279
  @property
396
280
  def asset_to_sz_decimals(self) -> dict[int, int]:
397
- """Get asset ID to size decimals mapping."""
398
281
  if self._asset_to_sz_decimals is None:
399
282
  self._asset_to_sz_decimals = dict(self.info.asset_to_sz_decimals)
400
283
  return self._asset_to_sz_decimals
401
284
 
402
285
  @property
403
286
  def coin_to_asset(self) -> dict[str, int]:
404
- """Get coin name to asset ID mapping (perps only)."""
405
287
  if self._coin_to_asset is None:
406
288
  self._coin_to_asset = dict(self.info.coin_to_asset)
407
289
  return self._coin_to_asset
408
290
 
409
291
  def get_sz_decimals(self, asset_id: int) -> int:
410
- """Get size decimals for an asset."""
411
292
  try:
412
293
  return self.asset_to_sz_decimals[asset_id]
413
294
  except KeyError:
@@ -416,7 +297,6 @@ class HyperliquidAdapter(BaseAdapter):
416
297
  ) from None
417
298
 
418
299
  def refresh_mappings(self) -> None:
419
- """Force refresh of cached asset mappings."""
420
300
  self._asset_to_sz_decimals = None
421
301
  self._coin_to_asset = None
422
302
  self._cache.clear()
@@ -426,7 +306,6 @@ class HyperliquidAdapter(BaseAdapter):
426
306
  # ------------------------------------------------------------------ #
427
307
 
428
308
  async def get_all_mid_prices(self) -> tuple[bool, dict[str, float]]:
429
- """Get mid prices for all markets."""
430
309
  try:
431
310
  data = self.info.all_mids()
432
311
  return True, {k: float(v) for k, v in data.items()}
@@ -435,7 +314,6 @@ class HyperliquidAdapter(BaseAdapter):
435
314
  return False, str(exc)
436
315
 
437
316
  def get_valid_order_size(self, asset_id: int, size: float) -> float:
438
- """Round size to valid lot size for asset."""
439
317
  decimals = self.get_sz_decimals(asset_id)
440
318
  from decimal import ROUND_DOWN, Decimal
441
319
 
@@ -463,22 +341,6 @@ class HyperliquidAdapter(BaseAdapter):
463
341
  cloid: str | None = None,
464
342
  builder: dict[str, Any] | None = None,
465
343
  ) -> tuple[bool, dict[str, Any]]:
466
- """
467
- Place a market order (IOC with slippage).
468
-
469
- Args:
470
- asset_id: Asset ID (perp < 10000, spot >= 10000)
471
- is_buy: True for buy, False for sell
472
- slippage: Slippage tolerance (0.0 to 1.0)
473
- size: Order size in base units
474
- address: Wallet address
475
- reduce_only: If True, only reduce existing position
476
- cloid: Client order ID (optional)
477
- builder: Optional builder fee config with keys 'b' (address) and 'f' (fee bps)
478
-
479
- Returns:
480
- (success, response_data or error_message)
481
- """
482
344
  if not self._executor:
483
345
  raise NotImplementedError(
484
346
  "No Hyperliquid executor configured. "
@@ -505,17 +367,6 @@ class HyperliquidAdapter(BaseAdapter):
505
367
  order_id: int | str,
506
368
  address: str,
507
369
  ) -> tuple[bool, dict[str, Any]]:
508
- """
509
- Cancel an open order.
510
-
511
- Args:
512
- asset_id: Asset ID
513
- order_id: Order ID to cancel
514
- address: Wallet address
515
-
516
- Returns:
517
- (success, response_data or error_message)
518
- """
519
370
  if not self._executor:
520
371
  raise NotImplementedError(
521
372
  "No Hyperliquid executor configured. "
@@ -538,18 +389,6 @@ class HyperliquidAdapter(BaseAdapter):
538
389
  is_cross: bool,
539
390
  address: str,
540
391
  ) -> tuple[bool, dict[str, Any]]:
541
- """
542
- Update leverage for an asset.
543
-
544
- Args:
545
- asset_id: Asset ID
546
- leverage: Target leverage
547
- is_cross: True for cross margin, False for isolated
548
- address: Wallet address
549
-
550
- Returns:
551
- (success, response_data or error_message)
552
- """
553
392
  if not self._executor:
554
393
  raise NotImplementedError("No Hyperliquid executor configured.")
555
394
 
@@ -568,7 +407,6 @@ class HyperliquidAdapter(BaseAdapter):
568
407
  amount: float,
569
408
  address: str,
570
409
  ) -> tuple[bool, dict[str, Any]]:
571
- """Transfer USDC from spot to perp balance."""
572
410
  if not self._executor:
573
411
  raise NotImplementedError("No Hyperliquid executor configured.")
574
412
 
@@ -585,7 +423,6 @@ class HyperliquidAdapter(BaseAdapter):
585
423
  amount: float,
586
424
  address: str,
587
425
  ) -> tuple[bool, dict[str, Any]]:
588
- """Transfer USDC from perp to spot balance."""
589
426
  if not self._executor:
590
427
  raise NotImplementedError("No Hyperliquid executor configured.")
591
428
 
@@ -605,19 +442,6 @@ class HyperliquidAdapter(BaseAdapter):
605
442
  size: float,
606
443
  address: str,
607
444
  ) -> tuple[bool, dict[str, Any]]:
608
- """
609
- Place a stop-loss order.
610
-
611
- Args:
612
- asset_id: Asset ID
613
- is_buy: True to buy (close short), False to sell (close long)
614
- trigger_price: Price at which to trigger
615
- size: Order size
616
- address: Wallet address
617
-
618
- Returns:
619
- (success, response_data or error_message)
620
- """
621
445
  if not self._executor:
622
446
  raise NotImplementedError("No Hyperliquid executor configured.")
623
447
 
@@ -633,15 +457,6 @@ class HyperliquidAdapter(BaseAdapter):
633
457
  return success, result
634
458
 
635
459
  async def get_user_fills(self, address: str) -> tuple[bool, list[dict[str, Any]]]:
636
- """
637
- Get recent fills for a user.
638
-
639
- Args:
640
- address: Wallet address
641
-
642
- Returns:
643
- List of fill records
644
- """
645
460
  try:
646
461
  data = self.info.user_fills(address)
647
462
  return True, data if isinstance(data, list) else []
@@ -652,16 +467,6 @@ class HyperliquidAdapter(BaseAdapter):
652
467
  async def get_order_status(
653
468
  self, address: str, order_id: int | str
654
469
  ) -> tuple[bool, dict[str, Any]]:
655
- """
656
- Get status of a specific order.
657
-
658
- Args:
659
- address: Wallet address
660
- order_id: Order ID (numeric) or client order ID (string)
661
-
662
- Returns:
663
- Order status data
664
- """
665
470
  try:
666
471
  body = {"type": "orderStatus", "user": address, "oid": order_id}
667
472
  data = self.info.post("/info", body)
@@ -671,15 +476,6 @@ class HyperliquidAdapter(BaseAdapter):
671
476
  return False, str(exc)
672
477
 
673
478
  async def get_open_orders(self, address: str) -> tuple[bool, list[dict[str, Any]]]:
674
- """
675
- Get open orders for a user.
676
-
677
- Args:
678
- address: Wallet address
679
-
680
- Returns:
681
- List of open order records
682
- """
683
479
  try:
684
480
  data = self.info.open_orders(address)
685
481
  return True, data if isinstance(data, list) else []
@@ -690,18 +486,6 @@ class HyperliquidAdapter(BaseAdapter):
690
486
  async def get_frontend_open_orders(
691
487
  self, address: str
692
488
  ) -> tuple[bool, list[dict[str, Any]]]:
693
- """
694
- Get all open orders including trigger orders (stop-loss, take-profit).
695
-
696
- Uses frontendOpenOrders endpoint which returns both limit and trigger orders
697
- with full order details including orderType and triggerPx.
698
-
699
- Args:
700
- address: Wallet address
701
-
702
- Returns:
703
- List of open order records including trigger orders
704
- """
705
489
  try:
706
490
  data = self.info.frontend_open_orders(address)
707
491
  return True, data if isinstance(data, list) else []
@@ -717,11 +501,6 @@ class HyperliquidAdapter(BaseAdapter):
717
501
  amount: float,
718
502
  address: str,
719
503
  ) -> tuple[bool, dict[str, Any]]:
720
- """
721
- Withdraw USDC from Hyperliquid to Arbitrum.
722
-
723
- Note: This is an L1 withdrawal handled by the Hyperliquid executor (signing required).
724
- """
725
504
  if not self._executor:
726
505
  raise NotImplementedError("No Hyperliquid executor configured.")
727
506
 
@@ -737,7 +516,6 @@ class HyperliquidAdapter(BaseAdapter):
737
516
  # ------------------------------------------------------------------ #
738
517
 
739
518
  async def health_check(self) -> dict[str, Any]:
740
- """Check adapter health by verifying API connectivity."""
741
519
  try:
742
520
  success, meta = await self.get_meta_and_asset_ctxs()
743
521
  if success and meta:
@@ -754,15 +532,6 @@ class HyperliquidAdapter(BaseAdapter):
754
532
  # ------------------------------------------------------------------ #
755
533
 
756
534
  def get_perp_margin_amount(self, user_state: dict[str, Any]) -> float:
757
- """
758
- Extract perp margin amount from user state.
759
-
760
- Args:
761
- user_state: User state from get_user_state()
762
-
763
- Returns:
764
- Perp margin balance in USD
765
- """
766
535
  try:
767
536
  margin_summary = user_state.get("marginSummary", {})
768
537
  account_value = margin_summary.get("accountValue")
@@ -779,17 +548,6 @@ class HyperliquidAdapter(BaseAdapter):
779
548
  user: str,
780
549
  builder: str,
781
550
  ) -> tuple[bool, int]:
782
- """
783
- Get the current max builder fee approval for a user/builder pair.
784
-
785
- Args:
786
- user: User wallet address
787
- builder: Builder wallet address
788
-
789
- Returns:
790
- (success, fee_in_tenths_bp) - The approved fee in tenths of basis points.
791
- Returns 0 if no approval exists.
792
- """
793
551
  try:
794
552
  body = {"type": "maxBuilderFee", "user": user, "builder": builder}
795
553
  data = self.info.post("/info", body)
@@ -805,17 +563,6 @@ class HyperliquidAdapter(BaseAdapter):
805
563
  max_fee_rate: str,
806
564
  address: str,
807
565
  ) -> tuple[bool, dict[str, Any]]:
808
- """
809
- Approve a builder fee for a user.
810
-
811
- Args:
812
- builder: Builder wallet address
813
- max_fee_rate: Fee rate as percentage string (e.g., "0.030%" for 30 tenths bp)
814
- address: User wallet address
815
-
816
- Returns:
817
- (success, response_data or error_message)
818
- """
819
566
  if not self._executor:
820
567
  raise NotImplementedError("No Hyperliquid executor configured.")
821
568
 
@@ -839,23 +586,6 @@ class HyperliquidAdapter(BaseAdapter):
839
586
  reduce_only: bool = False,
840
587
  builder: dict[str, Any] | None = None,
841
588
  ) -> tuple[bool, dict[str, Any]]:
842
- """
843
- Place a limit order (GTC - Good Till Cancelled).
844
-
845
- Used for spot stop-loss orders in basis trading.
846
-
847
- Args:
848
- asset_id: Asset ID (perp < 10000, spot >= 10000)
849
- is_buy: True for buy, False for sell
850
- price: Limit price
851
- size: Order size
852
- address: Wallet address
853
- reduce_only: If True, only reduces existing position
854
- builder: Optional builder fee config
855
-
856
- Returns:
857
- (success, response_data or error_message)
858
- """
859
589
  if not self._executor:
860
590
  raise NotImplementedError("No Hyperliquid executor configured.")
861
591
 
@@ -880,21 +610,8 @@ class HyperliquidAdapter(BaseAdapter):
880
610
  timeout_s: int = 120,
881
611
  poll_interval_s: int = 5,
882
612
  ) -> tuple[bool, float]:
883
- """
884
- Wait for a deposit to be credited on Hyperliquid L1.
885
-
886
- Args:
887
- address: Wallet address
888
- expected_increase: Expected USD amount to be deposited
889
- timeout_s: Maximum time to wait in seconds
890
- poll_interval_s: Time between polling attempts
891
-
892
- Returns:
893
- (success, final_balance) - True if deposit confirmed within timeout
894
- """
895
613
  iterations = timeout_s // poll_interval_s
896
614
 
897
- # Get initial balance
898
615
  success, initial_state = await self.get_user_state(address)
899
616
  if not success:
900
617
  self.logger.warning(f"Could not fetch initial state: {initial_state}")
@@ -934,7 +651,6 @@ class HyperliquidAdapter(BaseAdapter):
934
651
  f"Hyperliquid deposit not confirmed after {timeout_s}s. "
935
652
  f"Deposits typically take 1-2 minutes."
936
653
  )
937
- # Return current balance even if not confirmed
938
654
  success, state = await self.get_user_state(address)
939
655
  final_balance = (
940
656
  self.get_perp_margin_amount(state) if success else initial_balance
@@ -946,16 +662,6 @@ class HyperliquidAdapter(BaseAdapter):
946
662
  address: str,
947
663
  from_timestamp_ms: int,
948
664
  ) -> tuple[bool, dict[str, float]]:
949
- """
950
- Get user withdrawal history from Hyperliquid.
951
-
952
- Args:
953
- address: Wallet address
954
- from_timestamp_ms: Start time in milliseconds
955
-
956
- Returns:
957
- (success, {tx_hash: usdc_amount})
958
- """
959
665
  try:
960
666
  from eth_utils import to_checksum_address
961
667
 
@@ -992,21 +698,6 @@ class HyperliquidAdapter(BaseAdapter):
992
698
  max_poll_time_s: int = 30 * 60,
993
699
  poll_interval_s: int = 5,
994
700
  ) -> tuple[bool, dict[str, float]]:
995
- """
996
- Wait for a withdrawal to appear on-chain.
997
-
998
- Polls Hyperliquid's ledger updates until a withdrawal is detected.
999
- Withdrawals typically take 5-15 minutes to process.
1000
-
1001
- Args:
1002
- address: Wallet address
1003
- lookback_s: How far back to look for withdrawals (small buffer for latency)
1004
- max_poll_time_s: Maximum time to wait (default 30 minutes)
1005
- poll_interval_s: Time between polls
1006
-
1007
- Returns:
1008
- (success, {tx_hash: usdc_amount}) - withdrawals found
1009
- """
1010
701
  import time
1011
702
 
1012
703
  start_time_ms = time.time() * 1000