wayfinder-paths 0.1.7__py3-none-any.whl → 0.1.8__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/brap_adapter/adapter.py +1 -2
- wayfinder_paths/adapters/brap_adapter/test_adapter.py +5 -7
- wayfinder_paths/adapters/ledger_adapter/test_adapter.py +3 -0
- wayfinder_paths/adapters/pool_adapter/README.md +3 -28
- wayfinder_paths/adapters/pool_adapter/adapter.py +0 -72
- wayfinder_paths/adapters/pool_adapter/examples.json +0 -43
- wayfinder_paths/adapters/pool_adapter/test_adapter.py +0 -48
- wayfinder_paths/core/clients/BRAPClient.py +1 -0
- wayfinder_paths/core/clients/PoolClient.py +0 -16
- wayfinder_paths/core/clients/protocols.py +0 -4
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +40 -13
- {wayfinder_paths-0.1.7.dist-info → wayfinder_paths-0.1.8.dist-info}/METADATA +31 -3
- {wayfinder_paths-0.1.7.dist-info → wayfinder_paths-0.1.8.dist-info}/RECORD +15 -15
- {wayfinder_paths-0.1.7.dist-info → wayfinder_paths-0.1.8.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.7.dist-info → wayfinder_paths-0.1.8.dist-info}/WHEEL +0 -0
|
@@ -147,8 +147,7 @@ class BRAPAdapter(BaseAdapter):
|
|
|
147
147
|
)
|
|
148
148
|
|
|
149
149
|
# Extract best quote from response
|
|
150
|
-
|
|
151
|
-
best_quote = quotes.get("best_quote")
|
|
150
|
+
best_quote = data["best_route"]
|
|
152
151
|
|
|
153
152
|
if not best_quote:
|
|
154
153
|
return (False, "No quotes available")
|
|
@@ -81,12 +81,10 @@ class TestBRAPAdapter:
|
|
|
81
81
|
async def test_get_best_quote_success(self, adapter, mock_brap_client):
|
|
82
82
|
"""Test successful best quote retrieval"""
|
|
83
83
|
mock_response = {
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"total_fee": "8000000000000000",
|
|
89
|
-
}
|
|
84
|
+
"best_route": {
|
|
85
|
+
"input_amount": "1000000000000000000",
|
|
86
|
+
"output_amount": "995000000000000000",
|
|
87
|
+
"total_fee": "8000000000000000",
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
mock_brap_client.get_quote = AsyncMock(return_value=mock_response)
|
|
@@ -108,7 +106,7 @@ class TestBRAPAdapter:
|
|
|
108
106
|
@pytest.mark.asyncio
|
|
109
107
|
async def test_get_best_quote_no_quotes(self, adapter, mock_brap_client):
|
|
110
108
|
"""Test best quote retrieval when no quotes available"""
|
|
111
|
-
mock_response = {"
|
|
109
|
+
mock_response = {"best_route": None}
|
|
112
110
|
mock_brap_client.get_quote = AsyncMock(return_value=mock_response)
|
|
113
111
|
|
|
114
112
|
success, data = await adapter.get_best_quote(
|
|
@@ -159,12 +159,15 @@ class TestLedgerAdapter:
|
|
|
159
159
|
|
|
160
160
|
# Test
|
|
161
161
|
operation_data = SWAP(
|
|
162
|
+
adapter="TestAdapter",
|
|
162
163
|
from_token_id="0xA0b86a33E6441c8C06DdD4D4c4c4c4c4c4c4c4c4c",
|
|
163
164
|
to_token_id="0xB1c97a44F7552d9Dd5e5e5e5e5e5e5e5e5e5e5e5e5e",
|
|
164
165
|
from_amount="1000000000000000000",
|
|
165
166
|
to_amount="995000000000000000",
|
|
166
167
|
from_amount_usd=1000.0,
|
|
167
168
|
to_amount_usd=995.0,
|
|
169
|
+
transaction_hash="0x123abc",
|
|
170
|
+
transaction_chain_id=8453,
|
|
168
171
|
)
|
|
169
172
|
|
|
170
173
|
success, data = await adapter.record_operation(
|
|
@@ -15,6 +15,7 @@ A Wayfinder adapter that provides high-level operations for DeFi pool data and a
|
|
|
15
15
|
The adapter uses the PoolClient which automatically handles authentication and API configuration through the Wayfinder settings. No additional configuration is required.
|
|
16
16
|
|
|
17
17
|
The PoolClient will automatically:
|
|
18
|
+
|
|
18
19
|
- Use the WAYFINDER_API_URL from settings
|
|
19
20
|
- Handle authentication via environment variables or config.json
|
|
20
21
|
- Manage token refresh and retry logic
|
|
@@ -44,17 +45,6 @@ else:
|
|
|
44
45
|
print(f"Error: {data}")
|
|
45
46
|
```
|
|
46
47
|
|
|
47
|
-
### Get All Pools
|
|
48
|
-
|
|
49
|
-
```python
|
|
50
|
-
success, data = await adapter.get_all_pools(merge_external=False)
|
|
51
|
-
if success:
|
|
52
|
-
pools = data.get("pools", [])
|
|
53
|
-
print(f"Total pools available: {len(pools)}")
|
|
54
|
-
else:
|
|
55
|
-
print(f"Error: {data}")
|
|
56
|
-
```
|
|
57
|
-
|
|
58
48
|
### Find High Yield Pools
|
|
59
49
|
|
|
60
50
|
```python
|
|
@@ -90,22 +80,6 @@ else:
|
|
|
90
80
|
print(f"Error: {data}")
|
|
91
81
|
```
|
|
92
82
|
|
|
93
|
-
### Search Pools
|
|
94
|
-
|
|
95
|
-
```python
|
|
96
|
-
success, data = await adapter.search_pools(
|
|
97
|
-
query="USDC",
|
|
98
|
-
limit=10
|
|
99
|
-
)
|
|
100
|
-
if success:
|
|
101
|
-
pools = data.get("pools", [])
|
|
102
|
-
print(f"Found {len(pools)} pools matching 'USDC'")
|
|
103
|
-
for pool in pools:
|
|
104
|
-
print(f"Pool: {pool.get('name')} - {pool.get('symbol')}")
|
|
105
|
-
else:
|
|
106
|
-
print(f"Error: {data}")
|
|
107
|
-
```
|
|
108
|
-
|
|
109
83
|
### Get Llama Matches
|
|
110
84
|
|
|
111
85
|
```python
|
|
@@ -168,7 +142,7 @@ if success:
|
|
|
168
142
|
for pool_analytics in analytics:
|
|
169
143
|
pool = pool_analytics.get("pool", {})
|
|
170
144
|
llama_data = pool_analytics.get("llama_data", {})
|
|
171
|
-
|
|
145
|
+
|
|
172
146
|
print(f"Pool: {pool.get('name')}")
|
|
173
147
|
print(f" Combined APY: {pool_analytics.get('combined_apy', 0):.2%}")
|
|
174
148
|
print(f" TVL: ${pool_analytics.get('tvl_usd', 0):,.0f}")
|
|
@@ -189,6 +163,7 @@ The adapter uses the following Wayfinder API endpoints:
|
|
|
189
163
|
## Error Handling
|
|
190
164
|
|
|
191
165
|
All methods return a tuple of `(success: bool, data: Any)` where:
|
|
166
|
+
|
|
192
167
|
- `success` is `True` if the operation succeeded
|
|
193
168
|
- `data` contains the response data on success or error message on failure
|
|
194
169
|
|
|
@@ -53,25 +53,6 @@ class PoolAdapter(BaseAdapter):
|
|
|
53
53
|
self.logger.error(f"Error fetching pools by IDs: {e}")
|
|
54
54
|
return (False, str(e))
|
|
55
55
|
|
|
56
|
-
async def get_all_pools(
|
|
57
|
-
self, merge_external: bool | None = None
|
|
58
|
-
) -> tuple[bool, PoolList | str]:
|
|
59
|
-
"""
|
|
60
|
-
Get all available pools.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
merge_external: Whether to merge external data
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
Tuple of (success, data) where data is all pools or error message
|
|
67
|
-
"""
|
|
68
|
-
try:
|
|
69
|
-
data = await self.pool_client.get_all_pools(merge_external=merge_external)
|
|
70
|
-
return (True, data)
|
|
71
|
-
except Exception as e:
|
|
72
|
-
self.logger.error(f"Error fetching all pools: {e}")
|
|
73
|
-
return (False, str(e))
|
|
74
|
-
|
|
75
56
|
async def get_llama_matches(self) -> tuple[bool, dict[str, LlamaMatch] | str]:
|
|
76
57
|
"""
|
|
77
58
|
Get Llama protocol matches for pools.
|
|
@@ -227,56 +208,3 @@ class PoolAdapter(BaseAdapter):
|
|
|
227
208
|
except Exception as e:
|
|
228
209
|
self.logger.error(f"Error getting pool analytics: {e}")
|
|
229
210
|
return (False, str(e))
|
|
230
|
-
|
|
231
|
-
async def search_pools(self, query: str, limit: int = 10) -> tuple[bool, Any]:
|
|
232
|
-
"""
|
|
233
|
-
Search pools by name, symbol, or other criteria.
|
|
234
|
-
|
|
235
|
-
Args:
|
|
236
|
-
query: Search query string
|
|
237
|
-
limit: Maximum number of results
|
|
238
|
-
|
|
239
|
-
Returns:
|
|
240
|
-
Tuple of (success, data) where data is search results or error message
|
|
241
|
-
"""
|
|
242
|
-
try:
|
|
243
|
-
success, all_pools_data = await self.get_all_pools()
|
|
244
|
-
if not success:
|
|
245
|
-
return (False, f"Failed to fetch pools: {all_pools_data}")
|
|
246
|
-
|
|
247
|
-
pools = all_pools_data.get("pools", [])
|
|
248
|
-
query_lower = query.lower()
|
|
249
|
-
|
|
250
|
-
# Simple text search
|
|
251
|
-
matching_pools = []
|
|
252
|
-
for pool in pools:
|
|
253
|
-
name = pool.get("name", "").lower()
|
|
254
|
-
symbol = pool.get("symbol", "").lower()
|
|
255
|
-
description = pool.get("description", "").lower()
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
query_lower in name
|
|
259
|
-
or query_lower in symbol
|
|
260
|
-
or query_lower in description
|
|
261
|
-
):
|
|
262
|
-
matching_pools.append(pool)
|
|
263
|
-
|
|
264
|
-
# Sort by relevance (exact matches first)
|
|
265
|
-
matching_pools.sort(
|
|
266
|
-
key=lambda x: (
|
|
267
|
-
query_lower not in x.get("name", "").lower(),
|
|
268
|
-
query_lower not in x.get("symbol", "").lower(),
|
|
269
|
-
)
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
return (
|
|
273
|
-
True,
|
|
274
|
-
{
|
|
275
|
-
"pools": matching_pools[:limit],
|
|
276
|
-
"total_found": len(matching_pools),
|
|
277
|
-
"query": query,
|
|
278
|
-
},
|
|
279
|
-
)
|
|
280
|
-
except Exception as e:
|
|
281
|
-
self.logger.error(f"Error searching pools: {e}")
|
|
282
|
-
return (False, str(e))
|
|
@@ -21,27 +21,6 @@
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
|
-
"get_all_pools": {
|
|
25
|
-
"description": "Get all available pools",
|
|
26
|
-
"input": {
|
|
27
|
-
"merge_external": false
|
|
28
|
-
},
|
|
29
|
-
"output": {
|
|
30
|
-
"success": true,
|
|
31
|
-
"data": {
|
|
32
|
-
"pools": [
|
|
33
|
-
{
|
|
34
|
-
"id": "pool-123",
|
|
35
|
-
"name": "USDC/USDT Pool",
|
|
36
|
-
"symbol": "USDC-USDT",
|
|
37
|
-
"apy": 0.05,
|
|
38
|
-
"tvl": 1000000
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"total": 1
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
24
|
"get_llama_matches": {
|
|
46
25
|
"description": "Get Llama protocol matches for pools",
|
|
47
26
|
"input": {},
|
|
@@ -117,27 +96,5 @@
|
|
|
117
96
|
"total_pools": 1
|
|
118
97
|
}
|
|
119
98
|
}
|
|
120
|
-
},
|
|
121
|
-
"search_pools": {
|
|
122
|
-
"description": "Search pools by name, symbol, or other criteria",
|
|
123
|
-
"input": {
|
|
124
|
-
"query": "USDC",
|
|
125
|
-
"limit": 5
|
|
126
|
-
},
|
|
127
|
-
"output": {
|
|
128
|
-
"success": true,
|
|
129
|
-
"data": {
|
|
130
|
-
"pools": [
|
|
131
|
-
{
|
|
132
|
-
"id": "pool-123",
|
|
133
|
-
"name": "USDC/USDT Pool",
|
|
134
|
-
"symbol": "USDC-USDT",
|
|
135
|
-
"description": "Stablecoin pool on Base"
|
|
136
|
-
}
|
|
137
|
-
],
|
|
138
|
-
"total_found": 1,
|
|
139
|
-
"query": "USDC"
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
99
|
}
|
|
143
100
|
}
|
|
@@ -47,25 +47,6 @@ class TestPoolAdapter:
|
|
|
47
47
|
pool_ids="pool-123,pool-456", merge_external=True
|
|
48
48
|
)
|
|
49
49
|
|
|
50
|
-
@pytest.mark.asyncio
|
|
51
|
-
async def test_get_all_pools_success(self, adapter, mock_pool_client):
|
|
52
|
-
"""Test successful retrieval of all pools"""
|
|
53
|
-
# Mock response
|
|
54
|
-
mock_response = {
|
|
55
|
-
"pools": [
|
|
56
|
-
{"id": "pool-123", "name": "Pool 1"},
|
|
57
|
-
{"id": "pool-456", "name": "Pool 2"},
|
|
58
|
-
],
|
|
59
|
-
"total": 2,
|
|
60
|
-
}
|
|
61
|
-
mock_pool_client.get_all_pools = AsyncMock(return_value=mock_response)
|
|
62
|
-
|
|
63
|
-
success, data = await adapter.get_all_pools(merge_external=False)
|
|
64
|
-
|
|
65
|
-
assert success is True
|
|
66
|
-
assert data == mock_response
|
|
67
|
-
mock_pool_client.get_all_pools.assert_called_once_with(merge_external=False)
|
|
68
|
-
|
|
69
50
|
@pytest.mark.asyncio
|
|
70
51
|
async def test_get_llama_matches_success(self, adapter, mock_pool_client):
|
|
71
52
|
"""Test successful Llama matches retrieval"""
|
|
@@ -159,35 +140,6 @@ class TestPoolAdapter:
|
|
|
159
140
|
assert round(data["analytics"][0]["combined_apy"], 6) == round(0.052, 6)
|
|
160
141
|
assert data["analytics"][0]["tvl_usd"] == 1000000
|
|
161
142
|
|
|
162
|
-
@pytest.mark.asyncio
|
|
163
|
-
async def test_search_pools_success(self, adapter, mock_pool_client):
|
|
164
|
-
"""Test successful pool search"""
|
|
165
|
-
mock_all_pools = {
|
|
166
|
-
"pools": [
|
|
167
|
-
{
|
|
168
|
-
"id": "pool-123",
|
|
169
|
-
"name": "USDC/USDT Pool",
|
|
170
|
-
"symbol": "USDC-USDT",
|
|
171
|
-
"description": "Stablecoin pool on Base",
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
"id": "pool-456",
|
|
175
|
-
"name": "ETH/WETH Pool",
|
|
176
|
-
"symbol": "ETH-WETH",
|
|
177
|
-
"description": "Ethereum pool",
|
|
178
|
-
},
|
|
179
|
-
]
|
|
180
|
-
}
|
|
181
|
-
mock_pool_client.get_all_pools = AsyncMock(return_value=mock_all_pools)
|
|
182
|
-
|
|
183
|
-
success, data = await adapter.search_pools("USDC", limit=5)
|
|
184
|
-
|
|
185
|
-
assert success is True
|
|
186
|
-
assert len(data["pools"]) == 1
|
|
187
|
-
assert data["pools"][0]["id"] == "pool-123"
|
|
188
|
-
assert data["total_found"] == 1
|
|
189
|
-
assert data["query"] == "USDC"
|
|
190
|
-
|
|
191
143
|
@pytest.mark.asyncio
|
|
192
144
|
async def test_get_pools_by_ids_failure(self, adapter, mock_pool_client):
|
|
193
145
|
"""Test pool retrieval failure"""
|
|
@@ -27,6 +27,7 @@ class BRAPQuote(TypedDict):
|
|
|
27
27
|
amount1: Required[str]
|
|
28
28
|
amount2: NotRequired[str]
|
|
29
29
|
routes: NotRequired[list[dict[str, Any]]]
|
|
30
|
+
best_route: NotRequired[dict[str, Any]]
|
|
30
31
|
fees: NotRequired[dict[str, Any] | None]
|
|
31
32
|
slippage: NotRequired[float | None]
|
|
32
33
|
wayfinder_fee: NotRequired[float | None]
|
|
@@ -85,22 +85,6 @@ class PoolClient(WayfinderClient):
|
|
|
85
85
|
data = response.json()
|
|
86
86
|
return data.get("data", data)
|
|
87
87
|
|
|
88
|
-
async def get_all_pools(self, *, merge_external: bool | None = None) -> PoolList:
|
|
89
|
-
"""
|
|
90
|
-
Fetch all pools.
|
|
91
|
-
|
|
92
|
-
Example:
|
|
93
|
-
GET /api/v1/public/pools/?merge_external=false
|
|
94
|
-
"""
|
|
95
|
-
url = f"{self.api_base_url}/public/pools/"
|
|
96
|
-
params: dict[str, Any] = {}
|
|
97
|
-
if merge_external is not None:
|
|
98
|
-
params["merge_external"] = "true" if merge_external else "false"
|
|
99
|
-
response = await self._request("GET", url, params=params, headers={})
|
|
100
|
-
response.raise_for_status()
|
|
101
|
-
data = response.json()
|
|
102
|
-
return data.get("data", data)
|
|
103
|
-
|
|
104
88
|
async def get_llama_matches(self) -> dict[str, LlamaMatch]:
|
|
105
89
|
"""
|
|
106
90
|
Fetch Llama matches for pools.
|
|
@@ -213,10 +213,6 @@ class PoolClientProtocol(Protocol):
|
|
|
213
213
|
"""Fetch pools by comma-separated pool ids"""
|
|
214
214
|
...
|
|
215
215
|
|
|
216
|
-
async def get_all_pools(self, *, merge_external: bool | None = None) -> PoolList:
|
|
217
|
-
"""Fetch all pools"""
|
|
218
|
-
...
|
|
219
|
-
|
|
220
216
|
async def get_llama_matches(self) -> dict[str, LlamaMatch]:
|
|
221
217
|
"""Fetch Llama matches for pools"""
|
|
222
218
|
...
|
|
@@ -65,6 +65,7 @@ def strategy():
|
|
|
65
65
|
if hasattr(s, "token_adapter") and s.token_adapter:
|
|
66
66
|
default_usdc = {
|
|
67
67
|
"id": "usd-coin-base",
|
|
68
|
+
"token_id": "usd-coin-base",
|
|
68
69
|
"symbol": "USDC",
|
|
69
70
|
"name": "USD Coin",
|
|
70
71
|
"decimals": 6,
|
|
@@ -74,6 +75,7 @@ def strategy():
|
|
|
74
75
|
|
|
75
76
|
default_pool_token = {
|
|
76
77
|
"id": "test-pool-base",
|
|
78
|
+
"token_id": "test-pool-base",
|
|
77
79
|
"symbol": "POOL",
|
|
78
80
|
"name": "Test Pool",
|
|
79
81
|
"decimals": 18,
|
|
@@ -97,6 +99,7 @@ def strategy():
|
|
|
97
99
|
True,
|
|
98
100
|
{
|
|
99
101
|
"id": "ethereum-base",
|
|
102
|
+
"token_id": "ethereum-base",
|
|
100
103
|
"symbol": "ETH",
|
|
101
104
|
"name": "Ethereum",
|
|
102
105
|
"decimals": 18,
|
|
@@ -207,6 +210,7 @@ def strategy():
|
|
|
207
210
|
s.DEPOSIT_USDC = 0
|
|
208
211
|
s.usdc_token_info = {
|
|
209
212
|
"id": "usd-coin-base",
|
|
213
|
+
"token_id": "usd-coin-base",
|
|
210
214
|
"symbol": "USDC",
|
|
211
215
|
"name": "USD Coin",
|
|
212
216
|
"decimals": 6,
|
|
@@ -215,6 +219,7 @@ def strategy():
|
|
|
215
219
|
}
|
|
216
220
|
s.gas_token = {
|
|
217
221
|
"id": "ethereum-base",
|
|
222
|
+
"token_id": "ethereum-base",
|
|
218
223
|
"symbol": "ETH",
|
|
219
224
|
"name": "Ethereum",
|
|
220
225
|
"decimals": 18,
|
|
@@ -223,6 +228,7 @@ def strategy():
|
|
|
223
228
|
}
|
|
224
229
|
s.current_pool = {
|
|
225
230
|
"id": "usd-coin-base",
|
|
231
|
+
"token_id": "usd-coin-base",
|
|
226
232
|
"symbol": "USDC",
|
|
227
233
|
"decimals": 6,
|
|
228
234
|
"chain": {"code": "base", "id": 8453, "name": "Base"},
|
|
@@ -245,9 +251,6 @@ def strategy():
|
|
|
245
251
|
side_effect=get_token_price_side_effect
|
|
246
252
|
)
|
|
247
253
|
|
|
248
|
-
async def mock_sweep_wallet(target_token):
|
|
249
|
-
pass
|
|
250
|
-
|
|
251
254
|
async def mock_refresh_current_pool_balance():
|
|
252
255
|
pass
|
|
253
256
|
|
|
@@ -257,7 +260,6 @@ def strategy():
|
|
|
257
260
|
async def mock_has_idle_assets(balances, target):
|
|
258
261
|
return True
|
|
259
262
|
|
|
260
|
-
s._sweep_wallet = mock_sweep_wallet
|
|
261
263
|
s._refresh_current_pool_balance = mock_refresh_current_pool_balance
|
|
262
264
|
s._rebalance_gas = mock_rebalance_gas
|
|
263
265
|
s._has_idle_assets = mock_has_idle_assets
|
|
@@ -432,17 +434,34 @@ async def test_deposit_tracks_usdc(strategy):
|
|
|
432
434
|
@pytest.mark.asyncio
|
|
433
435
|
async def test_sweep_wallet_uses_tracked_tokens(strategy):
|
|
434
436
|
"""Test that _sweep_wallet only swaps tracked tokens."""
|
|
437
|
+
# Import the real implementation to restore it
|
|
438
|
+
from wayfinder_paths.strategies.stablecoin_yield_strategy.strategy import (
|
|
439
|
+
StablecoinYieldStrategy,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
# Restore the real _sweep_wallet method (fixture mocks it as a no-op)
|
|
443
|
+
strategy._sweep_wallet = StablecoinYieldStrategy._sweep_wallet.__get__(
|
|
444
|
+
strategy, StablecoinYieldStrategy
|
|
445
|
+
)
|
|
446
|
+
|
|
435
447
|
# Setup: track some tokens with balances
|
|
436
448
|
strategy._track_token("token-1", 1000000)
|
|
437
449
|
strategy._track_token("token-2", 2000000)
|
|
438
450
|
|
|
451
|
+
# Track the actual token IDs to avoid issues with gas token
|
|
452
|
+
# Make sure we're not accidentally matching gas token
|
|
453
|
+
assert "token-1" in strategy.tracked_token_ids
|
|
454
|
+
assert "token-2" in strategy.tracked_token_ids
|
|
455
|
+
|
|
439
456
|
# Mock balance adapter to return fresh balances
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
457
|
+
async def get_balance_mock(token_id, **kwargs):
|
|
458
|
+
balance = strategy.tracked_balances.get(token_id, 0)
|
|
459
|
+
# Return the balance, ensuring it's an int
|
|
460
|
+
return (True, int(balance) if balance else 0)
|
|
461
|
+
|
|
462
|
+
# Create a new AsyncMock that will track calls
|
|
463
|
+
new_mock = AsyncMock(side_effect=get_balance_mock)
|
|
464
|
+
strategy.balance_adapter.get_balance = new_mock
|
|
446
465
|
|
|
447
466
|
# Mock brap adapter swap
|
|
448
467
|
strategy.brap_adapter.swap_from_token_ids = AsyncMock(
|
|
@@ -451,15 +470,23 @@ async def test_sweep_wallet_uses_tracked_tokens(strategy):
|
|
|
451
470
|
|
|
452
471
|
target_token = {
|
|
453
472
|
"token_id": "usd-coin-base",
|
|
454
|
-
"address": "
|
|
473
|
+
"address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
455
474
|
"chain": {"code": "base", "name": "Base"},
|
|
456
475
|
}
|
|
457
476
|
|
|
458
477
|
# Call sweep
|
|
459
478
|
await strategy._sweep_wallet(target_token)
|
|
460
479
|
|
|
461
|
-
# Verify that swap was called for tracked tokens
|
|
462
|
-
|
|
480
|
+
# Verify that swap was called for tracked tokens (should be called twice, once for each token)
|
|
481
|
+
# If this fails, check: balance_adapter.get_balance was called, tracked_balances has values,
|
|
482
|
+
# and tokens pass the gas/target token checks
|
|
483
|
+
assert strategy.brap_adapter.swap_from_token_ids.call_count >= 1, (
|
|
484
|
+
f"Expected at least 1 swap call, got {strategy.brap_adapter.swap_from_token_ids.call_count}. "
|
|
485
|
+
f"Tracked tokens: {strategy.tracked_token_ids}, "
|
|
486
|
+
f"Tracked balances: {strategy.tracked_balances}, "
|
|
487
|
+
f"Get balance calls: {new_mock.call_count}, "
|
|
488
|
+
f"balance_adapter mock is: {id(strategy.balance_adapter.get_balance)}, new_mock is: {id(new_mock)}"
|
|
489
|
+
)
|
|
463
490
|
|
|
464
491
|
|
|
465
492
|
@pytest.mark.asyncio
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wayfinder-paths
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: Wayfinder Path: strategies and adapters
|
|
5
5
|
Author: Wayfinder
|
|
6
6
|
Author-email: dev@wayfinder.ai
|
|
@@ -125,6 +125,7 @@ We welcome contributions! This is an open-source project where community members
|
|
|
125
125
|
### Contributor Guidelines
|
|
126
126
|
|
|
127
127
|
#### For Adapters
|
|
128
|
+
|
|
128
129
|
- **Start from the template**: Copy `wayfinder_paths/templates/adapter/` as a starting point
|
|
129
130
|
- Extend `BaseAdapter` from `wayfinder_paths/core/adapters/BaseAdapter.py`
|
|
130
131
|
- Create a `manifest.yaml` (template at `wayfinder_paths/templates/adapter/manifest.yaml`) with:
|
|
@@ -138,6 +139,7 @@ We welcome contributions! This is an open-source project where community members
|
|
|
138
139
|
- Validate your manifest: `just validate-manifests`
|
|
139
140
|
|
|
140
141
|
#### For Strategies
|
|
142
|
+
|
|
141
143
|
- **Start from the template**: Use `just create-strategy "Strategy Name"` to create a new strategy with its own wallet, or copy `wayfinder_paths/templates/strategy/` manually
|
|
142
144
|
- Extend `Strategy` from `wayfinder_paths/core/strategies/Strategy.py`
|
|
143
145
|
- Create a `manifest.yaml` (template at `wayfinder_paths/templates/strategy/manifest.yaml`) with:
|
|
@@ -151,6 +153,7 @@ We welcome contributions! This is an open-source project where community members
|
|
|
151
153
|
- Validate your manifest: `just validate-manifests`
|
|
152
154
|
|
|
153
155
|
#### General Guidelines
|
|
156
|
+
|
|
154
157
|
- **Code Quality**: Follow existing patterns and use type hints
|
|
155
158
|
- **Testing**: See [TESTING.md](TESTING.md) - minimum: smoke test for strategies, basic tests for adapters
|
|
156
159
|
- **Documentation**: Update README files and add docstrings
|
|
@@ -205,6 +208,7 @@ poetry run python wayfinder_paths/run_strategy.py your_strategy --action status
|
|
|
205
208
|
## 🏗️ Architecture
|
|
206
209
|
|
|
207
210
|
### Client System
|
|
211
|
+
|
|
208
212
|
The platform uses a unified client system for all API interactions. Clients are thin wrappers that handle low-level API calls, authentication, and network communication. **Strategies should not call clients directly** - use adapters instead for domain-specific operations.
|
|
209
213
|
|
|
210
214
|
### Clients vs Adapters
|
|
@@ -231,6 +235,7 @@ Adapter manifests declare the capabilities an adapter provides and the clients i
|
|
|
231
235
|
**Template:** Copy `wayfinder_paths/templates/adapter/manifest.yaml` as a starting point.
|
|
232
236
|
|
|
233
237
|
**Schema:**
|
|
238
|
+
|
|
234
239
|
```yaml
|
|
235
240
|
schema_version: "0.1"
|
|
236
241
|
entrypoint: "adapters.my_adapter.adapter.MyAdapter"
|
|
@@ -243,12 +248,14 @@ dependencies:
|
|
|
243
248
|
```
|
|
244
249
|
|
|
245
250
|
**Fields:**
|
|
251
|
+
|
|
246
252
|
- `schema_version`: Manifest schema version (currently `"0.1"`)
|
|
247
253
|
- `entrypoint`: Full Python import path to the adapter class (required)
|
|
248
254
|
- `capabilities`: List of abstract capabilities this adapter provides (required, non-empty)
|
|
249
255
|
- `dependencies`: List of client class names from `core.clients` that this adapter requires (required, non-empty)
|
|
250
256
|
|
|
251
257
|
**Example** (`wayfinder_paths/adapters/pool_adapter/manifest.yaml`):
|
|
258
|
+
|
|
252
259
|
```yaml
|
|
253
260
|
schema_version: "0.1"
|
|
254
261
|
entrypoint: "adapters.pool_adapter.adapter.PoolAdapter"
|
|
@@ -269,6 +276,7 @@ Strategy manifests declare permissions and required adapters with their capabili
|
|
|
269
276
|
**Template:** Copy `wayfinder_paths/templates/strategy/manifest.yaml` as a starting point.
|
|
270
277
|
|
|
271
278
|
**Schema:**
|
|
279
|
+
|
|
272
280
|
```yaml
|
|
273
281
|
schema_version: "0.1"
|
|
274
282
|
entrypoint: "strategies.my_strategy.strategy.MyStrategy"
|
|
@@ -282,6 +290,7 @@ adapters:
|
|
|
282
290
|
```
|
|
283
291
|
|
|
284
292
|
**Fields:**
|
|
293
|
+
|
|
285
294
|
- `schema_version`: Manifest schema version (currently `"0.1"`)
|
|
286
295
|
- `entrypoint`: Full Python import path to the strategy class (required)
|
|
287
296
|
- `name`: Strategy directory name (optional, used for wallet lookup - defaults to directory name)
|
|
@@ -291,6 +300,7 @@ adapters:
|
|
|
291
300
|
- `capabilities`: List of capabilities required from this adapter
|
|
292
301
|
|
|
293
302
|
**Example** (`wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml`):
|
|
303
|
+
|
|
294
304
|
```yaml
|
|
295
305
|
schema_version: "0.1"
|
|
296
306
|
entrypoint: "strategies.stablecoin_yield_strategy.strategy.StablecoinYieldStrategy"
|
|
@@ -308,12 +318,14 @@ adapters:
|
|
|
308
318
|
#### Manifest Validation
|
|
309
319
|
|
|
310
320
|
Manifests are automatically validated to ensure:
|
|
321
|
+
|
|
311
322
|
- Schema compliance (all required fields present, correct types)
|
|
312
323
|
- Entrypoint classes exist and are importable
|
|
313
324
|
- Dependencies are valid client classes
|
|
314
325
|
- Permissions policies are non-empty
|
|
315
326
|
|
|
316
327
|
**Validate locally:**
|
|
328
|
+
|
|
317
329
|
```bash
|
|
318
330
|
# Validate all manifests
|
|
319
331
|
just validate-manifests
|
|
@@ -348,6 +360,7 @@ The `validate_manifests.py` script performs multi-stage validation:
|
|
|
348
360
|
- Policy syntax is not parsed/validated (assumed to be valid at runtime)
|
|
349
361
|
|
|
350
362
|
**Validation Flow:**
|
|
363
|
+
|
|
351
364
|
```
|
|
352
365
|
For each manifest file:
|
|
353
366
|
1. Load YAML → Parse with Pydantic (schema validation)
|
|
@@ -357,6 +370,7 @@ For each manifest file:
|
|
|
357
370
|
```
|
|
358
371
|
|
|
359
372
|
The script automatically discovers all manifests by scanning:
|
|
373
|
+
|
|
360
374
|
- `wayfinder_paths/adapters/*/manifest.yaml` for adapter manifests
|
|
361
375
|
- `wayfinder_paths/strategies/*/manifest.yaml` for strategy manifests
|
|
362
376
|
|
|
@@ -367,12 +381,15 @@ All errors are collected and reported at the end, with the script exiting with c
|
|
|
367
381
|
Capabilities are abstract operation identifiers (e.g., `"pool.read"`, `"swap.execute"`) declared in manifests. They represent what operations an adapter can perform, not specific method names. The manifest is the **single source of truth** for capabilities—they are not duplicated in code.
|
|
368
382
|
|
|
369
383
|
When creating an adapter:
|
|
384
|
+
|
|
370
385
|
1. Declare capabilities in your `manifest.yaml`
|
|
371
386
|
2. Implement methods that fulfill those capabilities
|
|
372
387
|
3. Capabilities are validated at manifest validation time (entrypoint must be importable)
|
|
373
388
|
|
|
374
389
|
### Configuration
|
|
390
|
+
|
|
375
391
|
Configuration is split between:
|
|
392
|
+
|
|
376
393
|
- **User Config**: Your credentials and preferences
|
|
377
394
|
- **System Config**: Platform settings
|
|
378
395
|
- **Strategy Config**: Strategy-specific parameters
|
|
@@ -384,9 +401,11 @@ See [CONFIG_GUIDE.md](wayfinder_paths/CONFIG_GUIDE.md) for details.
|
|
|
384
401
|
Wayfinder Paths supports two authentication methods:
|
|
385
402
|
|
|
386
403
|
#### 1. Service Account Authentication (API Key)
|
|
404
|
+
|
|
387
405
|
For backend services and automated systems with higher rate limits:
|
|
388
406
|
|
|
389
407
|
**Option A: Pass to Strategy Constructor**
|
|
408
|
+
|
|
390
409
|
```python
|
|
391
410
|
from wayfinder_paths.strategies.stablecoin_yield_strategy.strategy import StablecoinYieldStrategy
|
|
392
411
|
|
|
@@ -397,19 +416,21 @@ strategy = StablecoinYieldStrategy(
|
|
|
397
416
|
```
|
|
398
417
|
|
|
399
418
|
**Option B: Set Environment Variable**
|
|
419
|
+
|
|
400
420
|
```bash
|
|
401
421
|
export WAYFINDER_API_KEY="sk_live_abc123..."
|
|
402
422
|
# All clients will automatically discover and use this
|
|
403
423
|
```
|
|
404
424
|
|
|
405
425
|
**Option C: Add to config.json**
|
|
426
|
+
|
|
406
427
|
```json
|
|
407
428
|
{
|
|
408
429
|
"user": {
|
|
409
430
|
"api_key": "sk_live_abc123..."
|
|
410
431
|
},
|
|
411
432
|
"system": {
|
|
412
|
-
"api_key": "sk_live_abc123..."
|
|
433
|
+
"api_key": "sk_live_abc123..." // Alternative: system-level API key
|
|
413
434
|
}
|
|
414
435
|
}
|
|
415
436
|
```
|
|
@@ -419,6 +440,7 @@ export WAYFINDER_API_KEY="sk_live_abc123..."
|
|
|
419
440
|
**Note:** API keys in `config.json` are loaded directly by `WayfinderClient` via `_load_config_credentials()`, not through the `UserConfig` or `SystemConfig` dataclasses. This allows flexible credential loading.
|
|
420
441
|
|
|
421
442
|
#### 2. Personal Access Authentication (OAuth)
|
|
443
|
+
|
|
422
444
|
For standalone SDK users with username/password:
|
|
423
445
|
|
|
424
446
|
```json
|
|
@@ -426,12 +448,13 @@ For standalone SDK users with username/password:
|
|
|
426
448
|
"user": {
|
|
427
449
|
"username": "your_username",
|
|
428
450
|
"password": "your_password",
|
|
429
|
-
"refresh_token": null
|
|
451
|
+
"refresh_token": null // Optional: use refresh token instead
|
|
430
452
|
}
|
|
431
453
|
}
|
|
432
454
|
```
|
|
433
455
|
|
|
434
456
|
**How It Works:**
|
|
457
|
+
|
|
435
458
|
- API keys are automatically discovered by all clients (no need to pass explicitly)
|
|
436
459
|
- When an API key is available, it's used for all API requests (including public endpoints) for rate limiting
|
|
437
460
|
- If no API key is found, the system falls back to OAuth authentication
|
|
@@ -614,6 +637,7 @@ just create-wallets
|
|
|
614
637
|
```
|
|
615
638
|
|
|
616
639
|
This creates:
|
|
640
|
+
|
|
617
641
|
- `main` wallet - your main wallet for testing (labeled "main" in wallets.json)
|
|
618
642
|
- `wallets.json` - wallet addresses and private keys for local testing
|
|
619
643
|
|
|
@@ -689,12 +713,14 @@ This package follows [Semantic Versioning](https://semver.org/) (SemVer) and is
|
|
|
689
713
|
3. **Dependent changes**: Only after publishing can dependent changes be merged in other applications
|
|
690
714
|
|
|
691
715
|
**Why this order matters:**
|
|
716
|
+
|
|
692
717
|
- Other applications depend on this package from PyPI
|
|
693
718
|
- They cannot merge changes that depend on new versions until those versions are available on PyPI
|
|
694
719
|
- Publishing from `main` ensures the published version matches what's in the repository
|
|
695
720
|
- This prevents dependency resolution failures in downstream applications
|
|
696
721
|
|
|
697
722
|
**Example workflow:**
|
|
723
|
+
|
|
698
724
|
```bash
|
|
699
725
|
# 1. Make changes in a feature branch
|
|
700
726
|
git checkout -b feature/new-adapter
|
|
@@ -727,6 +753,7 @@ just publish
|
|
|
727
753
|
```
|
|
728
754
|
|
|
729
755
|
**Important:**
|
|
756
|
+
|
|
730
757
|
- ⚠️ **Publishing is only allowed from the `main` branch** - the publish command will fail if run from any other branch
|
|
731
758
|
- ⚠️ **Versions must be unique** - ensure the version in `pyproject.toml` has been bumped and is unique
|
|
732
759
|
- ⚠️ **Follow the order of operations** - see [Versioning](#-versioning) section above for the required workflow
|
|
@@ -749,6 +776,7 @@ pip install git+https://github.com/wayfinder-ai/wayfinder-paths.git
|
|
|
749
776
|
### Managing Package Access
|
|
750
777
|
|
|
751
778
|
To add collaborators who can publish updates:
|
|
779
|
+
|
|
752
780
|
1. Go to https://pypi.org/project/wayfinder-paths/
|
|
753
781
|
2. Click "Manage" → "Collaborators"
|
|
754
782
|
3. Add users as "Maintainers" (can publish) or "Owners" (full control)
|
|
@@ -9,10 +9,10 @@ wayfinder_paths/adapters/balance_adapter/manifest.yaml,sha256=vp2VoQJf-TxFxgkTsU
|
|
|
9
9
|
wayfinder_paths/adapters/balance_adapter/test_adapter.py,sha256=Z8iTRU0Rv1UsODuVSo5q4j-DrTXMd4YRxvaxLdZE4Us,1878
|
|
10
10
|
wayfinder_paths/adapters/brap_adapter/README.md,sha256=euWkSBR6OkYtebhvdNR_PL64sKbzKD5bg5hrYTIWZ1c,7905
|
|
11
11
|
wayfinder_paths/adapters/brap_adapter/__init__.py,sha256=jpqxZ-Bv_8kBo-lhgO_QCWaVZNq_WwlkNBHD4RsqOJg,90
|
|
12
|
-
wayfinder_paths/adapters/brap_adapter/adapter.py,sha256=
|
|
12
|
+
wayfinder_paths/adapters/brap_adapter/adapter.py,sha256=OCXlNxIR7vQUktaoEeM55VcFOXR-PucNJW1NpBkNEUs,26828
|
|
13
13
|
wayfinder_paths/adapters/brap_adapter/examples.json,sha256=KWuAklUspd2uvk0s2ey8gczg4nbzhdwxQqzhascyMiQ,5287
|
|
14
14
|
wayfinder_paths/adapters/brap_adapter/manifest.yaml,sha256=bJ8o4j9ZPjfnLxXxHfekoXKUHoBkXmWQ3nokTH1aya4,240
|
|
15
|
-
wayfinder_paths/adapters/brap_adapter/test_adapter.py,sha256=
|
|
15
|
+
wayfinder_paths/adapters/brap_adapter/test_adapter.py,sha256=w2q35tcE7j2QG53jSm_XZgIk7OKL4O51fnFuGMVRSNQ,10754
|
|
16
16
|
wayfinder_paths/adapters/hyperlend_adapter/__init__.py,sha256=DsWOnEn-Tlu9ZoIoGaFeSqOYI3b4lXGVK3_FTntWpLw,139
|
|
17
17
|
wayfinder_paths/adapters/hyperlend_adapter/adapter.py,sha256=QevMiOrztvTRHx7vA_dAQGX3ioUFdLY4aVOfsT-DXX8,10555
|
|
18
18
|
wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml,sha256=Ugc0jNf3txAQRGAXlVvTN3Mbdc4-fUMS1yVs0SZcBwI,259
|
|
@@ -31,13 +31,13 @@ wayfinder_paths/adapters/ledger_adapter/__init__.py,sha256=DK9GShIUiQ57YKSqhCKoS
|
|
|
31
31
|
wayfinder_paths/adapters/ledger_adapter/adapter.py,sha256=6Fjxltvn9iXp_-CZtN7lDz1Xt0lWaNQX2drx6lgeryw,10260
|
|
32
32
|
wayfinder_paths/adapters/ledger_adapter/examples.json,sha256=DdqTSe4vnBrfIycQVQQ_JZom7fBGHbL7MR4ppK9ljCY,3936
|
|
33
33
|
wayfinder_paths/adapters/ledger_adapter/manifest.yaml,sha256=121VPXNpx13vO9qoBww47Wvpi29JLn5WoIFnudCkDYs,271
|
|
34
|
-
wayfinder_paths/adapters/ledger_adapter/test_adapter.py,sha256=
|
|
35
|
-
wayfinder_paths/adapters/pool_adapter/README.md,sha256=
|
|
34
|
+
wayfinder_paths/adapters/ledger_adapter/test_adapter.py,sha256=Z1-rPP9k5fI-8ofWMKgU3syzNegKGH_hGO6CKApQj1c,7470
|
|
35
|
+
wayfinder_paths/adapters/pool_adapter/README.md,sha256=ttfG4aP_Y0Bl7DXxPlrAhrubOs9Yu0mtki3h7JqWvxQ,5293
|
|
36
36
|
wayfinder_paths/adapters/pool_adapter/__init__.py,sha256=rv56pYzz2Gqiz33uoPJktCQRe3CRt8U9ry5GbjVgK3A,90
|
|
37
|
-
wayfinder_paths/adapters/pool_adapter/adapter.py,sha256=
|
|
38
|
-
wayfinder_paths/adapters/pool_adapter/examples.json,sha256=
|
|
37
|
+
wayfinder_paths/adapters/pool_adapter/adapter.py,sha256=D3J9Bx7urFZjuqfmexg-wDjngKfaeeXi5aNgQXQ2W_Y,7249
|
|
38
|
+
wayfinder_paths/adapters/pool_adapter/examples.json,sha256=FS0cssPu2KB05MmzG4Hc0Ka0DzOn_0nogqfHBGLJns8,2295
|
|
39
39
|
wayfinder_paths/adapters/pool_adapter/manifest.yaml,sha256=z-OQYBsl2RdV6M34RZzqtQTAFHtQod0po_JD_-9ElNM,217
|
|
40
|
-
wayfinder_paths/adapters/pool_adapter/test_adapter.py,sha256=
|
|
40
|
+
wayfinder_paths/adapters/pool_adapter/test_adapter.py,sha256=AYk4YWf0H3FXNBc1NKVmXuLQvE7dpMU-QrCp0XWQYFw,5954
|
|
41
41
|
wayfinder_paths/adapters/token_adapter/README.md,sha256=d2tMJte6HBu62CCYXdjS8GHZXj5f2fU03uZAO6pscBI,2698
|
|
42
42
|
wayfinder_paths/adapters/token_adapter/__init__.py,sha256=nEmxrvffEygn3iKH3cZTNLkhnUUhlUAEtshmrFRAjq8,62
|
|
43
43
|
wayfinder_paths/adapters/token_adapter/adapter.py,sha256=JEb7A8wJYHxENFhJ6upAgnQAbPZeVfYi6OGs1hiHxnA,3432
|
|
@@ -56,18 +56,18 @@ wayfinder_paths/core/analytics/bootstrap.py,sha256=lb_PjL4Vh3O2F8eXgvAbnAFevJczR
|
|
|
56
56
|
wayfinder_paths/core/analytics/stats.py,sha256=qE6h0j8TZAbqbVpDeYlVKe0YbV5CENQcHbREzKyZ_s8,1426
|
|
57
57
|
wayfinder_paths/core/analytics/test_analytics.py,sha256=DNkVTsbWPLc9I1eeCD5wsPPqUDgN-npbGRhBgMKn3GM,5580
|
|
58
58
|
wayfinder_paths/core/clients/AuthClient.py,sha256=scz8GvnabNYAQq_XYDcLP2lf2LZqurQOixA7MMAfbCY,2796
|
|
59
|
-
wayfinder_paths/core/clients/BRAPClient.py,sha256
|
|
59
|
+
wayfinder_paths/core/clients/BRAPClient.py,sha256=-cL05ELlroi3pUfT_5nF8Axie2a0n19npnuP408bkAQ,3744
|
|
60
60
|
wayfinder_paths/core/clients/ClientManager.py,sha256=2p8oEFnCxKCH_TBMKo9gMLAwzwLgeotdgFod8wpoa04,8135
|
|
61
61
|
wayfinder_paths/core/clients/HyperlendClient.py,sha256=6yAhojEbjrRC7YLckwGL_2z5lwI4xnrRVNzxspqKSTg,6173
|
|
62
62
|
wayfinder_paths/core/clients/LedgerClient.py,sha256=M6VlG0yq3H4rQt6qRxc0QQVd7GoPXJpj2FcD0RM_C_k,14430
|
|
63
|
-
wayfinder_paths/core/clients/PoolClient.py,sha256=
|
|
63
|
+
wayfinder_paths/core/clients/PoolClient.py,sha256=EMIRRw7nh2bha-Qb5uOcIRgbnnu_v5FIvDU0D61nXGI,3475
|
|
64
64
|
wayfinder_paths/core/clients/SimulationClient.py,sha256=ViQmXCQKwhpnZA-YkfIgArrpxGr1U11lZNlbBIak1MU,6364
|
|
65
65
|
wayfinder_paths/core/clients/TokenClient.py,sha256=zg39K-uA1ObkNEcxoXviA1QYSd-fxQXxjBHFOeClY9E,2788
|
|
66
66
|
wayfinder_paths/core/clients/TransactionClient.py,sha256=APs-8lMdgBnE40wOn5L8_lEdJ3DddTZFcQbW0tIfJWg,2040
|
|
67
67
|
wayfinder_paths/core/clients/WalletClient.py,sha256=Vc2AwllBxUzkdZKKVRrPR4gl8mtvffRxz5QbrpxcH-0,2819
|
|
68
68
|
wayfinder_paths/core/clients/WayfinderClient.py,sha256=lLdmD58gAyx5N4yYN4-IYjvRDVzwE3K408XuI07g6g4,10724
|
|
69
69
|
wayfinder_paths/core/clients/__init__.py,sha256=oNq6fQW8hUnpkuIZxdbOTLPayJRLA6S-k8e7wqsH_7c,1581
|
|
70
|
-
wayfinder_paths/core/clients/protocols.py,sha256=
|
|
70
|
+
wayfinder_paths/core/clients/protocols.py,sha256=3TYdOdvz9en72_xA6sMHgahB21ZQFP5w86qE6pwo7YA,10117
|
|
71
71
|
wayfinder_paths/core/clients/sdk_example.py,sha256=Y6mSyHfsWcOje6E-geNI0C4CQ6uyZaD3V9Q8kPM53eo,2969
|
|
72
72
|
wayfinder_paths/core/config.py,sha256=A--KQp_EDLXhtituvk3WXPUP2SJv45IcNcm4G_nFMc0,16890
|
|
73
73
|
wayfinder_paths/core/constants/__init__.py,sha256=KH-TtfNBJgp0WfKIxvHnvS521odH8RS3Qhl8cQhr4Ys,663
|
|
@@ -128,7 +128,7 @@ wayfinder_paths/strategies/stablecoin_yield_strategy/README.md,sha256=Qj1b2bU560
|
|
|
128
128
|
wayfinder_paths/strategies/stablecoin_yield_strategy/examples.json,sha256=pL1DNFEvYvXKK7xXD5oQYFPQj3Cm1ocKnk6r_iZk0IY,423
|
|
129
129
|
wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml,sha256=rBb7-Fmub8twfKJgbBIiCWbwI2nLnuqBNyAJs36WhIg,750
|
|
130
130
|
wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py,sha256=6Ug2_cFx3nqw4Of5Oo1e9h1tQL1G3JXk2XcxNoq2Q0g,75607
|
|
131
|
-
wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py,sha256=
|
|
131
|
+
wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py,sha256=StGLLqDwthmqYDKLo-Qo0XCUU0pEFD_H65smdxgpBGc,20125
|
|
132
132
|
wayfinder_paths/templates/adapter/README.md,sha256=QcJ0cwXqqtj1VRK1wAs-unUphTPHdJwoIrIoSU4hTmA,3550
|
|
133
133
|
wayfinder_paths/templates/adapter/adapter.py,sha256=8wdqcEwqb7XGUxl2gQvGnbFwhPi1h15ZJhB2lgtZieI,814
|
|
134
134
|
wayfinder_paths/templates/adapter/examples.json,sha256=KLHy3AgPIplAaZN0qY2A-HBMa1xXkMhIyusORovTD9w,79
|
|
@@ -143,7 +143,7 @@ wayfinder_paths/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
143
143
|
wayfinder_paths/tests/test_smoke_manifest.py,sha256=YjVzHTWys5o6Ae2cUuuJPhk-QgKxT1InDFHLjpouRiY,1267
|
|
144
144
|
wayfinder_paths/tests/test_test_coverage.py,sha256=9NrZeVmP02D4W7Qc0XjciC05bhvdTCVibYjTGfa_GQk,7893
|
|
145
145
|
wayfinder_paths/tests/test_utils.py,sha256=pxHT0QKFlyJeJo8bFnKXzWcOdi6t8rbJ0JFCBaFCBRQ,2112
|
|
146
|
-
wayfinder_paths-0.1.
|
|
147
|
-
wayfinder_paths-0.1.
|
|
148
|
-
wayfinder_paths-0.1.
|
|
149
|
-
wayfinder_paths-0.1.
|
|
146
|
+
wayfinder_paths-0.1.8.dist-info/LICENSE,sha256=dYKnlkC_xosBAEQNUvB6cHMuhFgcUtN0oBR7E8_aR2Y,1066
|
|
147
|
+
wayfinder_paths-0.1.8.dist-info/METADATA,sha256=xHD03utEsSU9sZijwc-UwDmK0kXBiUNUIcQgD0eDfXA,31404
|
|
148
|
+
wayfinder_paths-0.1.8.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
149
|
+
wayfinder_paths-0.1.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|