wayfinder-paths 0.1.10__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 (49) 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/base.py +0 -55
  22. wayfinder_paths/core/services/local_evm_txn.py +37 -134
  23. wayfinder_paths/core/strategies/Strategy.py +3 -3
  24. wayfinder_paths/core/strategies/descriptors.py +7 -0
  25. wayfinder_paths/core/utils/evm_helpers.py +5 -28
  26. wayfinder_paths/core/utils/wallets.py +12 -19
  27. wayfinder_paths/core/wallets/README.md +1 -1
  28. wayfinder_paths/run_strategy.py +10 -8
  29. wayfinder_paths/scripts/create_strategy.py +5 -5
  30. wayfinder_paths/scripts/make_wallets.py +5 -5
  31. wayfinder_paths/scripts/run_strategy.py +3 -3
  32. wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +1 -1
  33. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +196 -515
  34. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +228 -11
  35. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +2 -2
  36. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +1 -0
  37. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +1 -1
  38. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +8 -7
  39. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +2 -2
  40. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +25 -25
  41. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +28 -9
  42. wayfinder_paths/templates/adapter/README.md +1 -1
  43. {wayfinder_paths-0.1.10.dist-info → wayfinder_paths-0.1.13.dist-info}/METADATA +15 -18
  44. {wayfinder_paths-0.1.10.dist-info → wayfinder_paths-0.1.13.dist-info}/RECORD +46 -48
  45. wayfinder_paths/CONFIG_GUIDE.md +0 -390
  46. wayfinder_paths/config.example.json +0 -22
  47. wayfinder_paths/core/settings.py +0 -61
  48. {wayfinder_paths-0.1.10.dist-info → wayfinder_paths-0.1.13.dist-info}/LICENSE +0 -0
  49. {wayfinder_paths-0.1.10.dist-info → wayfinder_paths-0.1.13.dist-info}/WHEEL +0 -0
@@ -9,7 +9,7 @@ from typing import Any, NotRequired, Required, TypedDict
9
9
 
10
10
  from wayfinder_paths.core.clients.AuthClient import AuthClient
11
11
  from wayfinder_paths.core.clients.WayfinderClient import WayfinderClient
12
- from wayfinder_paths.core.settings import settings
12
+ from wayfinder_paths.core.config import get_api_base_url
13
13
 
14
14
 
15
15
  class PoolData(TypedDict):
@@ -23,10 +23,10 @@ class PoolData(TypedDict):
23
23
  chain_code: Required[str]
24
24
  apy: NotRequired[float]
25
25
  tvl: NotRequired[float]
26
- llama_apy_pct: NotRequired[float | None]
27
- llama_tvl_usd: NotRequired[float | None]
28
- llama_stablecoin: NotRequired[bool | None]
29
- llama_il_risk: NotRequired[str | None]
26
+ apy: NotRequired[float | None]
27
+ tvlUsd: NotRequired[float | None]
28
+ stablecoin: NotRequired[bool | None]
29
+ ilRisk: NotRequired[str | None]
30
30
  network: NotRequired[str | None]
31
31
 
32
32
 
@@ -41,71 +41,35 @@ class LlamaMatch(TypedDict):
41
41
  """Llama match data structure"""
42
42
 
43
43
  id: Required[str]
44
- llama_apy_pct: Required[float]
45
- llama_tvl_usd: Required[float]
46
- llama_stablecoin: Required[bool]
47
- llama_il_risk: Required[str]
44
+ apy: Required[float]
45
+ tvlUsd: Required[float]
46
+ stablecoin: Required[bool]
47
+ ilRisk: Required[str]
48
48
  network: Required[str]
49
49
 
50
50
 
51
- class LlamaReport(TypedDict):
52
- """Llama report data structure"""
53
-
54
- identifier: Required[str]
55
- apy: NotRequired[float | None]
56
- tvl: NotRequired[float | None]
57
-
58
-
59
51
  class PoolClient(WayfinderClient):
60
52
  """Client for pool-related read operations"""
61
53
 
62
54
  def __init__(self, api_key: str | None = None):
63
55
  super().__init__(api_key=api_key)
64
- self.api_base_url = f"{settings.WAYFINDER_API_URL}"
56
+ self.api_base_url = f"{get_api_base_url()}"
65
57
  self._auth_client: AuthClient | None = AuthClient(api_key=api_key)
66
58
 
59
+ async def get_pools(self) -> dict[str, LlamaMatch]:
60
+ url = f"{self.api_base_url}/pools/"
61
+ response = await self._request("GET", url, headers={})
62
+ response.raise_for_status()
63
+ data = response.json()
64
+ return data.get("data", data)
65
+
67
66
  async def get_pools_by_ids(
68
67
  self,
69
68
  *,
70
69
  pool_ids: str,
71
- merge_external: bool | None = None,
72
70
  ) -> PoolList:
