wayfinder-paths 0.1.24__py3-none-any.whl → 0.1.27__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 (44) hide show
  1. wayfinder_paths/__init__.py +2 -0
  2. wayfinder_paths/adapters/brap_adapter/adapter.py +7 -47
  3. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +10 -31
  4. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +128 -60
  5. wayfinder_paths/adapters/hyperliquid_adapter/exchange.py +399 -0
  6. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +74 -0
  7. wayfinder_paths/adapters/hyperliquid_adapter/local_signer.py +82 -0
  8. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +1 -1
  9. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +1 -1
  10. wayfinder_paths/adapters/hyperliquid_adapter/util.py +237 -0
  11. wayfinder_paths/adapters/pendle_adapter/adapter.py +19 -55
  12. wayfinder_paths/adapters/pendle_adapter/test_adapter.py +14 -46
  13. wayfinder_paths/core/__init__.py +2 -0
  14. wayfinder_paths/core/clients/BalanceClient.py +72 -0
  15. wayfinder_paths/core/clients/TokenClient.py +1 -1
  16. wayfinder_paths/core/clients/__init__.py +2 -0
  17. wayfinder_paths/core/strategies/Strategy.py +3 -3
  18. wayfinder_paths/core/types.py +19 -0
  19. wayfinder_paths/core/utils/tokens.py +19 -1
  20. wayfinder_paths/core/utils/transaction.py +9 -7
  21. wayfinder_paths/mcp/tools/balances.py +122 -214
  22. wayfinder_paths/mcp/tools/execute.py +63 -41
  23. wayfinder_paths/mcp/tools/quotes.py +16 -5
  24. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +6 -22
  25. wayfinder_paths/strategies/boros_hype_strategy/boros_ops_mixin.py +227 -33
  26. wayfinder_paths/strategies/boros_hype_strategy/constants.py +17 -1
  27. wayfinder_paths/strategies/boros_hype_strategy/hyperevm_ops_mixin.py +44 -1
  28. wayfinder_paths/strategies/boros_hype_strategy/planner.py +87 -32
  29. wayfinder_paths/strategies/boros_hype_strategy/risk_ops_mixin.py +50 -28
  30. wayfinder_paths/strategies/boros_hype_strategy/strategy.py +71 -50
  31. wayfinder_paths/strategies/boros_hype_strategy/test_planner_golden.py +3 -1
  32. wayfinder_paths/strategies/boros_hype_strategy/test_strategy.py +0 -2
  33. wayfinder_paths/strategies/boros_hype_strategy/types.py +4 -1
  34. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +0 -2
  35. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +0 -2
  36. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +0 -2
  37. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +0 -2
  38. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +0 -2
  39. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +0 -2
  40. wayfinder_paths/tests/test_mcp_quote_swap.py +3 -3
  41. {wayfinder_paths-0.1.24.dist-info → wayfinder_paths-0.1.27.dist-info}/METADATA +2 -3
  42. {wayfinder_paths-0.1.24.dist-info → wayfinder_paths-0.1.27.dist-info}/RECORD +44 -39
  43. {wayfinder_paths-0.1.24.dist-info → wayfinder_paths-0.1.27.dist-info}/WHEEL +1 -1
  44. {wayfinder_paths-0.1.24.dist-info → wayfinder_paths-0.1.27.dist-info}/LICENSE +0 -0
@@ -2,6 +2,7 @@ __version__ = "0.1.0"
2
2
 
