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.
- wayfinder_paths/adapters/balance_adapter/adapter.py +3 -7
- wayfinder_paths/adapters/brap_adapter/adapter.py +10 -13
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +6 -9
- wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +1 -1
- wayfinder_paths/adapters/hyperliquid_adapter/executor.py +44 -5
- wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +104 -0
- wayfinder_paths/adapters/moonwell_adapter/adapter.py +0 -3
- wayfinder_paths/adapters/pool_adapter/README.md +4 -19
- wayfinder_paths/adapters/pool_adapter/adapter.py +4 -29
- wayfinder_paths/adapters/pool_adapter/examples.json +6 -7
- wayfinder_paths/adapters/pool_adapter/test_adapter.py +8 -8
- wayfinder_paths/core/clients/AuthClient.py +2 -2
- wayfinder_paths/core/clients/BRAPClient.py +2 -2
- wayfinder_paths/core/clients/HyperlendClient.py +2 -2
- wayfinder_paths/core/clients/PoolClient.py +18 -54
- wayfinder_paths/core/clients/TokenClient.py +3 -3
- wayfinder_paths/core/clients/WalletClient.py +2 -2
- wayfinder_paths/core/clients/WayfinderClient.py +9 -10
- wayfinder_paths/core/clients/protocols.py +1 -7
- wayfinder_paths/core/config.py +60 -224
- wayfinder_paths/core/services/local_evm_txn.py +22 -4
- wayfinder_paths/core/strategies/Strategy.py +3 -3
- wayfinder_paths/core/strategies/descriptors.py +7 -0
- wayfinder_paths/core/utils/evm_helpers.py +5 -1
- wayfinder_paths/core/utils/wallets.py +12 -19
- wayfinder_paths/core/wallets/README.md +1 -1
- wayfinder_paths/run_strategy.py +10 -8
- wayfinder_paths/scripts/create_strategy.py +5 -5
- wayfinder_paths/scripts/make_wallets.py +5 -5
- wayfinder_paths/scripts/run_strategy.py +3 -3
- wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +1 -1
- wayfinder_paths/strategies/basis_trading_strategy/strategy.py +196 -515
- wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +228 -11
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +2 -2
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +1 -0
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +1 -1
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +8 -7
- wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +2 -2
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +25 -25
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +28 -9
- wayfinder_paths/templates/adapter/README.md +1 -1
- {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/METADATA +9 -12
- {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/RECORD +45 -45
- wayfinder_paths/core/settings.py +0 -61
- {wayfinder_paths-0.1.11.dist-info → wayfinder_paths-0.1.13.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.11.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.
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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"{
|
|
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.
|
|
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"{
|
|
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"{
|
|
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.
|
|
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 =
|
|
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"{
|
|
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
|
|
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"{
|
|
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.
|
|
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(
|
|
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
|
|
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
|
|
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"{
|
|
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
|
|
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"""
|