wayfinder-paths 0.1.22__py3-none-any.whl → 0.1.23__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 (63) hide show
  1. wayfinder_paths/__init__.py +0 -4
  2. wayfinder_paths/adapters/balance_adapter/README.md +0 -1
  3. wayfinder_paths/adapters/balance_adapter/adapter.py +65 -169
  4. wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -113
  5. wayfinder_paths/adapters/brap_adapter/README.md +22 -75
  6. wayfinder_paths/adapters/brap_adapter/adapter.py +187 -576
  7. wayfinder_paths/adapters/brap_adapter/examples.json +21 -140
  8. wayfinder_paths/adapters/brap_adapter/test_adapter.py +6 -234
  9. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +39 -86
  10. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +5 -1
  11. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +6 -5
  12. wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
  13. wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
  14. wayfinder_paths/adapters/moonwell_adapter/adapter.py +108 -198
  15. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +37 -23
  16. wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
  17. wayfinder_paths/core/__init__.py +0 -3
  18. wayfinder_paths/core/clients/BRAPClient.py +3 -0
  19. wayfinder_paths/core/clients/ClientManager.py +0 -7
  20. wayfinder_paths/core/clients/LedgerClient.py +196 -172
  21. wayfinder_paths/core/clients/WayfinderClient.py +0 -1
  22. wayfinder_paths/core/clients/__init__.py +0 -5
  23. wayfinder_paths/core/clients/protocols.py +0 -13
  24. wayfinder_paths/core/config.py +0 -164
  25. wayfinder_paths/core/constants/__init__.py +58 -2
  26. wayfinder_paths/core/constants/base.py +8 -22
  27. wayfinder_paths/core/constants/chains.py +36 -0
  28. wayfinder_paths/core/constants/contracts.py +39 -0
  29. wayfinder_paths/core/constants/tokens.py +9 -0
  30. wayfinder_paths/core/strategies/Strategy.py +0 -10
  31. wayfinder_paths/core/utils/evm_helpers.py +5 -15
  32. wayfinder_paths/core/utils/tokens.py +28 -0
  33. wayfinder_paths/core/utils/transaction.py +13 -7
  34. wayfinder_paths/core/utils/web3.py +5 -3
  35. wayfinder_paths/policies/enso.py +1 -2
  36. wayfinder_paths/policies/hyper_evm.py +6 -3
  37. wayfinder_paths/policies/hyperlend.py +1 -2
  38. wayfinder_paths/policies/moonwell.py +12 -7
  39. wayfinder_paths/policies/prjx.py +1 -3
  40. wayfinder_paths/run_strategy.py +97 -300
  41. wayfinder_paths/strategies/basis_trading_strategy/constants.py +3 -1
  42. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +19 -14
  43. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +12 -11
  44. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +20 -33
  45. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +21 -18
  46. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -130
  47. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +32 -42
  48. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/METADATA +2 -3
  49. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/RECORD +51 -60
  50. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/WHEEL +1 -1
  51. wayfinder_paths/core/clients/WalletClient.py +0 -41
  52. wayfinder_paths/core/engine/StrategyJob.py +0 -110
  53. wayfinder_paths/core/services/test_local_evm_txn.py +0 -145
  54. wayfinder_paths/templates/adapter/README.md +0 -150
  55. wayfinder_paths/templates/adapter/adapter.py +0 -16
  56. wayfinder_paths/templates/adapter/examples.json +0 -8
  57. wayfinder_paths/templates/adapter/test_adapter.py +0 -30
  58. wayfinder_paths/templates/strategy/README.md +0 -186
  59. wayfinder_paths/templates/strategy/examples.json +0 -11
  60. wayfinder_paths/templates/strategy/strategy.py +0 -35
  61. wayfinder_paths/templates/strategy/test_strategy.py +0 -166
  62. wayfinder_paths/tests/test_smoke_manifest.py +0 -63
  63. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/LICENSE +0 -0
@@ -12,23 +12,19 @@ from wayfinder_paths.core.clients.HyperlendClient import (
12
12
  MarketEntry,
13
13
  StableMarketsHeadroomResponse,
14
14
  )
15
+ from wayfinder_paths.core.constants.contracts import (
16
+ HYPEREVM_WHYPE,
17
+ HYPERLEND_POOL,
18
+ HYPERLEND_WRAPPED_TOKEN_GATEWAY,
19
+ )
15
20
  from wayfinder_paths.core.constants.hyperlend_abi import (
16
21
  POOL_ABI,
17
22
  WRAPPED_TOKEN_GATEWAY_ABI,
18
23
  )