73
- """
74
- Fetch pools by comma-separated pool ids.
75
-
76
- Example:
77
- GET /api/v1/public/pools/?pool_ids=a,b&merge_external=false
78
- """
79
- url = f"{self.api_base_url}/public/pools/"
71
+ url = f"{self.api_base_url}/pools/"
80
72
  params: dict[str, Any] = {"pool_ids": pool_ids}
81
- if merge_external is not None:
82
- params["merge_external"] = "true" if merge_external else "false"
83
- response = await self._request("GET", url, params=params, headers={})
84
- response.raise_for_status()
85
- data = response.json()
86
- return data.get("data", data)
87
-
88
- async def get_llama_matches(self) -> dict[str, LlamaMatch]:
89
- """
90
- Fetch Llama matches for pools.
91
-
92
- GET /api/v1/public/pools/llama/matches/
93
- """
94
- url = f"{self.api_base_url}/public/pools/llama/matches/"
95
- response = await self._request("GET", url, headers={})
96
- response.raise_for_status()
97
- data = response.json()
98
- return data.get("data", data)
99
-
100
- async def get_llama_reports(self, *, identifiers: str) -> dict[str, LlamaReport]:
101
- """
102
- Fetch Llama reports using identifiers (token ids, address_network, or pool ids).
103
-
104
- Example:
105
- GET /api/v1/public/pools/llama/reports/?identifiers=pool-1,usd-coin
106
- """
107
- url = f"{self.api_base_url}/public/pools/llama/reports/"
108
- params = {"identifiers": identifiers}
109
73
  response = await self._request("GET", url, params=params, headers={})
110
74
  response.raise_for_status()
111
75
  data = response.json()
@@ -9,7 +9,7 @@ from typing import NotRequired, Required, TypedDict
9
9
 
10
10
  from wayfinder_paths.core.clients.AuthClient import AuthClient
11
11
  from wayfinder_paths.core.clients.WayfinderClient import WayfinderClient
12
- from wayfinder_paths.core.settings import settings
12
+ from wayfinder_paths.core.config import get_api_base_url
13
13
 
14
14
 
15
15
  class TokenDetails(TypedDict):
@@ -63,7 +63,7 @@ class TokenClient(WayfinderClient):
63
63
  Returns:
64
64
  Full token data including price information
65
65
  """
66
- url = f"{settings.WAYFINDER_API_URL}/public/tokens/detail/"
66
+ url = f"{get_api_base_url()}/public/tokens/detail/"
67
67
  params = {
68
68
  "query": token_id,
69
69
  "get_chart": "false",
@@ -80,7 +80,7 @@ class TokenClient(WayfinderClient):
80
80
  Fetch the native gas token for a given chain code via public endpoint.
81
81
  Example: GET /api/v1/public/tokens/gas/?chain_code=base
82
82
  """
83
- url = f"{settings.WAYFINDER_API_URL}/public/tokens/gas/"
83
+ url = f"{get_api_base_url()}/public/tokens/gas/"
84
84
  params = {"chain_code": chain_code}
85
85
  # Public endpoint: do not pass auth headers
86
86
  response = await self._request("GET", url, params=params, headers={})
@@ -9,7 +9,7 @@ from typing import NotRequired, Required, TypedDict
9
9
 
10
10
  from wayfinder_paths.core.clients.AuthClient import AuthClient
11
11
  from wayfinder_paths.core.clients.WayfinderClient import WayfinderClient
12
- from wayfinder_paths.core.settings import settings
12
+ from wayfinder_paths.core.config import get_api_base_url
13
13
 
14
14
 
15
15
  class TokenBalance(TypedDict):
@@ -36,7 +36,7 @@ class PoolBalance(TypedDict):
36
36
  class WalletClient(WayfinderClient):
37
37
  def __init__(self, api_key: str | None = None):
38
38
  super().__init__(api_key=api_key)
39
- self.api_base_url = f"{settings.WAYFINDER_API_URL}"
39
+ self.api_base_url = get_api_base_url()
40
40
  self._auth_client = AuthClient(api_key=api_key)
41
41
 
