wayfinder-paths 0.1.11__py3-none-any.whl → 0.1.13__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 (46) hide show
  1. wayfinder_paths/adapters/balance_adapter/adapter.py +3 -7
  2. wayfinder_paths/adapters/brap_adapter/adapter.py +10 -13
  3. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +6 -9
  4. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +1 -1
  5. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +44 -5
  6. wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +104 -0
  7. wayfinder_paths/adapters/moonwell_adapter/adapter.py +0 -3
  8. wayfinder_paths/adapters/pool_adapter/README.md +4 -19
  9. wayfinder_paths/adapters/pool_adapter/adapter.py +4 -29
  10. wayfinder_paths/adapters/pool_adapter/examples.json +6 -7
  11. wayfinder_paths/adapters/pool_adapter/test_adapter.py +8 -8
  12. wayfinder_paths/core/clients/AuthClient.py +2 -2
  13. wayfinder_paths/core/clients/BRAPClient.py +2 -2
  14. wayfinder_paths/core/clients/HyperlendClient.py +2 -2
  15. wayfinder_paths/core/clients/PoolClient.py +18 -54
  16. wayfinder_paths/core/clients/TokenClient.py +3 -3
  17. wayfinder_paths/core/clients/WalletClient.py +2 -2
  18. wayfinder_paths/core/clients/WayfinderClient.py +9 -10
  19. wayfinder_paths/core/clients/protocols.py +1 -7
  20. wayfinder_paths/core/config.py +60 -224
  21. wayfinder_paths/core/services/local_evm_txn.py +22 -4
  22. wayfinder_paths/core/strategies/Strategy.py +3 -3
  23. wayfinder_paths/core/strategies/descriptors.py +7 -0
  24. wayfinder_paths/core/utils/evm_helpers.py +5 -1
  25. wayfinder_paths/core/utils/wallets.py +12 -19
  26. wayfinder_paths/core/wallets/README.md +1 -1
  27. wayfinder_paths/run_strategy.py +10 -8
  28. wayfinder_paths/scripts/create_strategy.py +5 -5
  29. wayfinder_paths/scripts/make_wallets.py +5 -5
  30. wayfinder_paths/scripts/run_strategy.py +3 -3
  31. wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +1 -1
  32. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +196 -515
  33. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +228 -11
  34. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +2 -2
  35. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +1 -0
  36. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +1 -1
  37. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +8 -7
  38. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +2 -2
  39. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +25 -25
  40. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +28 -9
  41. wayfinder_paths/templates/adapter/README.md +1 -1
  42. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/METADATA +9 -12
  43. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/RECORD +45 -45
  44. wayfinder_paths/core/settings.py +0 -61
  45. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/LICENSE +0 -0
  46. {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/WHEEL +0 -0
@@ -7,7 +7,6 @@ from wayfinder_paths.core.clients.TokenClient import TokenClient
7
7
  from wayfinder_paths.core.clients.WalletClient import WalletClient
8
8
  from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
9
9
  from wayfinder_paths.core.services.base import Web3Service
10
- from wayfinder_paths.core.settings import settings
11
10
  from wayfinder_paths.core.utils.evm_helpers import resolve_chain_id
12
11
 
13
12
 
@@ -129,12 +128,9 @@ class BalanceAdapter(BaseAdapter):
129
128
  return False, tx_data
130
129
 
131
130
  tx = tx_data
132
- if getattr(settings, "DRY_RUN", False):
133
- broadcast_result = (True, {"dry_run": True, "transaction": tx})
134
- else:
135
- broadcast_result = await self.wallet_provider.broadcast_transaction(
136
- tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
137
- )
131
+ broadcast_result = await self.wallet_provider.broadcast_transaction(
132
+ tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
133
+ )
138
134
 
139
135
  if broadcast_result[0] and not skip_ledger and ledger_method is not None:
140
136
  wallet_for_ledger = from_address if ledger_wallet == "from" else to_address
@@ -14,7 +14,6 @@ from wayfinder_paths.core.clients.TokenClient import TokenClient
14
14
  from wayfinder_paths.core.constants import DEFAULT_SLIPPAGE, ZERO_ADDRESS
15
15
  from wayfinder_paths.core.constants.base import DEFAULT_TRANSACTION_TIMEOUT
16
16
  from wayfinder_paths.core.services.base import Web3Service
17
- from wayfinder_paths.core.settings import settings
18
17
 
19
18
  _NEEDS_CLEAR_APPROVAL = {
20
19
  (1, "0xdac17f958d2ee523a2206206994597c13d831ec7"),
@@ -339,16 +338,16 @@ class BRAPAdapter(BaseAdapter):
339
338
  "all_routes": sorted_quotes,
340
339
  "route_analysis": {
341
340
  "highest_output": sorted_quotes[0] if sorted_quotes else None,
342
- "lowest_fees": min(
343
- all_quotes, key=lambda x: int(x.get("total_fee", 0))
344
- )
345
- if all_quotes
346
- else None,
347
- "fastest": min(
348
- all_quotes, key=lambda x: int(x.get("estimated_time", 0))
349
- )
350
- if all_quotes
351
- else None,
341
+ "lowest_fees": (
342
+ min(all_quotes, key=lambda x: int(x.get("total_fee", 0)))
343
+ if all_quotes
344
+ else None
345
+ ),
346
+ "fastest": (
347
+ min(all_quotes, key=lambda x: int(x.get("estimated_time", 0)))
348
+ if all_quotes
349
+ else None
350
+ ),
352
351
  },
353
352
  }
354
353
 
@@ -698,8 +697,6 @@ class BRAPAdapter(BaseAdapter):
698
697
  async def _broadcast_transaction(
699
698
  self, transaction: dict[str, Any], confirmations: int = 0
700
699
  ) -> tuple[bool, Any]:
701
- if getattr(settings, "DRY_RUN", False):
702
- return True, {"dry_run": True, "transaction": transaction}
703
700
  return await self.wallet_provider.broadcast_transaction(
704
701
  transaction,
705
702
  wait_for_receipt=True,
@@ -18,7 +18,6 @@ from wayfinder_paths.core.constants.hyperlend_abi import (
18
18
  WRAPPED_TOKEN_GATEWAY_ABI,
19
19
  )
20
20
  from wayfinder_paths.core.services.base import Web3Service
21
- from wayfinder_paths.core.settings import settings
22
21
 
23
22
  HYPERLEND_DEFAULTS = {
24
23
  "pool": "0x00A89d7a5A02160f20150EbEA7a2b5E4879A1A8b",
@@ -136,7 +135,7 @@ class HyperlendAdapter(BaseAdapter):
136
135
  chain_id = int(chain_id)
137
136
 
138
137
  if native:
139
- tx = self._encode_call(
138
+ tx = await self._encode_call(
140
139
  target=self.gateway_address,
141
140
  abi=WRAPPED_TOKEN_GATEWAY_ABI,
142
141
  fn_name="depositETH",
@@ -156,7 +155,7 @@ class HyperlendAdapter(BaseAdapter):
156
155
  )
157
156
  if not approved[0]:
158
157
  return approved
159
- tx = self._encode_call(
158
+ tx = await self._encode_call(
160
159
  target=self.pool_address,
161
160
  abi=POOL_ABI,
162
161
  fn_name="supply",
@@ -181,7 +180,7 @@ class HyperlendAdapter(BaseAdapter):
181
180
  chain_id = int(chain_id)
182
181
 
183
182
  if native:
184
- tx = self._encode_call(
183
+ tx = await self._encode_call(
185
184
  target=self.gateway_address,
186
185
  abi=WRAPPED_TOKEN_GATEWAY_ABI,
187
186
  fn_name="withdrawETH",
@@ -191,7 +190,7 @@ class HyperlendAdapter(BaseAdapter):
191
190
  )
192
191
  else:
193
192
  token_addr = self._checksum(underlying_token)
194
- tx = self._encode_call(
193
+ tx = await self._encode_call(
195
194
  target=self.pool_address,
196
195
  abi=POOL_ABI,
197
196
  fn_name="withdraw",
@@ -237,13 +236,11 @@ class HyperlendAdapter(BaseAdapter):
237
236
  )
238
237
 
239
238
  async def _broadcast_transaction(self, tx: dict[str, Any]) -> tuple[bool, Any]:
240
- if getattr(settings, "DRY_RUN", False):
241
- return True, {"dry_run": True, "transaction": tx}
242
239
  return await self.web3.evm_transactions.broadcast_transaction(
243
240
  tx, wait_for_receipt=True, timeout=DEFAULT_TRANSACTION_TIMEOUT
244
241
  )
245
242
 
246
- def _encode_call(
243
+ async def _encode_call(
247
244
  self,
248
245
  *,
249
246
  target: str,
@@ -258,7 +255,7 @@ class HyperlendAdapter(BaseAdapter):
258
255
  web3 = self.web3.get_web3(chain_id)
259
256
  contract = web3.eth.contract(address=target, abi=abi)
260
257
  try:
261
- data = getattr(contract.functions, fn_name)(*args).build_transaction(
258
+ data = await getattr(contract.functions, fn_name)(*args).build_transaction(
262
259
  {"from": from_address}
263
260
  )["data"]
264
261
  except ValueError as exc:
@@ -31,7 +31,7 @@ except ImportError:
31
31
 
32
32
 
33
33
  class SimpleCache:
34
- """Simple in-memory cache with TTL to replace Django cache."""
34
+ """Simple in-memory cache with TTL for local caching."""
35
35
 
36
36
  def __init__(self):
37
37
  self._cache: dict[str, Any] = {}
@@ -10,6 +10,7 @@ the protocol (for example, by delegating signing to a hosted signer).
10
10
  from __future__ import annotations
11
11
 
12
12
  import uuid
13
+ from collections.abc import Mapping
13
14
  from typing import Any
14
15
 
15
16
  from loguru import logger
@@ -86,11 +87,49 @@ class LocalHyperliquidExecutor:
86
87
  )
87
88
  self.info = Info(base_url, skip_ws=True)
88
89
  self.exchange = Exchange(self._wallet, base_url)
90
+ self._asset_id_to_coin: dict[int, str] | None = None
89
91
 
90
92
  logger.info(
91
93
  f"LocalHyperliquidExecutor initialized for address: {self._wallet.address}"
92
94
  )
93
95
 
96
+ def _get_perp_coin(self, asset_id: int) -> str | None:
97
+ """
98
+ Resolve a perp coin name from a perp asset_id.
99
+
100
+ Note: newer versions of the hyperliquid SDK expose `coin_to_asset` but not
101
+ `asset_to_coin`, so we build the reverse mapping when needed.
102
+ """
103
+ if self._asset_id_to_coin is None:
104
+ mapping: dict[int, str] = {}
105
+
106
+ asset_to_coin = getattr(self.info, "asset_to_coin", None)
107
+ if isinstance(asset_to_coin, Mapping):
108
+ for k, v in asset_to_coin.items():
109
+ try:
110
+ asset_int = int(k)
111
+ except (TypeError, ValueError):
112
+ continue
113
+ if v:
114
+ mapping[asset_int] = str(v)
115
+
116
+ coin_to_asset = getattr(self.info, "coin_to_asset", None)
117
+ try:
118
+ coin_to_asset_dict = dict(coin_to_asset) if coin_to_asset else {}
119
+ except Exception: # noqa: BLE001
120
+ coin_to_asset_dict = {}
121
+ for coin, aid in coin_to_asset_dict.items():
122
+ try:
123
+ asset_int = int(aid)
124
+ except (TypeError, ValueError):
125
+ continue
126
+ if coin and asset_int not in mapping:
127
+ mapping[asset_int] = str(coin)
128
+
129
+ self._asset_id_to_coin = mapping
130
+
131
+ return self._asset_id_to_coin.get(asset_id) if self._asset_id_to_coin else None
132
+
94
133
  def _resolve_private_key(self, config: dict[str, Any]) -> str | None:
95
134
  """Extract private key from config."""
96
135
  # Try strategy_wallet first
@@ -172,7 +211,7 @@ class LocalHyperliquidExecutor:
172
211
  )
173
212
  else:
174
213
  # Perp market order
175
- coin = self.info.asset_to_coin.get(asset_id)
214
+ coin = self._get_perp_coin(asset_id)
176
215
  if not coin:
177
216
  return {
178
217
  "status": "err",
@@ -231,7 +270,7 @@ class LocalHyperliquidExecutor:
231
270
  spot_index = asset_id - 10000
232
271
  coin = f"@{spot_index}"
233
272
  else:
234
- coin = self.info.asset_to_coin.get(asset_id)
273
+ coin = self._get_perp_coin(asset_id)
235
274
  if not coin:
236
275
  return {
237
276
  "status": "err",
@@ -268,7 +307,7 @@ class LocalHyperliquidExecutor:
268
307
  }
269
308
 
270
309
  try:
271
- coin = self.info.asset_to_coin.get(asset_id)
310
+ coin = self._get_perp_coin(asset_id)
272
311
  if not coin:
273
312
  return {
274
313
  "status": "err",
@@ -366,7 +405,7 @@ class LocalHyperliquidExecutor:
366
405
  }
367
406
 
368
407
  try:
369
- coin = self.info.asset_to_coin.get(asset_id)
408
+ coin = self._get_perp_coin(asset_id)
370
409
  if not coin:
371
410
  return {
372
411
  "status": "err",
@@ -439,7 +478,7 @@ class LocalHyperliquidExecutor:
439
478
  spot_index = asset_id - 10000
440
479
  coin = f"@{spot_index}"
441
480
  else:
442
- coin = self.info.asset_to_coin.get(asset_id)
481
+ coin = self._get_perp_coin(asset_id)
443
482
  if not coin:
444
483
  return {
445
484
  "status": "err",
@@ -0,0 +1,104 @@
1
+ """Tests for LocalHyperliquidExecutor."""
2
+
3
+ from types import SimpleNamespace
4
+ from unittest.mock import MagicMock, patch
5
+
6
+ import pytest
7
+
8
+
9
+ class TestLocalHyperliquidExecutor:
10
+ """Tests for LocalHyperliquidExecutor."""
11
+
12
+ @pytest.fixture
13
+ def mock_info_without_asset_to_coin(self):
14
+ """Mock Info that only exposes coin_to_asset (no asset_to_coin)."""
15
+ return SimpleNamespace(coin_to_asset={"HYPE": 7})
16
+
17
+ @pytest.fixture
18
+ def mock_exchange(self):
19
+ """Mock Exchange client."""
20
+ mock = MagicMock()
21
+ mock.update_leverage.return_value = {"status": "ok"}
22
+ mock.market_open.return_value = {"status": "ok"}
23
+ return mock
24
+
25
+ @pytest.mark.asyncio
26
+ async def test_update_leverage_works_without_asset_to_coin(
27
+ self, mock_info_without_asset_to_coin, mock_exchange
28
+ ):
29
+ """update_leverage should map asset_id->coin via coin_to_asset inversion."""
30
+ dummy_wallet = SimpleNamespace(address="0xabc")
31
+
32
+ with patch(
33
+ "wayfinder_paths.adapters.hyperliquid_adapter.executor.Account"
34
+ ) as mock_account:
35
+ mock_account.from_key.return_value = dummy_wallet
36
+ with patch(
37
+ "wayfinder_paths.adapters.hyperliquid_adapter.executor.Info",
38
+ return_value=mock_info_without_asset_to_coin,
39
+ ):
40
+ with patch(
41
+ "wayfinder_paths.adapters.hyperliquid_adapter.executor.Exchange",
42
+ return_value=mock_exchange,
43
+ ):
44
+ from wayfinder_paths.adapters.hyperliquid_adapter.executor import (
45
+ LocalHyperliquidExecutor,
46
+ )
47
+
48
+ executor = LocalHyperliquidExecutor(
49
+ config={"strategy_wallet": {"private_key": "0x" + "11" * 32}}
50
+ )
51
+ resp = await executor.update_leverage(
52
+ asset_id=7,
53
+ leverage=1,
54
+ is_cross=True,
55
+ address="0xabc",
56
+ )
57
+
58
+ assert resp.get("status") == "ok"
59
+ mock_exchange.update_leverage.assert_called_once_with(
60
+ leverage=1,
61
+ name="HYPE",
62
+ is_cross=True,
63
+ )
64
+
65
+ @pytest.mark.asyncio
66
+ async def test_place_market_order_perp_works_without_asset_to_coin(
67
+ self, mock_info_without_asset_to_coin, mock_exchange
68
+ ):
69
+ """place_market_order should map asset_id->coin via coin_to_asset inversion."""
70
+ dummy_wallet = SimpleNamespace(address="0xabc")
71
+
72
+ with patch(
73
+ "wayfinder_paths.adapters.hyperliquid_adapter.executor.Account"
74
+ ) as mock_account:
75
+ mock_account.from_key.return_value = dummy_wallet
76
+ with patch(
77
+ "wayfinder_paths.adapters.hyperliquid_adapter.executor.Info",
78
+ return_value=mock_info_without_asset_to_coin,
79
+ ):
80
+ with patch(
81
+ "wayfinder_paths.adapters.hyperliquid_adapter.executor.Exchange",
82
+ return_value=mock_exchange,
83
+ ):
84
+ from wayfinder_paths.adapters.hyperliquid_adapter.executor import (
85
+ LocalHyperliquidExecutor,
86
+ )
87
+
88
+ executor = LocalHyperliquidExecutor(
89
+ config={"strategy_wallet": {"private_key": "0x" + "11" * 32}}
90
+ )
91
+ resp = await executor.place_market_order(
92
+ asset_id=7,
93
+ is_buy=True,
94
+ slippage=0.01,
95
+ size=1.0,
96
+ address="0xabc",
97
+ reduce_only=False,
98
+ cloid=MagicMock(), # Avoid Cloid conversion
99
+ )
100
+
101
+ assert resp.get("status") == "ok"
102
+ mock_exchange.market_open.assert_called_once()
103
+ _, kwargs = mock_exchange.market_open.call_args
104
+ assert kwargs["name"] == "HYPE"
@@ -23,7 +23,6 @@ from wayfinder_paths.core.constants.moonwell_abi import (
23
23
  WETH_ABI,
24
24
  )
25
25
  from wayfinder_paths.core.services.base import Web3Service
26
- from wayfinder_paths.core.settings import settings
27
26
 
28
27
  # Moonwell Base chain addresses
29
28
  MOONWELL_DEFAULTS = {
@@ -1149,8 +1148,6 @@ class MoonwellAdapter(BaseAdapter):
1149
1148
 
1150
1149
  Includes retry logic with exponential backoff for rate-limited RPCs.
1151
1150
  """
1152
- if getattr(settings, "DRY_RUN", False):
1153
- return True, {"dry_run": True, "transaction": tx}
1154
1151
  if not self.web3:
1155
1152
  return False, "web3 service not configured"
1156
1153
 
@@ -35,8 +35,7 @@ adapter = PoolAdapter()
35
35
 
36
36
  ```python
37
37
  success, data = await adapter.get_pools_by_ids(
38
- pool_ids=["pool-123", "pool-456"],
39
- merge_external=True
38
+ pool_ids=["pool-123", "pool-456"]
40
39
  )
41
40
  if success:
42
41
  pools = data.get("pools", [])
@@ -48,27 +47,13 @@ else:
48
47
  ### Get Llama Matches
49
48
 
50
49
  ```python
51
- success, data = await adapter.get_llama_matches()
50
+ success, data = await adapter.get_pools()
52
51
  if success:
53
52
  matches = data.get("matches", [])
54
53
  print(f"Found {len(matches)} Llama matches")
55
54
  for match in matches:
56
- if match.get("llama_stablecoin"):
57
- print(f"Stablecoin pool: {match.get('id')} - APY: {match.get('llama_apy_pct')}%")
58
- else:
59
- print(f"Error: {data}")
60
- ```
61
-
62
- ### Get Llama Reports
63
-
64
- ```python
65
- success, data = await adapter.get_llama_reports(
66
- identifiers=["pool-123", "usd-coin-base", "base_0x1234..."]
67
- )
68
- if success:
69
- reports = data
70
- for identifier, report in reports.items():
71
- print(f"Report for {identifier}: APY {report.get('llama_apy_pct', 0)}%")
55
+ if match.get("stablecoin"):
56
+ print(f"Stablecoin pool: {match.get('id')} - APY: {match.get('apy')}%")
72
57
  else:
73
58
  print(f"Error: {data}")
74
59
  ```
@@ -3,7 +3,6 @@ from typing import Any
3
3
  from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
4
4
  from wayfinder_paths.core.clients.PoolClient import (
5
5
  LlamaMatch,
6
- LlamaReport,
7
6
  PoolClient,
8
7
  PoolList,
9
8
  )
@@ -31,29 +30,25 @@ class PoolAdapter(BaseAdapter):
31
30
  self.pool_client = pool_client or PoolClient()
32
31
 
33
32
  async def get_pools_by_ids(
34
- self, pool_ids: list[str], merge_external: bool | None = None
33
+ self, pool_ids: list[str]
35
34
  ) -> tuple[bool, PoolList | str]:
36
35
  """
37
36
  Get pool information by pool IDs.
38
37
 
39
38
  Args:
40
39
  pool_ids: List of pool identifiers
41
- merge_external: Whether to merge external data
42
40
 
43
41
  Returns:
44
42
  Tuple of (success, data) where data is pool information or error message
45
43
  """
46
44
  try:
47
- pool_ids_str = ",".join(pool_ids)
48
- data = await self.pool_client.get_pools_by_ids(
49
- pool_ids=pool_ids_str, merge_external=merge_external
50
- )
45
+ data = await self.pool_client.get_pools_by_ids(pool_ids=pool_ids)
51
46
  return (True, data)
52
47
  except Exception as e:
53
48
  self.logger.error(f"Error fetching pools by IDs: {e}")
54
49
  return (False, str(e))
55
50
 
56
- async def get_llama_matches(self) -> tuple[bool, dict[str, LlamaMatch] | str]:
51
+ async def get_pools(self) -> tuple[bool, dict[str, LlamaMatch] | str]:
57
52
  """
58
53
  Get Llama protocol matches for pools.
59
54
 
@@ -61,28 +56,8 @@ class PoolAdapter(BaseAdapter):
61
56
  Tuple of (success, data) where data is Llama matches or error message
62
57
  """
63
58
  try:
64
- data = await self.pool_client.get_llama_matches()
59
+ data = await self.pool_client.get_pools()
65
60
  return (True, data)
66
61
  except Exception as e:
67
62
  self.logger.error(f"Error fetching Llama matches: {e}")
68
63
  return (False, str(e))
69
-
70
- async def get_llama_reports(
71
- self, identifiers: list[str]
72
- ) -> tuple[bool, dict[str, LlamaReport] | str]:
73
- """
74
- Get Llama reports for specific identifiers.
75
-
76
- Args:
77
- identifiers: List of identifiers (token IDs, addresses, pool IDs)
78
-
79
- Returns:
80
- Tuple of (success, data) where data is Llama reports or error message
81
- """
82
- try:
83
- identifiers_str = ",".join(identifiers)
84
- data = await self.pool_client.get_llama_reports(identifiers=identifiers_str)
85
- return (True, data)
86
- except Exception as e:
87
- self.logger.error(f"Error fetching Llama reports: {e}")
88
- return (False, str(e))
@@ -2,8 +2,7 @@
2
2
  "get_pools_by_ids": {
3
3
  "description": "Get pool information by pool IDs",
4
4
  "input": {
5
- "pool_ids": ["pool-123", "pool-456"],
6
- "merge_external": true
5
+ "pool_ids": ["pool-123", "pool-456"]
7
6
  },
8
7
  "output": {
9
8
  "success": true,
@@ -21,7 +20,7 @@
21
20
  }
22
21
  }
23
22
  },
24
- "get_llama_matches": {
23
+ "get_pools": {
25
24
  "description": "Get Llama protocol matches for pools",
26
25
  "input": {},
27
26
  "output": {
@@ -30,10 +29,10 @@
30
29
  "matches": [
31
30
  {
32
31
  "id": "pool-123",
33
- "llama_apy_pct": 5.2,
34
- "llama_tvl_usd": 1000000,
35
- "llama_stablecoin": true,
36
- "llama_il_risk": "no",
32
+ "apy": 5.2,
33
+ "tvlUsd": 1000000,
34
+ "stablecoin": true,
35
+ "ilRisk": "no",
37
36
  "network": "base"
38
37
  }
39
38
  ]
@@ -38,33 +38,33 @@ class TestPoolAdapter:
38
38
  mock_pool_client.get_pools_by_ids = AsyncMock(return_value=mock_response)
39
39
 
40
40
  success, data = await adapter.get_pools_by_ids(
41
- pool_ids=["pool-123", "pool-456"], merge_external=True
41
+ pool_ids=["pool-123", "pool-456"]
42
42
  )
43
43
 
44
44
  assert success is True
45
45
  assert data == mock_response
46
46
  mock_pool_client.get_pools_by_ids.assert_called_once_with(
47
- pool_ids="pool-123,pool-456", merge_external=True
47
+ pool_ids=["pool-123", "pool-456"]
48
48
  )
49
49
 
50
50
  @pytest.mark.asyncio
51
- async def test_get_llama_matches_success(self, adapter, mock_pool_client):
51
+ async def test_get_pools_success(self, adapter, mock_pool_client):
52
52
  """Test successful Llama matches retrieval"""
53
53
  # Mock response
54
54
  mock_response = {
55
55
  "matches": [
56
56
  {
57
57
  "id": "pool-123",
58
- "llama_apy_pct": 5.2,
59
- "llama_tvl_usd": 1000000,
60
- "llama_stablecoin": True,
58
+ "apy": 5.2,
59
+ "tvlUsd": 1000000,
60
+ "stablecoin": True,
61
61
  "network": "base",
62
62
  }
63
63
  ]
64
64
  }
65
- mock_pool_client.get_llama_matches = AsyncMock(return_value=mock_response)
65
+ mock_pool_client.get_pools = AsyncMock(return_value=mock_response)
66
66
 
67
- success, data = await adapter.get_llama_matches()
67
+ success, data = await adapter.get_pools()
68
68
 
69
69
  assert success is True
70
70
  assert data == mock_response
@@ -4,7 +4,7 @@ from typing import Any
4
4
  from loguru import logger
5
5
 
6
6
  from wayfinder_paths.core.clients.WayfinderClient import WayfinderClient
7
- from wayfinder_paths.core.settings import settings
7
+ from wayfinder_paths.core.config import get_api_base_url
8
8
 
9
9
 
10
10
  class AuthClient(WayfinderClient):
@@ -18,7 +18,7 @@ class AuthClient(WayfinderClient):
18
18
  """
19
19
  super().__init__(api_key=api_key)
20
20
 
21
- self.api_base_url = f"{settings.WAYFINDER_API_URL}"
21
+ self.api_base_url = get_api_base_url()
22
22
  self.logger = logger.bind(client="AuthClient")
23
23
 
24
24
  def _is_using_api_key(self) -> bool:
@@ -12,7 +12,7 @@ from loguru import logger
12
12
 
13
13
  from wayfinder_paths.core.clients.AuthClient import AuthClient
14
14
  from wayfinder_paths.core.clients.WayfinderClient import WayfinderClient
15
- from wayfinder_paths.core.settings import settings
15
+ from wayfinder_paths.core.config import get_api_base_url
16
16
 
17
17
 
18
18
  class BRAPQuote(TypedDict):
@@ -38,7 +38,7 @@ class BRAPClient(WayfinderClient):
38
38
 
39
39
  def __init__(self, api_key: str | None = None):
40
40
  super().__init__(api_key=api_key)
41
- self.api_base_url = f"{settings.WAYFINDER_API_URL}"
41
+ self.api_base_url = get_api_base_url()
42
42
  self._auth_client: AuthClient | None = AuthClient(api_key=api_key)
43
43
 
44
44
  async def get_quote(
@@ -8,7 +8,7 @@ from __future__ import annotations
8
8
  from typing import Any, NotRequired, Required, TypedDict
9
9
 
10
10
  from wayfinder_paths.core.clients.WayfinderClient import WayfinderClient
11
- from wayfinder_paths.core.settings import settings
11
+ from wayfinder_paths.core.config import get_api_base_url
12
12
 
13
13
 
14
14
  class StableMarket(TypedDict):
@@ -55,7 +55,7 @@ class HyperlendClient(WayfinderClient):
55
55
 
56
56
  def __init__(self, api_key: str | None = None):
57
57
  super().__init__(api_key=api_key)
58
- self.api_base_url = f"{settings.WAYFINDER_API_URL}"
58
+ self.api_base_url = get_api_base_url()
59
59
 
60
60
  async def get_stable_markets(
61
61
  self,