3
3
  from wayfinder_paths.core import (
4
4
  BaseAdapter,
5
+ LiquidationResult,
5
6
  StatusDict,
6
7
  StatusTuple,
7
8
  Strategy,
@@ -10,6 +11,7 @@ from wayfinder_paths.core import (
10
11
  __all__ = [
11
12
  "__version__",
12
13
  "BaseAdapter",
14
+ "LiquidationResult",
13
15
  "Strategy",
14
16
  "StatusDict",
15
17
  "StatusTuple",
@@ -11,10 +11,8 @@ from wayfinder_paths.core.adapters.models import SWAP
11
11
  from wayfinder_paths.core.clients.BRAPClient import BRAPClient
12
12
  from wayfinder_paths.core.clients.LedgerClient import TransactionRecord
13
13
  from wayfinder_paths.core.clients.TokenClient import TokenClient
14
- from wayfinder_paths.core.constants.contracts import TOKENS_REQUIRING_APPROVAL_RESET
15
14
  from wayfinder_paths.core.utils.tokens import (
16
- build_approve_transaction,
17
- get_token_allowance,
15
+ ensure_allowance,
18
16
  is_native_token,
19
17
  )
20
18
  from wayfinder_paths.core.utils.transaction import send_transaction
@@ -48,45 +46,6 @@ class BRAPAdapter(BaseAdapter):
48
46
  return max(matching, key=lambda q: int(q.get("output_amount", 0) or 0))
49
47
  return None
50
48
 
51
- async def _handle_token_approval(
52
- self,
53
- *,
54
- chain_id: int,
55
- token_address: str,
56
- owner_address: str,
57
- spender_address: str,
58
- amount: int,
59
- ) -> None:
60
- token_checksum = Web3.to_checksum_address(token_address)
61
- owner_checksum = Web3.to_checksum_address(owner_address)
62
- spender_checksum = Web3.to_checksum_address(spender_address)
63
-
64
- if (chain_id, token_checksum) in TOKENS_REQUIRING_APPROVAL_RESET:
65
- allowance = await get_token_allowance(
66
- token_checksum,
67
- chain_id,
68
- owner_checksum,
69
- spender_checksum,
70
- )
71
- if allowance > 0:
72
- clear_tx = await build_approve_transaction(
73
- from_address=owner_checksum,
74
- chain_id=chain_id,
75
- token_address=token_checksum,
76
- spender_address=spender_checksum,
77
- amount=0,
78
- )
79
- await send_transaction(clear_tx, self.strategy_wallet_signing_callback)
80
-
81
- approve_tx = await build_approve_transaction(
82
- from_address=owner_checksum,
83
- chain_id=chain_id,
84
- token_address=token_checksum,
85
- spender_address=spender_checksum,
86
- amount=int(amount),
87
- )
88
- await send_transaction(approve_tx, self.strategy_wallet_signing_callback)
89
-
90
49
  async def _record_swap_operation(
91
50
  self,
92
51
  from_token: dict[str, Any],
@@ -227,12 +186,13 @@ class BRAPAdapter(BaseAdapter):
227
186
  and approve_amount
228
187
  and not is_native_token(token_address)
229
188
  ):
230
- await self._handle_token_approval(
231
- chain_id=chain_id,
232
- token_address=from_token.get("address"),
233
- owner_address=from_address,
234
- spender_address=spender,
189
+ await ensure_allowance(
190
+ token_address=token_address,
191
+ owner=from_address,
192
+ spender=spender,
235
193
  amount=int(approve_amount),
194
+ chain_id=chain_id,
195
+ signing_callback=self.strategy_wallet_signing_callback,
236
196
  )
237
197
 
238
198
  txn_hash = await send_transaction(
@@ -49,9 +49,6 @@ class HyperlendAdapter(BaseAdapter):
49
49
  strategy_addr = strategy_wallet.get("address")
50
50
 
51
51
  self.strategy_wallet_address = to_checksum_address(strategy_addr)
52
- self.pool_address = HYPERLEND_POOL
53
- self.gateway_address = HYPERLEND_WRAPPED_TOKEN_GATEWAY
54
- self.wrapped_native = HYPEREVM_WHYPE
55
52
 
56
53
  async def get_stable_markets(
57
54
  self,
@@ -167,12 +164,12 @@ class HyperlendAdapter(BaseAdapter):
167
164
  chain_id = int(chain_id)
168
165
 
169
166
  if native:
170
- token_addr = self.wrapped_native
167
+ token_addr = HYPEREVM_WHYPE
171
168
  transaction = await self._encode_call(
172
- target=self.gateway_address,
169
+ target=HYPERLEND_WRAPPED_TOKEN_GATEWAY,
173
170
  abi=WRAPPED_TOKEN_GATEWAY_ABI,
174
171
  fn_name="depositETH",
175
- args=[self.pool_address, strategy, 0],
172
+ args=[HYPERLEND_POOL, strategy, 0],
176
173
  from_address=strategy,
177
174
  chain_id=chain_id,
178
175
  value=qty,
@@ -182,7 +179,7 @@ class HyperlendAdapter(BaseAdapter):
182
179
  approved = await ensure_allowance(
183
180
  token_address=token_addr,
184
181
  owner=strategy,
185
- spender=self.pool_address,
182
+ spender=HYPERLEND_POOL,
186
183
  amount=qty,
187
184
  chain_id=chain_id,
188
185
  signing_callback=self.strategy_wallet_signing_callback,
@@ -190,7 +187,7 @@ class HyperlendAdapter(BaseAdapter):
190
187
  if not approved[0]:
191
188
  return approved
192
189
  transaction = await self._encode_call(
193
- target=self.pool_address,
190
+ target=HYPERLEND_POOL,
194
191
  abi=POOL_ABI,
195
192
  fn_name="supply",
196
193
  args=[token_addr, qty, strategy, 0],
@@ -230,19 +227,19 @@ class HyperlendAdapter(BaseAdapter):
230
227
  chain_id = int(chain_id)
231
228
 
232
229
  if native:
233
- token_addr = self.wrapped_native
230
+ token_addr = HYPEREVM_WHYPE
234
231
  transaction = await self._encode_call(
235
- target=self.gateway_address,
232
+ target=HYPERLEND_WRAPPED_TOKEN_GATEWAY,
236
233
  abi=WRAPPED_TOKEN_GATEWAY_ABI,
237
234
  fn_name="withdrawETH",
238
- args=[self.pool_address, qty, strategy],
235
+ args=[HYPERLEND_POOL, qty, strategy],
239
236
  from_address=strategy,
240
237
  chain_id=chain_id,
241
238
  )
242
239
  else:
243
240
  token_addr = to_checksum_address(underlying_token)
244
241
  transaction = await self._encode_call(
245
- target=self.pool_address,
242
+ target=HYPERLEND_POOL,
246
243
  abi=POOL_ABI,
247
244
  fn_name="withdraw",
248
245
  args=[token_addr, qty, strategy],
@@ -317,7 +314,7 @@ class HyperlendAdapter(BaseAdapter):
317
314
  operation_data = model(
318
315
  adapter=self.adapter_type,
319
316
  token_address=token_address,
320
- pool_address=self.pool_address,
317
+ pool_address=HYPERLEND_POOL,
321
318
  amount=str(amount),
322
319
  amount_usd=amount_usd or 0,
323
320
  transaction_hash=txn_hash,
@@ -356,21 +353,3 @@ class HyperlendAdapter(BaseAdapter):
356
353
  token_data["current_price"],
357
354
  )
358
355
  return current_price * float(amount) / 10 ** int(decimals)
359
-
360
- async def _ensure_allowance(
361
- self,
362
- *,
363
- token_address: str,
364
- owner: str,
365
- spender: str,
366
- amount: int,
367
- chain_id: int,
368
- ) -> tuple[bool, Any]:
369
- return await ensure_allowance(
370
- token_address=token_address,
371
- owner=owner,
372
- spender=spender,
373
- amount=amount,
374
- chain_id=chain_id,
375
- signing_callback=self.strategy_wallet_signing_callback,
376
- )
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import time
5
5
  from decimal import ROUND_DOWN, Decimal, getcontext
6
- from typing import TYPE_CHECKING, Any
6
+ from typing import Any
7
7
 
8
8
  from aiocache import Cache
9
9
  from eth_utils import to_checksum_address
@@ -21,11 +21,7 @@ from wayfinder_paths.core.constants.hyperliquid import (
21
21
  from wayfinder_paths.core.constants.hyperliquid import (
22
22
  HYPERLIQUID_BRIDGE_ADDRESS as _HYPERLIQUID_BRIDGE_ADDRESS,
23
23
  )
24
-
25
- if TYPE_CHECKING:
26
- from wayfinder_paths.core.clients.protocols import (
27
- HyperliquidExecutorProtocol as HyperliquidExecutor,
28
- )
24
+ from wayfinder_paths.core.types import HyperliquidSignCallback
29
25
 
30
26
  # Re-export Bridge2 constants for backwards compatibility.
31
27
  HYPERLIQUID_BRIDGE_ADDRESS = _HYPERLIQUID_BRIDGE_ADDRESS
@@ -35,11 +31,20 @@ try:
35
31
  from hyperliquid.info import Info
36
32
  from hyperliquid.utils import constants
37
33
 
34
+ from wayfinder_paths.adapters.hyperliquid_adapter.exchange import Exchange
35
+ from wayfinder_paths.adapters.hyperliquid_adapter.local_signer import (
36
+ create_local_signer,
37
+ )
38
+ from wayfinder_paths.adapters.hyperliquid_adapter.util import Util
39
+
38
40
  HYPERLIQUID_AVAILABLE = True
39
41
  except ImportError:
40
42
  HYPERLIQUID_AVAILABLE = False
41
43
  Info = None
42
44
  constants = None
45
+ Exchange = None
46
+ Util = None
47
+ create_local_signer = None
43
48
 
44
49
 
45
50
  class HyperliquidAdapter(BaseAdapter):
@@ -62,7 +67,7 @@ class HyperliquidAdapter(BaseAdapter):
62
67
  config: dict[str, Any] | None = None,
63
68
  *,
64
69
  simulation: bool = False,
65
- executor: HyperliquidExecutor | None = None,
70
+ sign_callback: HyperliquidSignCallback | None = None,
66
71
  ) -> None:
67
72
  super().__init__("hyperliquid_adapter", config)
68
73
 
@@ -74,11 +79,36 @@ class HyperliquidAdapter(BaseAdapter):
74
79
 
75
80
  self.simulation = simulation
76
81
  self._cache = Cache(Cache.MEMORY)
77
- self._executor = executor
78
82
 
79
83
  # Initialize Hyperliquid Info client
80
84
  self.info = Info(constants.MAINNET_API_URL, skip_ws=True)
81
85
 
86
+ # Initialize Util
87
+ self.util = Util(self.info)
88
+
89
+ # Initialize Exchange with appropriate signing type
90
+ self._exchange: Exchange | None = None
91
+ if not self.simulation:
92
+ if sign_callback is None:
93
+ # Local signing: create local signer from config
94
+ if not config:
95
+ raise ValueError(
96
+ "Config required for local signing (no sign_callback provided)"
97
+ )
98
+ sign_callback = create_local_signer(config)
99
+ signing_type = "local"
100
+ else:
101
+ # Remote signing: use provided callback (EIP-712)
102
+ signing_type = "eip712"
103
+
104
+ # Instantiate Exchange
105
+ self._exchange = Exchange(
106
+ info=self.info,
107
+ util=self.util,
108
+ sign_callback=sign_callback,
109
+ signing_type=signing_type,
110
+ )
111
+
82
112
  # Cache asset mappings after first fetch
83
113
  self._asset_to_sz_decimals: dict[int, int] | None = None
84
114
  self._coin_to_asset: dict[str, int] | None = None
@@ -533,13 +563,18 @@ class HyperliquidAdapter(BaseAdapter):
533
563
  )
534
564
  return True, {"simulation": True, "status": "ok"}
535
565
 
536
- if not self._executor:
566
+ if not self._exchange:
537
567
  raise NotImplementedError(
538
- "No Hyperliquid executor configured. "
539
- "Inject a HyperliquidExecutor implementation (e.g., LocalHyperliquidExecutor)."
568
+ "No Hyperliquid exchange configured. "
569
+ "Provide a sign_callback or config with private key."
540
570
  )
541
571
 
542
- result = await self._executor.place_market_order(
572
+ # Convert builder to BuilderInfo
573
+ from hyperliquid.utils.types import BuilderInfo
574
+
575
+ builder_info = BuilderInfo(b=builder.get("b"), f=builder.get("f"))
576
+
577
+ result = await self._exchange.place_market_order(
543
578
  asset_id=asset_id,
544
579
  is_buy=is_buy,
545
580
  slippage=slippage,
@@ -547,7 +582,7 @@ class HyperliquidAdapter(BaseAdapter):
547
582
  address=address,
548
583
  reduce_only=reduce_only,
549
584
  cloid=cloid,
550
- builder=builder,
585
+ builder=builder_info,
551
586
  )
552
587
 
553
588
  # Check both the API status and the order statuses for errors
@@ -575,15 +610,12 @@ class HyperliquidAdapter(BaseAdapter):
575
610
  )
576
611
  return True, {"simulation": True, "status": "ok"}
577
612
 
578
- if not self._executor:
579
- raise NotImplementedError(
580
- "No Hyperliquid executor configured. "
581
- "Inject a HyperliquidExecutor implementation (e.g., LocalHyperliquidExecutor)."
582
- )
613
+ if not self._exchange:
614
+ raise NotImplementedError("No Hyperliquid exchange configured.")
583
615
 
584
- result = await self._executor.cancel_order(
616
+ result = await self._exchange.cancel_order(
585
617
  asset_id=asset_id,
586
- order_id=int(order_id) if isinstance(order_id, str) else order_id,
618
+ order_id=str(order_id) if isinstance(order_id, int) else order_id,
587
619
  address=address,
588
620
  )
589
621
 
@@ -596,26 +628,52 @@ class HyperliquidAdapter(BaseAdapter):
596
628
  cloid: str,
597
629
  address: str,
598
630
  ) -> tuple[bool, dict[str, Any]]:
631
+ """
632
+ Cancel order by client order ID (CLOID).
633
+
634
+ Note: The Exchange class uses cancel_order with order_id.
635
+ For cloid-based cancellation, we'd need to first fetch the order_id from open orders.
636
+ """
599
637
  if self.simulation:
600
638
  logger.info(
601
639
  f"[SIMULATION] cancel_order_by_cloid: asset={asset_id}, cloid={cloid}"
602
640
  )
603
641
  return True, {"simulation": True, "status": "ok"}
604
642
 
605
- if not self._executor:
606
- raise NotImplementedError(
607
- "No Hyperliquid executor configured. "
608
- "Inject a HyperliquidExecutor implementation (e.g., LocalHyperliquidExecutor)."
609
- )
643
+ # Find order_id from open orders
644
+ success, orders = await self.get_frontend_open_orders(address)
645
+ if not success:
646
+ return False, {
647
+ "status": "err",
648
+ "response": {"type": "error", "data": "Could not fetch open orders"},
649
+ }
610
650
 
611
- result = await self._executor.cancel_order_by_cloid(
612
- asset_id=asset_id,
613
- cloid=cloid,
614
- address=address,
615
- )
651
+ # Find matching order by cloid
652
+ matching_order = None
653
+ for order in orders:
654
+ if order.get("cloid") == cloid:
655
+ matching_order = order
656
+ break
616
657
 
617
- success = result.get("status") == "ok"
618
- return success, result
658
+ if not matching_order:
659
+ return False, {
660
+ "status": "err",
661
+ "response": {
662
+ "type": "error",
663
+ "data": f"Order with cloid {cloid} not found",
664
+ },
665
+ }
666
+
667
+ order_id = matching_order.get("oid")
668
+ if not order_id:
669
+ return False, {
670
+ "status": "err",
671
+ "response": {"type": "error", "data": "Order missing oid"},
672
+ }
673
+
674
+ return await self.cancel_order(
675
+ asset_id=asset_id, order_id=order_id, address=address
676
+ )
619
677
 
620
678
  async def spot_transfer(
621
679
  self,
@@ -638,13 +696,15 @@ class HyperliquidAdapter(BaseAdapter):
638
696
  )
639
697
  return True, {"simulation": True, "status": "ok"}
640
698
 
641
- if not self._executor:
642
- raise NotImplementedError("No Hyperliquid executor configured.")
699
+ if not self._exchange:
700
+ raise NotImplementedError("No Hyperliquid exchange configured.")
643
701
 
644
- result = await self._executor.spot_transfer(
645
- amount=float(amount),
702
+ # Arbitrum chain ID
703
+ result = await self._exchange.spot_transfer(
704
+ signature_chain_id=42161,
646
705
  destination=str(destination),
647
706
  token=str(token),
707
+ amount=str(amount),
648
708
  address=address,
649
709
  )
650
710
 
@@ -760,11 +820,11 @@ class HyperliquidAdapter(BaseAdapter):
760
820
  )
761
821
  return True, {"simulation": True, "status": "ok"}
762
822
 
763
- if not self._executor:
764
- raise NotImplementedError("No Hyperliquid executor configured.")
823
+ if not self._exchange:
824
+ raise NotImplementedError("No Hyperliquid exchange configured.")
765
825
 
766
- result = await self._executor.update_leverage(
767
- asset_id=asset_id,
826
+ result = await self._exchange.update_leverage(
827
+ asset=asset_id,
768
828
  leverage=leverage,
769
829
  is_cross=is_cross,
770
830
  address=address,
@@ -782,12 +842,13 @@ class HyperliquidAdapter(BaseAdapter):
782
842
  self.logger.info(f"[SIMULATION] transfer_spot_to_perp: {amount} USDC")
783
843
  return True, {"simulation": True, "status": "ok"}
784
844
 
785
- if not self._executor:
786
- raise NotImplementedError("No Hyperliquid executor configured.")
845
+ if not self._exchange:
846
+ raise NotImplementedError("No Hyperliquid exchange configured.")
787
847
 
788
- result = await self._executor.transfer_spot_to_perp(
848
+ result = await self._exchange.usd_class_transfer(
789
849
  amount=amount,
790
850
  address=address,
851
+ to_perp=True,
791
852
  )
792
853
 
793
854
  success = result.get("status") == "ok"
@@ -802,12 +863,13 @@ class HyperliquidAdapter(BaseAdapter):
802
863
  self.logger.info(f"[SIMULATION] transfer_perp_to_spot: {amount} USDC")
803
864
  return True, {"simulation": True, "status": "ok"}
804
865
 
805
- if not self._executor:
806
- raise NotImplementedError("No Hyperliquid executor configured.")
866
+ if not self._exchange:
867
+ raise NotImplementedError("No Hyperliquid exchange configured.")
807
868
 
808
- result = await self._executor.transfer_perp_to_spot(
869
+ result = await self._exchange.usd_class_transfer(
809
870
  amount=amount,
810
871
  address=address,
872
+ to_perp=False,
811
873
  )
812
874
 
813
875
  success = result.get("status") == "ok"
@@ -828,15 +890,17 @@ class HyperliquidAdapter(BaseAdapter):
828
890
  )
829
891
  return True, {"simulation": True, "status": "ok"}
830
892
 
831
- if not self._executor:
832
- raise NotImplementedError("No Hyperliquid executor configured.")
893
+ if not self._exchange:
894
+ raise NotImplementedError("No Hyperliquid exchange configured.")
833
895
 
834
- result = await self._executor.place_stop_loss(
896
+ result = await self._exchange.place_trigger_order(
835
897
  asset_id=asset_id,
836
898
  is_buy=is_buy,
837
899
  trigger_price=trigger_price,
838
900
  size=size,
839
901
  address=address,
902
+ tpsl="sl",
903
+ is_market=True,
840
904
  )
841
905
 
842
906
  success = result.get("status") == "ok"
@@ -951,10 +1015,10 @@ class HyperliquidAdapter(BaseAdapter):
951
1015
  self.logger.info(f"[SIMULATION] withdraw: {amount} USDC")
952
1016
  return True, {"simulation": True, "status": "ok"}
953
1017
 
954
- if not self._executor:
955
- raise NotImplementedError("No Hyperliquid executor configured.")
1018
+ if not self._exchange:
1019
+ raise NotImplementedError("No Hyperliquid exchange configured.")
956
1020
 
957
- result = await self._executor.withdraw(
1021
+ result = await self._exchange.withdraw(
958
1022
  amount=amount,
959
1023
  address=address,
960
1024
  )
@@ -1004,10 +1068,10 @@ class HyperliquidAdapter(BaseAdapter):
1004
1068
  )
1005
1069
  return True, {"simulation": True, "status": "ok"}
1006
1070
 
1007
- if not self._executor:
1008
- raise NotImplementedError("No Hyperliquid executor configured.")
1071
+ if not self._exchange:
1072
+ raise NotImplementedError("No Hyperliquid exchange configured.")
1009
1073
 
1010
- result = await self._executor.approve_builder_fee(
1074
+ result = await self._exchange.approve_builder_fee(
1011
1075
  builder=builder,
1012
1076
  max_fee_rate=max_fee_rate,
1013
1077
  address=address,
@@ -1094,17 +1158,21 @@ class HyperliquidAdapter(BaseAdapter):
1094
1158
  )
1095
1159
  return True, {"simulation": True, "status": "ok"}
1096
1160
 
1097
- if not self._executor:
1098
- raise NotImplementedError("No Hyperliquid executor configured.")
1161
+ if not self._exchange:
1162
+ raise NotImplementedError("No Hyperliquid exchange configured.")
1163
+
1164
+ # Convert builder to BuilderInfo
1165
+ from hyperliquid.utils.types import BuilderInfo
1166
+
1167
+ builder_info = BuilderInfo(b=builder.get("b"), f=builder.get("f"))
1099
1168
 
1100
- result = await self._executor.place_limit_order(
1169
+ result = await self._exchange.place_limit_order(
1101
1170
  asset_id=asset_id,
1102
1171
  is_buy=is_buy,
1103
1172
  price=price,
1104
1173
  size=size,
1105
1174
  address=address,
1106
- reduce_only=reduce_only,
1107
- builder=builder,
1175
+ builder=builder_info,
1108
1176
  )
1109
1177
 
1110
1178
  success = result.get("status") == "ok"