wayfinder-paths 0.1.9__py3-none-any.whl → 0.1.11__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 (54) hide show
  1. wayfinder_paths/adapters/balance_adapter/README.md +1 -2
  2. wayfinder_paths/adapters/balance_adapter/adapter.py +4 -4
  3. wayfinder_paths/adapters/brap_adapter/adapter.py +139 -23
  4. wayfinder_paths/adapters/moonwell_adapter/README.md +174 -0
  5. wayfinder_paths/adapters/moonwell_adapter/__init__.py +7 -0
  6. wayfinder_paths/adapters/moonwell_adapter/adapter.py +1226 -0
  7. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +635 -0
  8. wayfinder_paths/core/clients/AuthClient.py +3 -0
  9. wayfinder_paths/core/clients/WayfinderClient.py +2 -2
  10. wayfinder_paths/core/constants/__init__.py +0 -2
  11. wayfinder_paths/core/constants/base.py +6 -2
  12. wayfinder_paths/core/constants/moonwell_abi.py +411 -0
  13. wayfinder_paths/core/engine/StrategyJob.py +3 -0
  14. wayfinder_paths/core/services/local_evm_txn.py +182 -217
  15. wayfinder_paths/core/services/local_token_txn.py +46 -26
  16. wayfinder_paths/core/strategies/descriptors.py +1 -1
  17. wayfinder_paths/core/utils/evm_helpers.py +0 -27
  18. wayfinder_paths/run_strategy.py +34 -74
  19. wayfinder_paths/scripts/create_strategy.py +2 -27
  20. wayfinder_paths/scripts/run_strategy.py +37 -7
  21. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +1 -1
  22. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +0 -15
  23. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +1 -1
  24. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md +108 -0
  25. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/examples.json +11 -0
  26. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +2975 -0
  27. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +886 -0
  28. wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +0 -7
  29. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +1 -1
  30. wayfinder_paths/templates/adapter/README.md +5 -21
  31. wayfinder_paths/templates/adapter/adapter.py +1 -2
  32. wayfinder_paths/templates/adapter/test_adapter.py +1 -1
  33. wayfinder_paths/templates/strategy/README.md +4 -21
  34. wayfinder_paths/tests/test_smoke_manifest.py +17 -2
  35. {wayfinder_paths-0.1.9.dist-info → wayfinder_paths-0.1.11.dist-info}/METADATA +60 -187
  36. {wayfinder_paths-0.1.9.dist-info → wayfinder_paths-0.1.11.dist-info}/RECORD +38 -45
  37. wayfinder_paths/CONFIG_GUIDE.md +0 -390
  38. wayfinder_paths/adapters/balance_adapter/manifest.yaml +0 -8
  39. wayfinder_paths/adapters/brap_adapter/manifest.yaml +0 -11
  40. wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml +0 -10
  41. wayfinder_paths/adapters/hyperliquid_adapter/manifest.yaml +0 -8
  42. wayfinder_paths/adapters/ledger_adapter/manifest.yaml +0 -11
  43. wayfinder_paths/adapters/pool_adapter/manifest.yaml +0 -10
  44. wayfinder_paths/adapters/token_adapter/manifest.yaml +0 -6
  45. wayfinder_paths/config.example.json +0 -22
  46. wayfinder_paths/core/engine/manifest.py +0 -97
  47. wayfinder_paths/scripts/validate_manifests.py +0 -213
  48. wayfinder_paths/strategies/basis_trading_strategy/manifest.yaml +0 -23
  49. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/manifest.yaml +0 -7
  50. wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml +0 -17
  51. wayfinder_paths/templates/adapter/manifest.yaml +0 -6
  52. wayfinder_paths/templates/strategy/manifest.yaml +0 -8
  53. {wayfinder_paths-0.1.9.dist-info → wayfinder_paths-0.1.11.dist-info}/LICENSE +0 -0
  54. {wayfinder_paths-0.1.9.dist-info → wayfinder_paths-0.1.11.dist-info}/WHEEL +0 -0