19
- from wayfinder_paths.core.utils.tokens import (
20
- build_approve_transaction,
21
- get_token_allowance,
22
- )
24
+ from wayfinder_paths.core.utils.tokens import ensure_allowance
23
25
  from wayfinder_paths.core.utils.transaction import send_transaction
24
26
  from wayfinder_paths.core.utils.web3 import web3_from_chain_id
25
27
 
26
- HYPERLEND_DEFAULTS = {
27
- "pool": "0x00A89d7a5A02160f20150EbEA7a2b5E4879A1A8b",
28
- "wrapped_token_gateway": "0x49558c794ea2aC8974C9F27886DDfAa951E99171",
29
- "wrapped_native_underlying": "0x5555555555555555555555555555555555555555",
30
- }
31
-
32
28
 
33
29
  class HyperlendAdapter(BaseAdapter):
34
30
  adapter_type = "HYPERLEND"
@@ -39,32 +35,30 @@ class HyperlendAdapter(BaseAdapter):
39
35
  strategy_wallet_signing_callback=None,
40
36
  ) -> None:
41
37
  super().__init__("hyperlend_adapter", config)
42
- cfg = config or {}
43
- adapter_cfg = cfg.get("hyperlend_adapter") or {}
38
+ config = config or {}
39
+ adapter_cfg = config.get("hyperlend_adapter") or {}
44
40
 
45
41
  self.strategy_wallet_signing_callback = strategy_wallet_signing_callback
46
42
  self.hyperlend_client = HyperlendClient()
47
43
 
