wayfinder-paths 0.1.3__py3-none-any.whl → 0.1.5__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/CONFIG_GUIDE.md +37 -32
- wayfinder_paths/__init__.py +3 -3
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/README.md +12 -12
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/adapter.py +12 -11
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/examples.json +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/balance_adapter/test_adapter.py +12 -6
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/README.md +2 -2
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/adapter.py +30 -23
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/test_adapter.py +2 -2
- wayfinder_paths/adapters/hyperlend_adapter/__init__.py +7 -0
- wayfinder_paths/{vaults/adapters → adapters}/hyperlend_adapter/adapter.py +33 -26
- wayfinder_paths/{vaults/adapters → adapters}/hyperlend_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/hyperlend_adapter/test_adapter.py +2 -2
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/README.md +27 -40
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/adapter.py +78 -75
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/examples.json +10 -4
- wayfinder_paths/adapters/ledger_adapter/manifest.yaml +11 -0
- wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/test_adapter.py +33 -28
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/README.md +2 -14
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/adapter.py +12 -19
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/test_adapter.py +2 -2
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/README.md +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/adapter.py +8 -4
- wayfinder_paths/adapters/token_adapter/examples.json +26 -0
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/adapters → adapters}/token_adapter/test_adapter.py +1 -1
- wayfinder_paths/config.example.json +3 -1
- wayfinder_paths/core/__init__.py +3 -3
- wayfinder_paths/core/adapters/BaseAdapter.py +20 -3
- wayfinder_paths/core/adapters/models.py +41 -0
- wayfinder_paths/core/clients/BRAPClient.py +21 -2
- wayfinder_paths/core/clients/ClientManager.py +42 -63
- wayfinder_paths/core/clients/HyperlendClient.py +46 -5
- wayfinder_paths/core/clients/LedgerClient.py +350 -124
- wayfinder_paths/core/clients/PoolClient.py +51 -19
- wayfinder_paths/core/clients/SimulationClient.py +16 -4
- wayfinder_paths/core/clients/TokenClient.py +34 -18
- wayfinder_paths/core/clients/TransactionClient.py +18 -2
- wayfinder_paths/core/clients/WalletClient.py +35 -4
- wayfinder_paths/core/clients/WayfinderClient.py +16 -5
- wayfinder_paths/core/clients/protocols.py +69 -62
- wayfinder_paths/core/clients/sdk_example.py +0 -5
- wayfinder_paths/core/config.py +192 -103
- wayfinder_paths/core/constants/base.py +17 -0
- wayfinder_paths/core/engine/{VaultJob.py → StrategyJob.py} +25 -19
- wayfinder_paths/core/engine/__init__.py +2 -2
- wayfinder_paths/core/engine/manifest.py +1 -1
- wayfinder_paths/core/services/base.py +6 -4
- wayfinder_paths/core/services/local_evm_txn.py +3 -2
- wayfinder_paths/core/settings.py +2 -2
- wayfinder_paths/core/strategies/Strategy.py +123 -37
- wayfinder_paths/core/utils/evm_helpers.py +12 -10
- wayfinder_paths/core/wallets/README.md +3 -3
- wayfinder_paths/core/wallets/WalletManager.py +3 -3
- wayfinder_paths/{vaults/policies → policies}/enso.py +1 -1
- wayfinder_paths/{vaults/policies → policies}/hyper_evm.py +2 -2
- wayfinder_paths/{vaults/policies → policies}/hyperlend.py +1 -1
- wayfinder_paths/{vaults/policies → policies}/moonwell.py +1 -1
- wayfinder_paths/{vaults/policies → policies}/prjx.py +1 -1
- wayfinder_paths/run_strategy.py +29 -27
- wayfinder_paths/scripts/create_strategy.py +3 -3
- wayfinder_paths/scripts/make_wallets.py +6 -6
- wayfinder_paths/scripts/validate_manifests.py +2 -2
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/README.md +10 -9
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/manifest.yaml +1 -1
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/strategy.py +47 -167
- wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/test_strategy.py +10 -8
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/README.md +15 -14
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/manifest.yaml +2 -2
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/strategy.py +97 -97
- wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/test_strategy.py +8 -8
- wayfinder_paths/{vaults/templates → templates}/adapter/README.md +5 -5
- wayfinder_paths/{vaults/templates → templates}/adapter/manifest.yaml +1 -1
- wayfinder_paths/{vaults/templates → templates}/adapter/test_adapter.py +1 -1
- wayfinder_paths/{vaults/templates → templates}/strategy/README.md +10 -9
- wayfinder_paths/{vaults/templates → templates}/strategy/manifest.yaml +1 -1
- wayfinder_paths/{vaults/templates → templates}/strategy/test_strategy.py +8 -8
- wayfinder_paths/tests/test_test_coverage.py +5 -5
- {wayfinder_paths-0.1.3.dist-info → wayfinder_paths-0.1.5.dist-info}/METADATA +146 -69
- wayfinder_paths-0.1.5.dist-info/RECORD +126 -0
- wayfinder_paths/vaults/adapters/hyperlend_adapter/__init__.py +0 -7
- wayfinder_paths/vaults/adapters/ledger_adapter/manifest.yaml +0 -11
- wayfinder_paths/vaults/adapters/token_adapter/examples.json +0 -26
- wayfinder_paths/vaults/strategies/__init__.py +0 -0
- wayfinder_paths-0.1.3.dist-info/RECORD +0 -126
- /wayfinder_paths/{vaults → adapters}/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/brap_adapter/examples.json +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/ledger_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/pool_adapter/examples.json +0 -0
- /wayfinder_paths/{vaults/adapters → adapters}/token_adapter/__init__.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/erc20.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/evm.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/hyperliquid.py +0 -0
- /wayfinder_paths/{vaults/policies → policies}/util.py +0 -0
- /wayfinder_paths/{vaults/adapters → strategies}/__init__.py +0 -0
- /wayfinder_paths/{vaults/strategies → strategies}/config.py +0 -0
- /wayfinder_paths/{vaults/strategies → strategies}/hyperlend_stable_yield_strategy/examples.json +0 -0
- /wayfinder_paths/{vaults/strategies → strategies}/stablecoin_yield_strategy/examples.json +0 -0
- /wayfinder_paths/{vaults/templates → templates}/adapter/adapter.py +0 -0
- /wayfinder_paths/{vaults/templates → templates}/adapter/examples.json +0 -0
- /wayfinder_paths/{vaults/templates → templates}/strategy/examples.json +0 -0
- /wayfinder_paths/{vaults/templates → templates}/strategy/strategy.py +0 -0
- {wayfinder_paths-0.1.3.dist-info → wayfinder_paths-0.1.5.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.3.dist-info → wayfinder_paths-0.1.5.dist-info}/WHEEL +0 -0
|
@@ -6,9 +6,9 @@ Adapters expose protocol-specific capabilities to strategies. They should be thi
|
|
|
6
6
|
|
|
7
7
|
1. Copy the template:
|
|
8
8
|
```
|
|
9
|
-
cp -r wayfinder_paths/
|
|
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 (`
|
|
11
|
+
2. Rename `MyAdapter` in `adapter.py` and update `manifest.yaml` so the `entrypoint` matches (`adapters.my_adapter.adapter.MyAdapter`).
|
|
12
12
|
3. Declare the capabilities your adapter will provide and list any client dependencies (e.g., `PoolClient`, `LedgerClient`).
|
|
13
13
|
4. Implement the public methods that fulfill those capabilities.
|
|
14
14
|
|
|
@@ -63,7 +63,7 @@ Every adapter needs a manifest describing its import path, declared capabilities
|
|
|
63
63
|
|
|
64
64
|
```yaml
|
|
65
65
|
schema_version: "0.1"
|
|
66
|
-
entrypoint: "
|
|
66
|
+
entrypoint: "adapters.my_adapter.adapter.MyAdapter"
|
|
67
67
|
capabilities:
|
|
68
68
|
- "pool.read"
|
|
69
69
|
dependencies:
|
|
@@ -80,13 +80,13 @@ The `dependencies` list is informational today but helps reviewers understand wh
|
|
|
80
80
|
import pytest
|
|
81
81
|
from unittest.mock import AsyncMock, patch
|
|
82
82
|
|
|
83
|
-
from wayfinder_paths.
|
|
83
|
+
from wayfinder_paths.adapters.my_adapter.adapter import MyAdapter
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
@pytest.mark.asyncio
|
|
87
87
|
async def test_get_pools():
|
|
88
88
|
with patch(
|
|
89
|
-
"wayfinder_paths.
|
|
89
|
+
"wayfinder_paths.adapters.my_adapter.adapter.PoolClient",
|
|
90
90
|
return_value=AsyncMock(
|
|
91
91
|
get_pools_by_ids=AsyncMock(return_value={"pools": []})
|
|
92
92
|
),
|
|
@@ -4,7 +4,7 @@ Quick setup:
|
|
|
4
4
|
1. Replace MyAdapter with your actual adapter class name
|
|
5
5
|
2. Implement test_basic_functionality with your adapter's core methods
|
|
6
6
|
3. Add client mocking if your adapter uses external clients
|
|
7
|
-
4. Run: pytest
|
|
7
|
+
4. Run: pytest wayfinder_paths/adapters/your_adapter/ -v
|
|
8
8
|
|
|
9
9
|
Note: examples.json is optional for adapters (not required).
|
|
10
10
|
"""
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Strategy Template
|
|
2
2
|
|
|
3
|
-
This template provides the scaffolding for a new
|
|
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.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
1. Copy the template to a new folder:
|
|
8
8
|
```
|
|
9
|
-
cp -r wayfinder_paths/
|
|
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 `
|
|
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`).
|
|
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
|
|
|
@@ -27,7 +27,7 @@ my_strategy/
|
|
|
27
27
|
|
|
28
28
|
```python
|
|
29
29
|
async def deposit(self, main_token_amount: float, gas_token_amount: float) -> StatusTuple:
|
|
30
|
-
"""Move funds from the main wallet into the
|
|
30
|
+
"""Move funds from the main wallet into the strategy wallet and prepare on-chain positions."""
|
|
31
31
|
|
|
32
32
|
async def update(self) -> StatusTuple:
|
|
33
33
|
"""Periodic rebalance/update loop."""
|
|
@@ -49,7 +49,7 @@ Strategies typically:
|
|
|
49
49
|
```python
|
|
50
50
|
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
51
51
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
52
|
-
from wayfinder_paths.
|
|
52
|
+
from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
class MyStrategy(Strategy):
|
|
@@ -89,7 +89,7 @@ class MyStrategy(Strategy):
|
|
|
89
89
|
"""Surface state back to run_strategy.py."""
|
|
90
90
|
success, balance = await self.balance_adapter.get_balance(
|
|
91
91
|
token_id=self.config.get("token_id"),
|
|
92
|
-
wallet_address=self.config.get("
|
|
92
|
+
wallet_address=self.config.get("strategy_wallet", {}).get("address"),
|
|
93
93
|
)
|
|
94
94
|
return {
|
|
95
95
|
"portfolio_value": float(balance or 0),
|
|
@@ -104,7 +104,7 @@ Your `manifest.yaml` should define:
|
|
|
104
104
|
|
|
105
105
|
```yaml
|
|
106
106
|
schema_version: "0.1"
|
|
107
|
-
entrypoint: "
|
|
107
|
+
entrypoint: "strategies.my_strategy.strategy.MyStrategy"
|
|
108
108
|
permissions:
|
|
109
109
|
policy: "(wallet.id == 'FORMAT_WALLET_ID') && (eth.tx.to == '0x...')"
|
|
110
110
|
adapters:
|
|
@@ -120,7 +120,7 @@ adapters:
|
|
|
120
120
|
|
|
121
121
|
```python
|
|
122
122
|
import pytest
|
|
123
|
-
from wayfinder_paths.
|
|
123
|
+
from wayfinder_paths.strategies.my_strategy.strategy import MyStrategy
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
@pytest.mark.asyncio
|
|
@@ -135,7 +135,8 @@ async def test_status_shape():
|
|
|
135
135
|
```bash
|
|
136
136
|
# Install dependencies & create wallets first
|
|
137
137
|
poetry install
|
|
138
|
-
|
|
138
|
+
# Creates a main wallet (or use 'just create-strategy' which auto-creates wallets)
|
|
139
|
+
poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
|
|
139
140
|
|
|
140
141
|
# Copy config and edit credentials
|
|
141
142
|
cp wayfinder_paths/config.example.json config.json
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
schema_version: "0.1"
|
|
2
|
-
entrypoint: "
|
|
2
|
+
entrypoint: "strategies.my_strategy.strategy.MyStrategy"
|
|
3
3
|
name: "my_strategy" # Unique name for this strategy instance (used for wallet lookup)
|
|
4
4
|
permissions:
|
|
5
5
|
policy: "(wallet.id == 'FORMAT_WALLET_ID')"
|
|
@@ -7,14 +7,14 @@ Quick setup:
|
|
|
7
7
|
1. Replace MyStrategy with your strategy class name
|
|
8
8
|
2. Create examples.json with a 'smoke' example (see TESTING.md)
|
|
9
9
|
3. Add mocking if your strategy uses adapters
|
|
10
|
-
4. Run: pytest
|
|
10
|
+
4. Run: pytest wayfinder_paths/strategies/your_strategy/ -v
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
import sys
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
16
|
# TODO: Replace MyStrategy with your actual strategy class name
|
|
17
|
-
from wayfinder_paths.
|
|
17
|
+
from wayfinder_paths.strategies.your_strategy.strategy import (
|
|
18
18
|
MyStrategy, # noqa: E402
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -51,13 +51,13 @@ def strategy():
|
|
|
51
51
|
"""Create a strategy instance for testing with minimal config."""
|
|
52
52
|
mock_config = {
|
|
53
53
|
"main_wallet": {"address": "0x1234567890123456789012345678901234567890"},
|
|
54
|
-
"
|
|
54
|
+
"strategy_wallet": {"address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"},
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
s = MyStrategy(
|
|
58
58
|
config=mock_config,
|
|
59
59
|
main_wallet=mock_config["main_wallet"],
|
|
60
|
-
|
|
60
|
+
strategy_wallet=mock_config["strategy_wallet"],
|
|
61
61
|
simulation=True,
|
|
62
62
|
)
|
|
63
63
|
|
|
@@ -96,19 +96,19 @@ def strategy():
|
|
|
96
96
|
|
|
97
97
|
# Example for transaction adapters:
|
|
98
98
|
# if hasattr(s, "tx_adapter") and s.tx_adapter:
|
|
99
|
-
# s.tx_adapter.
|
|
99
|
+
# s.tx_adapter.move_from_main_wallet_to_strategy_wallet = AsyncMock(
|
|
100
100
|
# return_value=(True, "Transfer successful (simulated)")
|
|
101
101
|
# )
|
|
102
|
-
# s.tx_adapter.
|
|
102
|
+
# s.tx_adapter.move_from_strategy_wallet_to_main_wallet = AsyncMock(
|
|
103
103
|
# return_value=(True, "Transfer successful (simulated)")
|
|
104
104
|
# )
|
|
105
105
|
|
|
106
106
|
# Example for ledger_adapter:
|
|
107
107
|
# if hasattr(s, "ledger_adapter") and s.ledger_adapter:
|
|
108
|
-
# s.ledger_adapter.
|
|
108
|
+
# s.ledger_adapter.get_strategy_net_deposit = AsyncMock(
|
|
109
109
|
# return_value=(True, {"net_deposit": 0})
|
|
110
110
|
# )
|
|
111
|
-
# s.ledger_adapter.
|
|
111
|
+
# s.ledger_adapter.get_strategy_transactions = AsyncMock(
|
|
112
112
|
# return_value=(True, {"transactions": []})
|
|
113
113
|
# )
|
|
114
114
|
|
|
@@ -7,7 +7,7 @@ import pytest
|
|
|
7
7
|
|
|
8
8
|
def test_all_adapters_have_tests():
|
|
9
9
|
"""Verify that all adapters have a test_adapter.py file."""
|
|
10
|
-
adapters_dir = Path(__file__).parent.parent / "
|
|
10
|
+
adapters_dir = Path(__file__).parent.parent / "adapters"
|
|
11
11
|
|
|
12
12
|
if not adapters_dir.exists():
|
|
13
13
|
pytest.skip("Adapters directory not found")
|
|
@@ -36,7 +36,7 @@ def test_all_adapters_have_tests():
|
|
|
36
36
|
|
|
37
37
|
def test_all_strategies_have_tests():
|
|
38
38
|
"""Verify that all strategies have a test_strategy.py file."""
|
|
39
|
-
strategies_dir = Path(__file__).parent.parent / "
|
|
39
|
+
strategies_dir = Path(__file__).parent.parent / "strategies"
|
|
40
40
|
|
|
41
41
|
if not strategies_dir.exists():
|
|
42
42
|
pytest.skip("Strategies directory not found")
|
|
@@ -65,7 +65,7 @@ def test_all_strategies_have_tests():
|
|
|
65
65
|
|
|
66
66
|
def test_all_strategies_have_examples_json():
|
|
67
67
|
"""Verify that all strategies have an examples.json file (REQUIRED)."""
|
|
68
|
-
strategies_dir = Path(__file__).parent.parent / "
|
|
68
|
+
strategies_dir = Path(__file__).parent.parent / "strategies"
|
|
69
69
|
|
|
70
70
|
if not strategies_dir.exists():
|
|
71
71
|
pytest.skip("Strategies directory not found")
|
|
@@ -95,7 +95,7 @@ def test_all_strategies_have_examples_json():
|
|
|
95
95
|
|
|
96
96
|
def test_strategy_tests_use_examples_json():
|
|
97
97
|
"""Verify that strategy test files load examples.json using the shared utility."""
|
|
98
|
-
strategies_dir = Path(__file__).parent.parent / "
|
|
98
|
+
strategies_dir = Path(__file__).parent.parent / "strategies"
|
|
99
99
|
|
|
100
100
|
if not strategies_dir.exists():
|
|
101
101
|
pytest.skip("Strategies directory not found")
|
|
@@ -167,7 +167,7 @@ def test_strategy_tests_use_examples_json():
|
|
|
167
167
|
|
|
168
168
|
def test_strategy_examples_have_smoke():
|
|
169
169
|
"""Verify that all strategy examples.json files have a 'smoke' entry."""
|
|
170
|
-
strategies_dir = Path(__file__).parent.parent / "
|
|
170
|
+
strategies_dir = Path(__file__).parent.parent / "strategies"
|
|
171
171
|
|
|
172
172
|
if not strategies_dir.exists():
|
|
173
173
|
pytest.skip("Strategies directory not found")
|