@@ -1,7 +1,6 @@
1
1
  # Stablecoin Yield Strategy
2
2
 
3
3
  - Entrypoint: `strategies.stablecoin_yield_strategy.strategy.StablecoinYieldStrategy`
4
- - Manifest: `manifest.yaml`
5
4
  - Examples: `examples.json`
6
5
  - Tests: `test_strategy.py`
7
6
 
@@ -87,10 +86,4 @@ poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --ac
87
86
  poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --action update --config $(pwd)/config.json
88
87
  ```
89
88
 
90
- You can also load the manifest explicitly:
91
-
92
- ```bash
93
- poetry run python wayfinder_paths/run_strategy.py --manifest wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml --action status --config $(pwd)/config.json
94
- ```
95
-
96
89
  Wallet addresses are auto-populated from `wallets.json` when you run `wayfinder_paths/scripts/make_wallets.py`. Set `NETWORK=testnet` in `config.json` to dry-run operations against mocked services.
@@ -74,7 +74,7 @@ class StablecoinYieldStrategy(Strategy):
74
74
  gas_threshold=GAS_MAXIMUM * GAS_SAFETY_FRACTION,
75
75
  # risk indicators
76
76
  volatility=Volatility.LOW,
77
- volatility_description_short=(
77
+ volatility_description=(
78
78
  "Capital sits in Base stablecoin lending pools, so price swings are minimal."
79
79
  ),
80
80
  directionality=Directionality.MARKET_NEUTRAL,
@@ -8,16 +8,15 @@ Adapters expose protocol-specific capabilities to strategies. They should be thi
8
8
  ```
9
9
  cp -r wayfinder_paths/templates/adapter wayfinder_paths/adapters/my_adapter
10
10
  ```
11
- 2. Rename `MyAdapter` in `adapter.py` and update `manifest.yaml` so the `entrypoint` matches (`adapters.my_adapter.adapter.MyAdapter`).
12
- 3. Declare the capabilities your adapter will provide and list any client dependencies (e.g., `PoolClient`, `LedgerClient`).
13
- 4. Implement the public methods that fulfill those capabilities.
11
+ 2. Rename `MyAdapter` in `adapter.py` to match your adapter's purpose.
12
+ 3. Implement the public methods that provide your adapter's capabilities.
13
+ 4. Add tests in `test_adapter.py`.
14
14
 
15
15
  ## Layout
16
16
 
17
17
  ```
18
18
  my_adapter/
19
19
  ├── adapter.py # Adapter implementation
20
- ├── manifest.yaml # Entrypoint + capabilities + dependency list
21
20
  ├── examples.json # Example payloads (optional but encouraged)
22
21
  ├── test_adapter.py # Pytest smoke tests
23
22
  └── README.md # Adapter-specific notes
@@ -57,21 +56,6 @@ class MyAdapter(BaseAdapter):
57
56
 
58
57
  Your adapter should return `(success, payload)` tuples for every operation, just like the built-in adapters do.
59
58
 
60
- ## Manifest
61
-
62
- Every adapter needs a manifest describing its import path, declared capabilities, and runtime dependencies.
63
-
64
- ```yaml
65
- schema_version: "0.1"
66
- entrypoint: "adapters.my_adapter.adapter.MyAdapter"
67
- capabilities:
68
- - "pool.read"
69
- dependencies:
70
- - "PoolClient"
71
- ```
72
-
73
- The `dependencies` list is informational today but helps reviewers understand which core clients you rely on.
74
-
75
59
  ## Testing
76
60
 
77
61
  `test_adapter.py` should cover the public methods you expose. Patch out remote clients with `unittest.mock.AsyncMock` so tests run offline.
@@ -99,7 +83,7 @@ async def test_get_pools():
99
83
 
100
84
  ## Best practices
101
85
 
102
- - Capabilities listed in `manifest.yaml` must correspond to methods you implement.
103
86
  - Keep adapters stateless and idempotent—strategies may reuse instances across operations.