42
42
  async def get_token_balance_for_wallet(
@@ -6,8 +6,8 @@ from typing import Any
6
6
  import httpx
7
7
  from loguru import logger
8
8
 
9
+ from wayfinder_paths.core.config import get_api_base_url
9
10
  from wayfinder_paths.core.constants.base import DEFAULT_HTTP_TIMEOUT
10
- from wayfinder_paths.core.settings import settings
11
11
 
12
12
 
13
13
  class WayfinderClient:
@@ -19,7 +19,7 @@ class WayfinderClient:
19
19
  api_key: Optional API key for service account authentication.
20
20
  If provided, uses API key auth. Otherwise falls back to config.json.
21
21
  """
22
- self.api_base_url = f"{settings.WAYFINDER_API_URL}/"
22
+ self.api_base_url = f"{get_api_base_url()}/"
23
23
  timeout = httpx.Timeout(DEFAULT_HTTP_TIMEOUT)
24
24
  self.client = httpx.AsyncClient(timeout=timeout)
25
25
 
@@ -33,7 +33,7 @@ class WayfinderClient:
33
33
 
34
34
  def set_bearer_token(self, token: str) -> None:
35
35
  """
36
- Set runtime OAuth/JWT Bearer token for Django-backed Wayfinder services.
36
+ Set runtime OAuth/JWT Bearer token for Wayfinder services.
37
37
  """
38
38
  self.headers["Authorization"] = f"Bearer {token}"
39
39
  self._access_token = token
@@ -57,7 +57,7 @@ class WayfinderClient:
57
57
  try:
58
58
  logger.info("Attempting to refresh access token")
59
59
  start_time = time.time()
60
- url = f"{settings.WAYFINDER_API_URL}/auth/token/refresh/"
60
+ url = f"{get_api_base_url()}/auth/token/refresh/"
61
61
  payload = {"refresh": self._refresh_token}
62
62
  response = await self.client.post(
63
63
  url, json=payload, headers={"Content-Type": "application/json"}
@@ -83,16 +83,15 @@ class WayfinderClient:
83
83
 
84
84
  def _load_config_credentials(self) -> dict[str, str | None]:
85
85
  """
86
- Load credentials from config.json. Path can be overridden via WAYFINDER_CONFIG_PATH.
86
+ Load credentials from config.json.
87
87
  Expected shape:
88
88
  {
89
89
  "user": { "username": ..., "password": ..., "refresh_token": ..., "api_key": ... },
90
90
  "system": { "api_key": ... }
91
91
  }
92
92
  """
93
- path = os.getenv("WAYFINDER_CONFIG_PATH", "config.json")
94
93
  try:
95
- with open(path) as f:
94
+ with open("config.json") as f:
96
95
  cfg = json.load(f)
97
96
  user = cfg.get("user", {}) if isinstance(cfg, dict) else {}
98
97
  system = cfg.get("system", {}) if isinstance(cfg, dict) else {}
@@ -103,7 +102,7 @@ class WayfinderClient:
103
102
  "api_key": user.get("api_key") or system.get("api_key"),
104
103
  }
105
104
  except (FileNotFoundError, json.JSONDecodeError, OSError) as e:
106
- logger.debug(f"Could not load config file at {path}: {e}")
105
+ logger.debug(f"Could not load config file at config.json: {e}")
107
106
  return {
108
107
  "username": None,
109
108
  "password": None,
@@ -111,7 +110,7 @@ class WayfinderClient:
111
110
  "api_key": None,
112
111
  }
113
112
  except Exception as e:
114
- logger.warning(f"Unexpected error loading config file at {path}: {e}")
113
+ logger.warning(f"Unexpected error loading config file at config.json: {e}")
115
114
  return {
116
115
  "username": None,
117
116
  "password": None,
@@ -155,7 +154,7 @@ class WayfinderClient:
155
154
 
156
155
  if username and password:
157
156
  try:
158
- url = f"{settings.WAYFINDER_API_URL}/auth/token/"
157
+ url = f"{get_api_base_url()}/auth/token/"
159
158
  payload = {"username": username, "password": password}
160
159
  response = await self.client.post(
161
160
  url,
@@ -25,7 +25,6 @@ if TYPE_CHECKING:
25
25
  )
26
26
  from wayfinder_paths.core.clients.PoolClient import (
27
27
  LlamaMatch,
28
- LlamaReport,
29
28
  PoolList,
30
29
  )
31
30
  from wayfinder_paths.core.clients.TokenClient import (
@@ -191,19 +190,14 @@ class PoolClientProtocol(Protocol):
191
190
  self,
192
191
  *,
193
192
  pool_ids: str,
194
- merge_external: bool | None = None,
195
193
  ) -> PoolList:
196
194
  """Fetch pools by comma-separated pool ids"""
197
195
  ...
198
196
 
199
- async def get_llama_matches(self) -> dict[str, LlamaMatch]:
197
+ async def get_pools(self) -> dict[str, LlamaMatch]:
200
198
  """Fetch Llama matches for pools"""
201
199
  ...
202
200
 
203
- async def get_llama_reports(self, *, identifiers: str) -> dict[str, LlamaReport]:
204
- """Fetch Llama reports using identifiers"""
205
- ...
206
-
207
201
 
208
202
  class BRAPClientProtocol(Protocol):
209
203
  """Protocol for BRAP (Bridge/Router/Adapter Protocol) quote operations"""