48
- self.strategy_wallet = cfg.get("strategy_wallet") or {}
49
- self.pool_address = self._checksum(
50
- adapter_cfg.get("pool_address") or HYPERLEND_DEFAULTS["pool"]
44
+ strategy_wallet = config.get("strategy_wallet") or {}
45
+ strategy_addr = strategy_wallet.get("address")
46
+ if not strategy_addr:
47
+ raise ValueError("strategy_wallet.address is required")
48
+ self.strategy_wallet_address = to_checksum_address(strategy_addr)
49
+ self.pool_address = to_checksum_address(
50
+ adapter_cfg.get("pool_address") or HYPERLEND_POOL
51
51
  )
52
- self.gateway_address = self._checksum(
53
- adapter_cfg.get("wrapped_token_gateway")
54
- or HYPERLEND_DEFAULTS["wrapped_token_gateway"]
52
+ self.gateway_address = to_checksum_address(
53
+ adapter_cfg.get("wrapped_token_gateway") or HYPERLEND_WRAPPED_TOKEN_GATEWAY
55
54
  )
56
- self.wrapped_native = self._checksum(
57
- adapter_cfg.get("wrapped_native_underlying")
58
- or HYPERLEND_DEFAULTS["wrapped_native_underlying"]
55
+ self.wrapped_native = to_checksum_address(
56
+ adapter_cfg.get("wrapped_native_underlying") or HYPEREVM_WHYPE
59
57
  )
60
58
  self.gateway_deposit_takes_pool = adapter_cfg.get(
61
59
  "gateway_deposit_takes_pool", True
62
60
  )
63
61
 
64
- # ------------------------------------------------------------------ #
65
- # Public API #
66
- # ------------------------------------------------------------------ #
67
-
68
62
  async def get_stable_markets(
69
63
  self,
70
64
  *,
@@ -131,14 +125,14 @@ class HyperlendAdapter(BaseAdapter):
131
125
  chain_id: int,
132
126
  native: bool = False,
133
127
  ) -> tuple[bool, Any]:
134
- strategy = self._strategy_address()
128
+ strategy = self.strategy_wallet_address
135
129
  qty = int(qty)
136
130
  if qty <= 0:
137
131
  return False, "qty must be positive"
138
132
  chain_id = int(chain_id)
139
133
 
140
134
  if native:
141
- tx = await self._encode_call(
135
+ transcation = await self._encode_call(
142
136
  target=self.gateway_address,
143
137
  abi=WRAPPED_TOKEN_GATEWAY_ABI,
144
138
  fn_name="depositETH",
@@ -148,17 +142,18 @@ class HyperlendAdapter(BaseAdapter):
148
142
  value=qty,
149
143
  )
150
144
  else:
151
- token_addr = self._checksum(underlying_token)
152
- approved = await self._ensure_allowance(
145
+ token_addr = to_checksum_address(underlying_token)
146
+ approved = await ensure_allowance(
153
147
  token_address=token_addr,
154
148
  owner=strategy,
155
149
  spender=self.pool_address,
156
150
  amount=qty,
157
151
  chain_id=chain_id,
152
+ signing_callback=self.strategy_wallet_signing_callback,
158
153
  )
159
154
  if not approved[0]:
160
155
  return approved
161
- tx = await self._encode_call(
156
+ transcation = await self._encode_call(
162
157
  target=self.pool_address,
163
158
  abi=POOL_ABI,
164
159
  fn_name="supply",
@@ -166,7 +161,10 @@ class HyperlendAdapter(BaseAdapter):
166
161
  from_address=strategy,
167
162
  chain_id=chain_id,
168
163
  )
169
- return await self._send_tx(tx)
164
+ txn_hash = await send_transaction(
165
+ transcation, self.strategy_wallet_signing_callback
166
+ )
167
+ return True, txn_hash
170
168
 
171
169
  async def unlend(
172
170
  self,
@@ -176,14 +174,14 @@ class HyperlendAdapter(BaseAdapter):
176
174
  chain_id: int,
177
175
  native: bool = False,
178
176
  ) -> tuple[bool, Any]:
179
- strategy = self._strategy_address()
177
+ strategy = self.strategy_wallet_address
180
178
  qty = int(qty)
181
179
  if qty <= 0:
182
180
  return False, "qty must be positive"
183
181
  chain_id = int(chain_id)
184
182
 
185
183
  if native:
186
- tx = await self._encode_call(
184
+ transaction = await self._encode_call(
187
185
  target=self.gateway_address,
188
186
  abi=WRAPPED_TOKEN_GATEWAY_ABI,
189
187
  fn_name="withdrawETH",
@@ -192,8 +190,8 @@ class HyperlendAdapter(BaseAdapter):
192
190
  chain_id=chain_id,
193
191
  )
194
192
  else:
195
- token_addr = self._checksum(underlying_token)
196
- tx = await self._encode_call(
193
+ token_addr = to_checksum_address(underlying_token)
194
+ transaction = await self._encode_call(
197
195
  target=self.pool_address,
198
196
  abi=POOL_ABI,
199
197
  fn_name="withdraw",
@@ -201,36 +199,10 @@ class HyperlendAdapter(BaseAdapter):
201
199
  from_address=strategy,
202
200
  chain_id=chain_id,
203
201
  )
204
- return await self._send_tx(tx)
205
-
206
- # ------------------------------------------------------------------ #
207
- # Helpers #
208
- # ------------------------------------------------------------------ #
209
-
210
- async def _send_tx(self, tx: dict[str, Any]) -> tuple[bool, Any]:
211
- txn_hash = await send_transaction(tx, self.strategy_wallet_signing_callback)
212
- return True, txn_hash
213
-
214
- async def _ensure_allowance(
215
- self,
216
- *,
217
- token_address: str,
218
- owner: str,
219
- spender: str,
220
- amount: int,
221
- chain_id: int,
222
- ) -> tuple[bool, Any]:
223
- allowance = await get_token_allowance(token_address, chain_id, owner, spender)
224
- if allowance >= amount:
225
- return True, {}
226
- approve_tx = await build_approve_transaction(
227
- from_address=owner,
228
- chain_id=chain_id,
229
- token_address=token_address,
230
- spender_address=spender,
231
- amount=amount,
202
+ txn_hash = await send_transaction(
203
+ transaction, self.strategy_wallet_signing_callback
232
204
  )
233
- return await self._send_tx(approve_tx)
205
+ return True, txn_hash
234
206
 
235
207
  async def _encode_call(
236
208
  self,
@@ -254,35 +226,16 @@ class HyperlendAdapter(BaseAdapter):
254
226
  except ValueError as exc:
255
227
  raise ValueError(f"Failed to encode {fn_name}: {exc}") from exc
256
228
 
257
- tx: dict[str, Any] = {
229
+ transaction: dict[str, Any] = {
258
230
  "chainId": int(chain_id),
259
231
  "from": to_checksum_address(from_address),
260
232
  "to": to_checksum_address(target),
261
233
  "data": data,
262
234
  "value": int(value),
263
235
  }
264
- return tx
265
-
266
- def _strategy_address(self) -> str:
267
- addr = None
268
- if isinstance(self.strategy_wallet, dict):
269
- addr = self.strategy_wallet.get("address") or (
270
- (self.strategy_wallet.get("evm") or {}).get("address")
271
- )
272
- elif isinstance(self.strategy_wallet, str):
273
- addr = self.strategy_wallet
274
- if not addr:
275
- raise ValueError(
276
- "strategy_wallet address is required for HyperLend operations"
277
- )
278
- return to_checksum_address(addr)
236
+ return transaction
279
237
 
280
238
  def _gateway_first_arg(self, underlying_token: str) -> str:
281
239
  if self.gateway_deposit_takes_pool:
282
240
  return self.pool_address
283
- return self._checksum(underlying_token) or self.wrapped_native
284
-
285
- def _checksum(self, address: str | None) -> str:
286
- if not address:
287
- raise ValueError("Missing required contract address in HyperLend config")
288
- return to_checksum_address(address)
241
+ return to_checksum_address(underlying_token)
@@ -14,7 +14,11 @@ class TestHyperlendAdapter:
14
14
  @pytest.fixture
15
15
  def adapter(self, mock_hyperlend_client):
16
16
  adapter = HyperlendAdapter(
17
- config={},
17
+ config={
18
+ "strategy_wallet": {
19
+ "address": "0x1234567890123456789012345678901234567890"
20
+ }
21
+ },
18
22
  )
19
23
  adapter.hyperlend_client = mock_hyperlend_client
20
24
  return adapter
@@ -5,17 +5,18 @@ import time
5
5
  from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
8
+ from wayfinder_paths.core.constants.contracts import (
9
+ ARBITRUM_USDC,
10
+ HYPERLIQUID_BRIDGE,
11
+ )
8
12
 
9
13
  if TYPE_CHECKING:
10
14
  from wayfinder_paths.core.clients.protocols import (
11
15
  HyperliquidExecutorProtocol as HyperliquidExecutor,
12
16
  )
13
17
 
14
- # Hyperliquid L1 bridge address on Arbitrum - send USDC here to deposit
15
- HYPERLIQUID_BRIDGE_ADDRESS = "0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7"
16
-
17
- # USDC contract on Arbitrum
18
- ARBITRUM_USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
18
+ HYPERLIQUID_BRIDGE_ADDRESS = HYPERLIQUID_BRIDGE
19
+ ARBITRUM_USDC_ADDRESS = ARBITRUM_USDC
19
20
 
20
21
  try:
21
22
  from hyperliquid.info import Info
@@ -46,7 +46,10 @@ success, data = await adapter.get_strategy_net_deposit(
46
46
  wallet_address="0x..."
47
47
  )
48
48
  if success:
49
- net_deposit = data.get("net_deposit", 0)
49
+ net_deposit = float(data) if data is not None else 0
50
+ print(f"Net deposit: {net_deposit} USDC")
51
+ else:
52
+ print(f"Error: {data}")
50
53
  ```
51
54
 
52
55
  ### record_deposit
@@ -4,7 +4,6 @@ from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
4
4
  from wayfinder_paths.core.adapters.models import Operation
5
5
  from wayfinder_paths.core.clients.LedgerClient import (
6
6
  LedgerClient,
7
- NetDeposit,
8
7
  StrategyTransactionList,
9
8
  TransactionRecord,
10
9
  )
@@ -36,7 +35,7 @@ class LedgerAdapter(BaseAdapter):
36
35
 
37
36
  async def get_strategy_net_deposit(
38
37
  self, wallet_address: str
39
- ) -> tuple[bool, NetDeposit | str]:
38
+ ) -> tuple[bool, float | str]:
40
39
  try:
41
40
  data = await self.ledger_client.get_strategy_net_deposit(
42
41
  wallet_address=wallet_address
@@ -116,9 +115,10 @@ class LedgerAdapter(BaseAdapter):
116
115
  strategy_name: str | None = None,
117
116
  ) -> tuple[bool, TransactionRecord | str]:
118
117
  try:
118
+ op_dict = operation_data.model_dump(mode="json")
119
119
  result = await self.ledger_client.add_strategy_operation(
120
120
  wallet_address=wallet_address,
121
- operation_data=operation_data,
121
+ operation_data=op_dict,
122
122
  usd_value=usd_value,
123
123
  strategy_name=strategy_name,
124
124
  )