104
87
  - Use `self.logger` for contextual logging (BaseAdapter has already bound the adapter name).
105
- - Raise `NotImplementedError` for manifest capabilities you intentionally do not support yet.
88
+ - Return `(success, payload)` tuples consistently for all operations.
89
+ - Raise `NotImplementedError` for capabilities you intentionally do not support yet.
@@ -6,8 +6,7 @@ from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
6
6
  class MyAdapter(BaseAdapter):
7
7
  """
8
8
  Template adapter for a protocol/exchange integration.
9
- Copy this folder, rename it (e.g., my_adapter), update manifest entrypoint,
10
- and implement the capabilities your manifest declares.
9
+ Copy this folder, rename it (e.g., my_adapter), and implement your adapter methods.
11
10
  """
12
11
 
13
12
  adapter_type: str = "MY_ADAPTER"
@@ -40,7 +40,7 @@ class TestMyAdapter:
40
40
  assert isinstance(ok, bool)
41
41
 
42
42
  def test_capabilities(self, adapter):
43
- """Test adapter capabilities match manifest"""
43
+ """Test adapter capabilities"""
44
44
  assert hasattr(adapter, "adapter_type")
45
45
 
46
46
  @pytest.mark.asyncio
@@ -1,6 +1,6 @@
1
1
  # Strategy Template
2
2
 
3
- This template provides the scaffolding for a new strategy. It mirrors the structure in `wayfinder_paths/strategies/...` and wires into the runner via a manifest.
3
+ This template provides the scaffolding for a new strategy. It mirrors the structure in `wayfinder_paths/strategies/...`.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -8,7 +8,7 @@ This template provides the scaffolding for a new strategy. It mirrors the struct
8
8
  ```
9
9
  cp -r wayfinder_paths/templates/strategy wayfinder_paths/strategies/my_strategy
10
10
  ```
11
- 2. Rename the class in `strategy.py` and update `manifest.yaml` so `entrypoint` points to your new module (for example `strategies.my_strategy.strategy.MyStrategy`).
11
+ 2. Rename the class in `strategy.py` to match your strategy name.
12
12
  3. Fill out `examples.json` with sample CLI invocations and `test_strategy.py` with at least one smoke test.
13
13
  4. Implement the required strategy methods (`deposit`, `update`, `_status`, optionally override `withdraw`).
14
14
 
@@ -17,7 +17,6 @@ This template provides the scaffolding for a new strategy. It mirrors the struct
17
17
  ```
18
18
  my_strategy/
19
19
  ├── strategy.py # Strategy implementation
20
- ├── manifest.yaml # Entrypoint + adapter requirements + policy
21
20
  ├── examples.json # Example CLI payloads
22
21
  ├── test_strategy.py # Pytest-based smoke tests
23
22
  └── README.md # Strategy-specific documentation
@@ -98,22 +97,6 @@ class MyStrategy(Strategy):
98
97
  }
99
98
  ```
100
99
 
101
- ## Manifest configuration
102
-
103
- Your `manifest.yaml` should define:
104
-
105
- ```yaml
106
- schema_version: "0.1"
107
- entrypoint: "strategies.my_strategy.strategy.MyStrategy"
108
- permissions:
109
- policy: "(wallet.id == 'FORMAT_WALLET_ID') && (eth.tx.to == '0x...')"
110
- adapters:
111
- - name: "BALANCE"
112
- capabilities: ["wallet_read", "wallet_transfer"]
113
- - name: "POOL"
114
- capabilities: ["pool.read", "pool.analytics"]
115
- ```
116
-
117
100
  ## Testing
118
101
 
119
102
  `test_strategy.py` should cover at least deposit/update/status. Use `pytest.mark.asyncio` and patch adapters or services as needed.
@@ -149,5 +132,5 @@ poetry run python wayfinder_paths/run_strategy.py my_strategy --action status --
149
132
 
150
133
  - Return `(success: bool, message: str)` tuples from `deposit`/`update`.
151
134
  - Always populate `portfolio_value`, `net_deposit`, and `strategy_status` keys in `_status`.
152
- - Use the adapters declared in `manifest.yaml`—they are injected via `register_adapters`.
153
- - Keep on-chain permissions tight by scoping the manifest policy to the strategy wallet and expected contracts.
135
+ - Register adapters via `register_adapters` in your `__init__` method.
136
+ - Keep strategy logic clear and well-documented.
@@ -14,6 +14,16 @@ class FakeAdapter(BaseAdapter):
14
14
  return {"asset": asset, "amount": 100}
15
15
 
16
16
 
17
+ class FakeLedgerAdapter(BaseAdapter):
18
+ adapter_type = "LEDGER"
19
+
20
+ async def connect(self) -> bool:
21
+ return True
22
+
23
+ async def record_strategy_snapshot(self, **kwargs):
24
+ pass
25
+
26
+
17
27
  class FakeStrategy(Strategy):
18
28
  name = "Fake Strategy"
19
29
 
@@ -26,7 +36,7 @@ class FakeStrategy(Strategy):
26
36
  async def withdraw(self, amount: float = 0) -> StatusTuple:
27
37
  return (True, "withdrew")
28
38
 
29
- async def status(self) -> StatusDict:
39
+ async def _status(self) -> StatusDict:
30
40
  return {"total_earned": 0.0, "strategy_status": {"ok": True}}
31
41
 
32
42
  @staticmethod
@@ -36,8 +46,13 @@ class FakeStrategy(Strategy):
36
46
 
37
47
  @pytest.mark.asyncio
38
48
  async def test_smoke_deposit_update_withdraw_status():
39
- s = FakeStrategy()
49
+ s = FakeStrategy(
50
+ config={
51
+ "strategy_wallet": {"address": "0x1234567890123456789012345678901234567890"}
52
+ }
53
+ )
40
54
  s.register_adapters([FakeAdapter("fake")])
55
+ s.ledger_adapter = FakeLedgerAdapter("ledger")
41
56
  ok, msg = await s.deposit(amount=1)
42
57
  assert ok
43
58
  ok, msg = await s.update()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wayfinder-paths
3
- Version: 0.1.9
3
+ Version: 0.1.11
4
4
  Summary: Wayfinder Path: strategies and adapters
5
5
  Author: Wayfinder
6
6
  Author-email: dev@wayfinder.ai
@@ -47,6 +47,9 @@ poetry install
47
47
  just create-wallets
48
48
  # Or manually: poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
49
49
 
50
+ # To test a specific strategy
51
+ just create-wallet stablecoin_yield_strategy
52
+
50
53
  # Copy and configure
51
54
  cp wayfinder_paths/config.example.json config.json
52
55
  # Edit config.json with your Wayfinder credentials
@@ -72,7 +75,6 @@ wayfinder_paths/
72
75
  │ ├── adapters/ # Your exchange/protocol integrations (community contributions)
73
76
  │ │ ├── balance_adapter/
74
77
  │ │ │ ├── adapter.py # Adapter implementation
75
- │ │ │ ├── manifest.yaml # Adapter manifest (caps, entrypoint)
76
78
  │ │ │ ├── examples.json # Example inputs for smoke
77
79
  │ │ │ ├── README.md # Local notes
78
80
  │ │ │ └── test_adapter.py # Local smoke test
@@ -81,7 +83,6 @@ wayfinder_paths/
81
83
  │ ├── strategies/ # Your trading strategies (community contributions)
82
84
  │ │ ├── stablecoin_yield_strategy/
83
85
  │ │ │ ├── strategy.py # Strategy implementation
84
- │ │ │ ├── manifest.yaml # Strategy manifest
85
86
  │ │ │ ├── examples.json # Example inputs
86
87
  │ │ │ ├── README.md # Local notes
87
88
  │ │ │ └── test_strategy.py # Local smoke test
@@ -108,10 +109,9 @@ We welcome contributions! This is an open-source project where community members
108
109
  3. **Copy a template** to get started:
109
110
  - **For adapters**: Copy `wayfinder_paths/templates/adapter/` to `wayfinder_paths/adapters/my_adapter/`
110
111
  - **For strategies**: Copy `wayfinder_paths/templates/strategy/` to `wayfinder_paths/strategies/my_strategy/`
111
- 4. **Customize** the template (rename classes, update manifest, implement methods)
112
+ 4. **Customize** the template (rename classes, implement methods)
112
113
  5. **Test your code** thoroughly using the provided test framework
113
- 6. **Validate manifests**: Run `just validate-manifests`
114
- 7. **Submit a Pull Request** with a clear description of your changes
114
+ 6. **Submit a Pull Request** with a clear description of your changes
115
115
 
116
116
  ### What You Can Contribute
117
117
 
@@ -125,29 +125,18 @@ We welcome contributions! This is an open-source project where community members
125
125
 
126
126
  - **Start from the template**: Copy `wayfinder_paths/templates/adapter/` as a starting point
127
127
  - Extend `BaseAdapter` from `wayfinder_paths/core/adapters/BaseAdapter.py`
128
- - Create a `manifest.yaml` (template at `wayfinder_paths/templates/adapter/manifest.yaml`) with:
129
- - `entrypoint`: Full import path to your adapter class
130
- - `capabilities`: List of capabilities your adapter provides
131
- - `dependencies`: List of required client classes (e.g., `PoolClient`, `TokenClient`)
132
- - Implement methods that fulfill the declared capabilities
128
+ - Implement your adapter methods
133
129
  - Add comprehensive tests in `test_adapter.py`
134
130
  - Include usage examples in `examples.json`
135
131
  - Document your adapter in `README.md`
136
- - Validate your manifest: `just validate-manifests`
137
132
 
138
133
  #### For Strategies
139
134
 
140
135
  - **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
141
136
  - Extend `Strategy` from `wayfinder_paths/core/strategies/Strategy.py`
142
- - Create a `manifest.yaml` (template at `wayfinder_paths/templates/strategy/manifest.yaml`) with:
143
- - `entrypoint`: Full import path to your strategy class
144
- - `name`: Strategy directory name (used for wallet lookup)
145
- - `permissions.policy`: Security policy for transaction permissions
146
- - `adapters`: List of required adapters and their capabilities
147
137
  - Implement required methods: `deposit()`, `update()`, `status()`, `withdraw()`
148
138
  - Include test cases in `test_strategy.py`
149
139
  - Add example configurations in `examples.json`
150
- - Validate your manifest: `just validate-manifests`
151
140
 
152
141
  #### General Guidelines
153
142
 
@@ -183,10 +172,7 @@ cp -r wayfinder_paths/templates/strategy wayfinder_paths/strategies/my_strategy
183
172
 
184
173
  # 5. Customize the template (see template README.md files for details)
185
174
 
186
- # 6. Validate your manifest
187
- just validate-manifests
188
-
189
- # 7. Run tests
175
+ # 6. Run tests
190
176
  poetry run pytest -k smoke -v
191
177
 
192
178
  # Or test your specific contribution
@@ -211,7 +197,7 @@ The platform uses a unified client system for all API interactions. Clients are
211
197
  ### Clients vs Adapters
212
198
 
213
199
  - **Clients**: Low-level, reusable service wrappers that talk to networks and external APIs. They handle auth, headers, retries, and response parsing, and expose generic capabilities (e.g., token info, tx building). Examples: `TokenClient`, `WalletClient`.
214
- - **Adapters**: Strategy-facing integrations for a specific exchange/protocol. They compose one or more clients to implement a manifest of capabilities (e.g., `supply`, `borrow`, `place_order`). Adapters encapsulate protocol-specific semantics and raise `NotImplementedError` for unsupported ops.
200
+ - **Adapters**: Strategy-facing integrations for a specific exchange/protocol. They compose one or more clients to implement a set of capabilities (e.g., `supply`, `borrow`, `place_order`). Adapters encapsulate protocol-specific semantics and raise `NotImplementedError` for unsupported ops.
215
201
 
216
202
  Recommended usage:
217
203
 
@@ -221,168 +207,6 @@ Recommended usage:
221
207
 
222
208
  Data flow: `Strategy` → `Adapter` → `Client(s)` → network/API.
223
209
 
224
- ### Manifests
225
-
226
- Every adapter and strategy requires a `manifest.yaml` file that declares its metadata, capabilities, and dependencies. Manifests are validated automatically in CI/CD and serve as the **single source of truth** for what each component can do.
227
-
228
- #### Adapter Manifests
229
-
230
- Adapter manifests declare the capabilities an adapter provides and the clients it depends on.
231
-
232
- **Template:** Copy `wayfinder_paths/templates/adapter/manifest.yaml` as a starting point.
233
-
234
- **Schema:**
235
-
236
- ```yaml
237
- schema_version: "0.1"
238
- entrypoint: "adapters.my_adapter.adapter.MyAdapter"
239
- capabilities:
240
- - "pool.read"
241
- - "pool.analytics"
242
- dependencies:
243
- - "PoolClient"
244
- - "TokenClient"
245
- ```
246
-
247
- **Fields:**
248
-
249
- - `schema_version`: Manifest schema version (currently `"0.1"`)
250
- - `entrypoint`: Full Python import path to the adapter class (required)
251
- - `capabilities`: List of abstract capabilities this adapter provides (required, non-empty)
252
- - `dependencies`: List of client class names from `core.clients` that this adapter requires (required, non-empty)
253
-
254
- **Example** (`wayfinder_paths/adapters/pool_adapter/manifest.yaml`):
255
-
256
- ```yaml
257
- schema_version: "0.1"
258
- entrypoint: "adapters.pool_adapter.adapter.PoolAdapter"
259
- capabilities:
260
- - "pool.read"
261
- - "pool.analytics"
262
- - "pool.discovery"
263
- - "llama.data"
264
- - "pool.reports"
265
- dependencies:
266
- - "PoolClient"
267
- ```
268
-
269
- #### Strategy Manifests
270
-
271
- Strategy manifests declare permissions and required adapters with their capabilities.
272
-
273
- **Template:** Copy `wayfinder_paths/templates/strategy/manifest.yaml` as a starting point.
274
-
275
- **Schema:**
276
-
277
- ```yaml
278
- schema_version: "0.1"
279
- entrypoint: "strategies.my_strategy.strategy.MyStrategy"
280
- permissions:
281
- policy: "(wallet.id == 'FORMAT_WALLET_ID') && (eth.tx.to == '0x...')"
282
- adapters:
283
- - name: "POOL"
284
- capabilities: ["pool.read", "pool.analytics"]
285
- - name: "BRAP"
286
- capabilities: ["swap.quote", "swap.execute"]
287
- ```
288
-
289
- **Fields:**
290
-
291
- - `schema_version`: Manifest schema version (currently `"0.1"`)
292
- - `entrypoint`: Full Python import path to the strategy class (required)
293
- - `name`: Strategy directory name (optional, used for wallet lookup - defaults to directory name)
294
- - `permissions.policy`: Security policy string that defines transaction permissions (required, non-empty)
295
- - `adapters`: List of required adapters with their names and needed capabilities (required, non-empty)
296
- - `name`: Adapter type identifier (e.g., "POOL", "BRAP")
297
- - `capabilities`: List of capabilities required from this adapter
298
-
299
- **Example** (`wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml`):
300
-
301
- ```yaml
302
- schema_version: "0.1"
303
- entrypoint: "strategies.stablecoin_yield_strategy.strategy.StablecoinYieldStrategy"
304
- permissions:
305
- policy: "(wallet.id == 'FORMAT_WALLET_ID') && ((eth.tx.data[0..10] == '0x095ea7b3' && eth.tx.data[34..74] == 'f75584ef6673ad213a685a1b58cc0330b8ea22cf') || (eth.tx.to == '0xF75584eF6673aD213a685a1B58Cc0330B8eA22Cf'))"
306
- adapters:
307
- - name: "BALANCE"
308
- capabilities: ["wallet_read", "wallet_transfer"]
309
- - name: "POOL"
310
- capabilities: ["pool.read", "pool.analytics"]
311
- - name: "BRAP"
312
- capabilities: ["swap.quote", "swap.execute"]
313
- ```
314
-
315
- #### Manifest Validation
316
-
317
- Manifests are automatically validated to ensure:
318
-
319
- - Schema compliance (all required fields present, correct types)
320
- - Entrypoint classes exist and are importable
321
- - Dependencies are valid client classes
322
- - Permissions policies are non-empty
323
-
324
- **Validate locally:**
325
-
326
- ```bash
327
- # Validate all manifests
328
- just validate-manifests
329
-
330
- # Or manually
331
- PYTHONPATH=wayfinder_paths poetry run python wayfinder_paths/scripts/validate_manifests.py
332
- ```
333
-
334
- Validation runs automatically in CI/CD on every PR and push to main. All manifests must be valid before merging.
335
-
336
- **How Validation Works:**
337
-
338
- The `validate_manifests.py` script performs multi-stage validation:
339
-
340
- 1. **Schema Validation** (via Pydantic models):
341
- - Loads YAML file and validates against `AdapterManifest` or `StrategyManifest` schema
342
- - Checks required fields, types, and basic constraints (e.g., capabilities cannot be empty)
343
- - Validates entrypoint format (must be full import path like `"adapters.pool_adapter.adapter.PoolAdapter"`)
344
-
345
- 2. **Entrypoint Verification**:
346
- - **For Adapters**: Imports the entrypoint class and verifies it's a subclass of `BaseAdapter`
347
- - **For Strategies**: Imports the entrypoint class and verifies it's a subclass of `Strategy`
348
- - Uses Python's `__import__()` to dynamically import the module and class
349
- - Catches import errors, missing classes, and type mismatches
350
-
351
- 3. **Dependency Verification** (adapters only):
352
- - Validates that all declared dependencies (e.g., `PoolClient`, `TokenClient`) exist in `core.clients`
353
- - Attempts to import each dependency as `core.clients.{DepName}`
354
-
355
- 4. **Permissions Validation** (strategies only):
356
- - Validated by Pydantic: ensures `permissions.policy` exists and is non-empty
357
- - Policy syntax is not parsed/validated (assumed to be valid at runtime)
358
-
359
- **Validation Flow:**
360
-
361
- ```
362
- For each manifest file:
363
- 1. Load YAML → Parse with Pydantic (schema validation)
364
- 2. Import entrypoint class → Verify inheritance (entrypoint validation)
365
- 3. For adapters: Import dependencies → Verify they exist (dependency validation)
366
- 4. Collect all errors → Report results
367
- ```
368
-
369
- The script automatically discovers all manifests by scanning:
370
-
371
- - `wayfinder_paths/adapters/*/manifest.yaml` for adapter manifests
372
- - `wayfinder_paths/strategies/*/manifest.yaml` for strategy manifests
373
-
374
- All errors are collected and reported at the end, with the script exiting with code 1 if any validation fails.
375
-
376
- #### Capabilities
377
-
378
- 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.
379
-
380
- When creating an adapter:
381
-
382
- 1. Declare capabilities in your `manifest.yaml`
383
- 2. Implement methods that fulfill those capabilities
384
- 3. Capabilities are validated at manifest validation time (entrypoint must be importable)
385
-
386
210
  ### Configuration
387
211
 
388
212
  Configuration is split between:
@@ -473,7 +297,7 @@ class MyAdapter(BaseAdapter):
473
297
  self.pool_client = PoolClient()
474
298
 
475
299
  async def connect(self) -> bool:
476
- """No-op for read-only adapters, but kept for manifest compatibility."""
300
+ """No-op for read-only adapters, but kept for interface consistency."""
477
301
  return True
478
302
 
479
303
  async def get_pools(self, pool_ids: list[str]):
@@ -546,6 +370,54 @@ class MyStrategy(Strategy):
546
370
  }
547
371
  ```
548
372
 
373
+ ### Built-in Strategies
374
+
375
+ The following strategies are available and can be run using the CLI:
376
+
377
+ | Strategy | Description | Chain |
378
+ | --------------------------------- | --------------------------- | -------- |
379
+ | `basis_trading_strategy` | Delta-neutral basis trading | - |
380
+ | `hyperlend_stable_yield_strategy` | Stable yield on HyperLend | HyperEVM |
381
+ | `moonwell_wsteth_loop_strategy` | Leveraged wstETH yield loop | Base |
382
+
383
+ #### Running Strategies
384
+
385
+ ```bash
386
+ # Check strategy status
387
+ poetry run python wayfinder_paths/scripts/run_strategy.py \
388
+ --strategy moonwell_wsteth_loop_strategy \
389
+ --main-wallet-label main \
390
+ --strategy-wallet-label moonwell_wsteth_loop_strategy \
391
+ status
392
+
393
+ # Deposit funds (USDC amount, optional ETH for gas)
394
+ poetry run python wayfinder_paths/scripts/run_strategy.py \
395
+ --strategy moonwell_wsteth_loop_strategy \
396
+ --main-wallet-label main \
397
+ --strategy-wallet-label moonwell_wsteth_loop_strategy \
398
+ deposit --usdc 100 --eth 0.01
399
+
400
+ # Run periodic update
401
+ poetry run python wayfinder_paths/scripts/run_strategy.py \
402
+ --strategy moonwell_wsteth_loop_strategy \
403
+ --main-wallet-label main \
404
+ --strategy-wallet-label moonwell_wsteth_loop_strategy \
405
+ update
406
+
407
+ # Withdraw funds (omit --amount for full withdrawal)
408
+ poetry run python wayfinder_paths/scripts/run_strategy.py \
409
+ --strategy moonwell_wsteth_loop_strategy \
410
+ --main-wallet-label main \
411
+ --strategy-wallet-label moonwell_wsteth_loop_strategy \
412
+ withdraw --amount 50
413
+
414
+ # Run in simulation mode (no real transactions)
415
+ poetry run python wayfinder_paths/scripts/run_strategy.py \
416
+ --strategy moonwell_wsteth_loop_strategy \
417
+ --simulation \
418
+ status
419
+ ```
420
+
549
421
  ### Built-in adapters
550
422
 
551
423
  - **BALANCE (BalanceAdapter)**: wraps `WalletClient`/`TokenClient` to read wallet, token, and pool balances and now orchestrates transfers between the main/strategy wallets with ledger bookkeeping. Requires a `Web3Service` so it can share the same wallet provider as the strategy.
@@ -554,8 +426,9 @@ class MyStrategy(Strategy):
554
426
  - **LEDGER (LedgerAdapter)**: records deposits, withdrawals, custom operations, and cashflows via `LedgerClient`, and can read strategy transaction summaries.
555
427
  - **TOKEN (TokenAdapter)**: lightweight wrapper around `TokenClient` for token metadata, live price snapshots, and gas token lookups.
556
428
  - **HYPERLEND (HyperlendAdapter)**: connects to `HyperlendClient` for lending/supply caps inside the HyperLend strategy.
429
+ - **MOONWELL (MoonwellAdapter)**: interfaces with Moonwell protocol on Base for lending, borrowing, collateral management, and WELL rewards.
557
430
 
558
- Each strategy manifest declares which adapters it needs and which capabilities it consumes. Adapters must implement the behavior promised in their manifest (or raise `NotImplementedError` if invoked outside the manifest contract).
431
+ Strategies register the adapters they need in their `__init__` method. Adapters implement their specific capabilities and raise `NotImplementedError` for unsupported operations.
559
432
 
560
433
  ## 🧪 Testing
561
434