wayfinder-paths 0.1.7__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 +399 -0
- wayfinder_paths/__init__.py +22 -0
- wayfinder_paths/abis/generic/erc20.json +383 -0
- wayfinder_paths/adapters/__init__.py +0 -0
- wayfinder_paths/adapters/balance_adapter/README.md +94 -0
- wayfinder_paths/adapters/balance_adapter/adapter.py +238 -0
- wayfinder_paths/adapters/balance_adapter/examples.json +6 -0
- wayfinder_paths/adapters/balance_adapter/manifest.yaml +8 -0
- wayfinder_paths/adapters/balance_adapter/test_adapter.py +59 -0
- wayfinder_paths/adapters/brap_adapter/README.md +249 -0
- wayfinder_paths/adapters/brap_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/brap_adapter/adapter.py +726 -0
- wayfinder_paths/adapters/brap_adapter/examples.json +175 -0
- wayfinder_paths/adapters/brap_adapter/manifest.yaml +11 -0
- wayfinder_paths/adapters/brap_adapter/test_adapter.py +286 -0
- wayfinder_paths/adapters/hyperlend_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +305 -0
- wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml +10 -0
- wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +274 -0
- wayfinder_paths/adapters/hyperliquid_adapter/__init__.py +18 -0
- wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +1093 -0
- wayfinder_paths/adapters/hyperliquid_adapter/executor.py +549 -0
- wayfinder_paths/adapters/hyperliquid_adapter/manifest.yaml +8 -0
- wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +1050 -0
- wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +126 -0
- wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +219 -0
- wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +220 -0
- wayfinder_paths/adapters/hyperliquid_adapter/utils.py +134 -0
- wayfinder_paths/adapters/ledger_adapter/README.md +145 -0
- wayfinder_paths/adapters/ledger_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/ledger_adapter/adapter.py +289 -0
- wayfinder_paths/adapters/ledger_adapter/examples.json +137 -0
- wayfinder_paths/adapters/ledger_adapter/manifest.yaml +11 -0
- wayfinder_paths/adapters/ledger_adapter/test_adapter.py +205 -0
- wayfinder_paths/adapters/pool_adapter/README.md +206 -0
- wayfinder_paths/adapters/pool_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/pool_adapter/adapter.py +282 -0
- wayfinder_paths/adapters/pool_adapter/examples.json +143 -0
- wayfinder_paths/adapters/pool_adapter/manifest.yaml +10 -0
- wayfinder_paths/adapters/pool_adapter/test_adapter.py +220 -0
- wayfinder_paths/adapters/token_adapter/README.md +101 -0
- wayfinder_paths/adapters/token_adapter/__init__.py +3 -0
- wayfinder_paths/adapters/token_adapter/adapter.py +96 -0
- wayfinder_paths/adapters/token_adapter/examples.json +26 -0
- wayfinder_paths/adapters/token_adapter/manifest.yaml +6 -0
- wayfinder_paths/adapters/token_adapter/test_adapter.py +125 -0
- wayfinder_paths/config.example.json +22 -0
- wayfinder_paths/conftest.py +31 -0
- wayfinder_paths/core/__init__.py +18 -0
- wayfinder_paths/core/adapters/BaseAdapter.py +65 -0
- wayfinder_paths/core/adapters/__init__.py +5 -0
- wayfinder_paths/core/adapters/base.py +5 -0
- wayfinder_paths/core/adapters/models.py +46 -0
- wayfinder_paths/core/analytics/__init__.py +11 -0
- wayfinder_paths/core/analytics/bootstrap.py +57 -0
- wayfinder_paths/core/analytics/stats.py +48 -0
- wayfinder_paths/core/analytics/test_analytics.py +170 -0
- wayfinder_paths/core/clients/AuthClient.py +83 -0
- wayfinder_paths/core/clients/BRAPClient.py +109 -0
- wayfinder_paths/core/clients/ClientManager.py +210 -0
- wayfinder_paths/core/clients/HyperlendClient.py +192 -0
- wayfinder_paths/core/clients/LedgerClient.py +443 -0
- wayfinder_paths/core/clients/PoolClient.py +128 -0
- wayfinder_paths/core/clients/SimulationClient.py +192 -0
- wayfinder_paths/core/clients/TokenClient.py +89 -0
- wayfinder_paths/core/clients/TransactionClient.py +63 -0
- wayfinder_paths/core/clients/WalletClient.py +94 -0
- wayfinder_paths/core/clients/WayfinderClient.py +269 -0
- wayfinder_paths/core/clients/__init__.py +48 -0
- wayfinder_paths/core/clients/protocols.py +392 -0
- wayfinder_paths/core/clients/sdk_example.py +110 -0
- wayfinder_paths/core/config.py +458 -0
- wayfinder_paths/core/constants/__init__.py +26 -0
- wayfinder_paths/core/constants/base.py +42 -0
- wayfinder_paths/core/constants/erc20_abi.py +118 -0
- wayfinder_paths/core/constants/hyperlend_abi.py +152 -0
- wayfinder_paths/core/engine/StrategyJob.py +188 -0
- wayfinder_paths/core/engine/__init__.py +5 -0
- wayfinder_paths/core/engine/manifest.py +97 -0
- wayfinder_paths/core/services/__init__.py +0 -0
- wayfinder_paths/core/services/base.py +179 -0
- wayfinder_paths/core/services/local_evm_txn.py +430 -0
- wayfinder_paths/core/services/local_token_txn.py +231 -0
- wayfinder_paths/core/services/web3_service.py +45 -0
- wayfinder_paths/core/settings.py +61 -0
- wayfinder_paths/core/strategies/Strategy.py +280 -0
- wayfinder_paths/core/strategies/__init__.py +5 -0
- wayfinder_paths/core/strategies/base.py +7 -0
- wayfinder_paths/core/strategies/descriptors.py +81 -0
- wayfinder_paths/core/utils/__init__.py +1 -0
- wayfinder_paths/core/utils/evm_helpers.py +206 -0
- wayfinder_paths/core/utils/wallets.py +77 -0
- wayfinder_paths/core/wallets/README.md +91 -0
- wayfinder_paths/core/wallets/WalletManager.py +56 -0
- wayfinder_paths/core/wallets/__init__.py +7 -0
- wayfinder_paths/policies/enso.py +17 -0
- wayfinder_paths/policies/erc20.py +34 -0
- wayfinder_paths/policies/evm.py +21 -0
- wayfinder_paths/policies/hyper_evm.py +19 -0
- wayfinder_paths/policies/hyperlend.py +12 -0
- wayfinder_paths/policies/hyperliquid.py +30 -0
- wayfinder_paths/policies/moonwell.py +54 -0
- wayfinder_paths/policies/prjx.py +30 -0
- wayfinder_paths/policies/util.py +27 -0
- wayfinder_paths/run_strategy.py +411 -0
- wayfinder_paths/scripts/__init__.py +0 -0
- wayfinder_paths/scripts/create_strategy.py +181 -0
- wayfinder_paths/scripts/make_wallets.py +169 -0
- wayfinder_paths/scripts/run_strategy.py +124 -0
- wayfinder_paths/scripts/validate_manifests.py +213 -0
- wayfinder_paths/strategies/__init__.py +0 -0
- wayfinder_paths/strategies/basis_trading_strategy/README.md +213 -0
- wayfinder_paths/strategies/basis_trading_strategy/__init__.py +3 -0
- wayfinder_paths/strategies/basis_trading_strategy/constants.py +1 -0
- wayfinder_paths/strategies/basis_trading_strategy/examples.json +16 -0
- wayfinder_paths/strategies/basis_trading_strategy/manifest.yaml +23 -0
- wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +1011 -0
- wayfinder_paths/strategies/basis_trading_strategy/strategy.py +4522 -0
- wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +727 -0
- wayfinder_paths/strategies/basis_trading_strategy/types.py +39 -0
- wayfinder_paths/strategies/config.py +85 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +100 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/examples.json +8 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/manifest.yaml +7 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +2270 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +352 -0
- wayfinder_paths/strategies/stablecoin_yield_strategy/README.md +96 -0
- wayfinder_paths/strategies/stablecoin_yield_strategy/examples.json +17 -0
- wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml +17 -0
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +1810 -0
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +520 -0
- wayfinder_paths/templates/adapter/README.md +105 -0
- wayfinder_paths/templates/adapter/adapter.py +26 -0
- wayfinder_paths/templates/adapter/examples.json +8 -0
- wayfinder_paths/templates/adapter/manifest.yaml +6 -0
- wayfinder_paths/templates/adapter/test_adapter.py +49 -0
- wayfinder_paths/templates/strategy/README.md +153 -0
- wayfinder_paths/templates/strategy/examples.json +11 -0
- wayfinder_paths/templates/strategy/manifest.yaml +8 -0
- wayfinder_paths/templates/strategy/strategy.py +57 -0
- wayfinder_paths/templates/strategy/test_strategy.py +197 -0
- wayfinder_paths/tests/__init__.py +0 -0
- wayfinder_paths/tests/test_smoke_manifest.py +48 -0
- wayfinder_paths/tests/test_test_coverage.py +212 -0
- wayfinder_paths/tests/test_utils.py +64 -0
- wayfinder_paths-0.1.7.dist-info/LICENSE +21 -0
- wayfinder_paths-0.1.7.dist-info/METADATA +777 -0
- wayfinder_paths-0.1.7.dist-info/RECORD +149 -0
- wayfinder_paths-0.1.7.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: wayfinder-paths
|
|
3
|
+
Version: 0.1.7
|
|
4
|
+
Summary: Wayfinder Path: strategies and adapters
|
|
5
|
+
Author: Wayfinder
|
|
6
|
+
Author-email: dev@wayfinder.ai
|
|
7
|
+
Requires-Python: >=3.12,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Requires-Dist: aiohttp (>=3.13.0,<4.0.0)
|
|
11
|
+
Requires-Dist: eth-account (>=0.13.7,<0.14.0)
|
|
12
|
+
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
13
|
+
Requires-Dist: hyperliquid-python-sdk (>=0.21.0,<0.22.0)
|
|
14
|
+
Requires-Dist: loguru (>=0.7.3,<0.8.0)
|
|
15
|
+
Requires-Dist: numpy (>=1.26.0,<2.0.0)
|
|
16
|
+
Requires-Dist: pandas (>=2.2.0,<3.0.0)
|
|
17
|
+
Requires-Dist: pydantic (>=2.11.9,<3.0.0)
|
|
18
|
+
Requires-Dist: pydantic-settings (>=2.7.0,<3.0.0)
|
|
19
|
+
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
|
20
|
+
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
21
|
+
Requires-Dist: web3 (>=7.13.0,<8.0.0)
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# 🔐 Wayfinder Paths
|
|
25
|
+
|
|
26
|
+
[](https://www.python.org/downloads/)
|
|
27
|
+
[](https://www.docker.com/)
|
|
28
|
+
[](https://discord.gg/fUVwGMXjm3)
|
|
29
|
+
|
|
30
|
+
Open-source platform for community-contributed crypto trading strategies and adapters. Build, test, and deploy automated trading strategies with direct wallet integration.
|
|
31
|
+
|
|
32
|
+
## 🚀 Quick Start
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Clone the repository
|
|
36
|
+
git clone https://github.com/wayfinder-ai/wayfinder-paths.git
|
|
37
|
+
cd wayfinder-paths
|
|
38
|
+
|
|
39
|
+
# Install Poetry (if not already installed)
|
|
40
|
+
curl -sSL https://install.python-poetry.org | python3 -
|
|
41
|
+
|
|
42
|
+
# Install dependencies
|
|
43
|
+
poetry install
|
|
44
|
+
|
|
45
|
+
# ⚠️ Generate test wallets FIRST (required!)
|
|
46
|
+
# This creates wallets.json with a main wallet for local testing
|
|
47
|
+
just create-wallets
|
|
48
|
+
# Or manually: poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
|
|
49
|
+
|
|
50
|
+
# Copy and configure
|
|
51
|
+
cp wayfinder_paths/config.example.json config.json
|
|
52
|
+
# Edit config.json with your Wayfinder credentials
|
|
53
|
+
|
|
54
|
+
# Run a strategy locally (one-shot status check)
|
|
55
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --action status --config config.json
|
|
56
|
+
|
|
57
|
+
export WAYFINDER_API_KEY="sk_live_abc123..."
|
|
58
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --config config.json
|
|
59
|
+
|
|
60
|
+
# Run continuously (production mode)
|
|
61
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --config config.json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 📁 Repository Structure
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
wayfinder_paths/
|
|
68
|
+
├── wayfinder_paths/ # Main package directory
|
|
69
|
+
│ ├── core/ # Core engine (maintained by team)
|
|
70
|
+
│ │ ├── clients/ # API client managers
|
|
71
|
+
│ │ ├── adapters/ # Base adapter interfaces
|
|
72
|
+
│ │ ├── engine/ # Trading engine & StrategyJob
|
|
73
|
+
│ │ ├── strategies/ # Base strategy classes
|
|
74
|
+
│ │ └── config.py # Configuration system
|
|
75
|
+
│ ├── adapters/ # Your exchange/protocol integrations (community contributions)
|
|
76
|
+
│ │ ├── balance_adapter/
|
|
77
|
+
│ │ │ ├── adapter.py # Adapter implementation
|
|
78
|
+
│ │ │ ├── manifest.yaml # Adapter manifest (caps, entrypoint)
|
|
79
|
+
│ │ │ ├── examples.json # Example inputs for smoke
|
|
80
|
+
│ │ │ ├── README.md # Local notes
|
|
81
|
+
│ │ │ └── test_adapter.py # Local smoke test
|
|
82
|
+
│ │ ├── brap_adapter/
|
|
83
|
+
│ │ └── ...
|
|
84
|
+
│ ├── strategies/ # Your trading strategies (community contributions)
|
|
85
|
+
│ │ ├── stablecoin_yield_strategy/
|
|
86
|
+
│ │ │ ├── strategy.py # Strategy implementation
|
|
87
|
+
│ │ │ ├── manifest.yaml # Strategy manifest
|
|
88
|
+
│ │ │ ├── examples.json # Example inputs
|
|
89
|
+
│ │ │ ├── README.md # Local notes
|
|
90
|
+
│ │ │ └── test_strategy.py # Local smoke test
|
|
91
|
+
│ │ └── ...
|
|
92
|
+
│ ├── tests/ # Test suite
|
|
93
|
+
│ ├── CONFIG_GUIDE.md # Configuration documentation
|
|
94
|
+
│ ├── config.example.json # Example configuration
|
|
95
|
+
│ ├── scripts/ # Utility scripts
|
|
96
|
+
│ └── run_strategy.py # Strategy runner script
|
|
97
|
+
├── config.json # Your local config (created by you)
|
|
98
|
+
├── wallets.json # Generated dev wallets
|
|
99
|
+
├── pyproject.toml # Poetry configuration
|
|
100
|
+
└── README.md # This file
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 🤝 Contributing
|
|
104
|
+
|
|
105
|
+
We welcome contributions! This is an open-source project where community members can contribute adapters and strategies.
|
|
106
|
+
|
|
107
|
+
### Quick Contribution Guide
|
|
108
|
+
|
|
109
|
+
1. **Fork the repository** and clone your fork
|
|
110
|
+
2. **Create a feature branch**: `git checkout -b feature/my-strategy`
|
|
111
|
+
3. **Copy a template** to get started:
|
|
112
|
+
- **For adapters**: Copy `wayfinder_paths/templates/adapter/` to `wayfinder_paths/adapters/my_adapter/`
|
|
113
|
+
- **For strategies**: Copy `wayfinder_paths/templates/strategy/` to `wayfinder_paths/strategies/my_strategy/`
|
|
114
|
+
4. **Customize** the template (rename classes, update manifest, implement methods)
|
|
115
|
+
5. **Test your code** thoroughly using the provided test framework
|
|
116
|
+
6. **Validate manifests**: Run `just validate-manifests`
|
|
117
|
+
7. **Submit a Pull Request** with a clear description of your changes
|
|
118
|
+
|
|
119
|
+
### What You Can Contribute
|
|
120
|
+
|
|
121
|
+
- **Adapters**: Exchange/protocol integrations (e.g., Uniswap, Aave, Compound)
|
|
122
|
+
- **Strategies**: Trading algorithms and yield optimization strategies
|
|
123
|
+
- **Improvements**: Bug fixes, documentation, or core system enhancements
|
|
124
|
+
|
|
125
|
+
### Contributor Guidelines
|
|
126
|
+
|
|
127
|
+
#### For Adapters
|
|
128
|
+
- **Start from the template**: Copy `wayfinder_paths/templates/adapter/` as a starting point
|
|
129
|
+
- Extend `BaseAdapter` from `wayfinder_paths/core/adapters/BaseAdapter.py`
|
|
130
|
+
- Create a `manifest.yaml` (template at `wayfinder_paths/templates/adapter/manifest.yaml`) with:
|
|
131
|
+
- `entrypoint`: Full import path to your adapter class
|
|
132
|
+
- `capabilities`: List of capabilities your adapter provides
|
|
133
|
+
- `dependencies`: List of required client classes (e.g., `PoolClient`, `TokenClient`)
|
|
134
|
+
- Implement methods that fulfill the declared capabilities
|
|
135
|
+
- Add comprehensive tests in `test_adapter.py`
|
|
136
|
+
- Include usage examples in `examples.json`
|
|
137
|
+
- Document your adapter in `README.md`
|
|
138
|
+
- Validate your manifest: `just validate-manifests`
|
|
139
|
+
|
|
140
|
+
#### For Strategies
|
|
141
|
+
- **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
|
+
- Extend `Strategy` from `wayfinder_paths/core/strategies/Strategy.py`
|
|
143
|
+
- Create a `manifest.yaml` (template at `wayfinder_paths/templates/strategy/manifest.yaml`) with:
|
|
144
|
+
- `entrypoint`: Full import path to your strategy class
|
|
145
|
+
- `name`: Strategy directory name (used for wallet lookup)
|
|
146
|
+
- `permissions.policy`: Security policy for transaction permissions
|
|
147
|
+
- `adapters`: List of required adapters and their capabilities
|
|
148
|
+
- Implement required methods: `deposit()`, `update()`, `status()`, `withdraw()`
|
|
149
|
+
- Include test cases in `test_strategy.py`
|
|
150
|
+
- Add example configurations in `examples.json`
|
|
151
|
+
- Validate your manifest: `just validate-manifests`
|
|
152
|
+
|
|
153
|
+
#### General Guidelines
|
|
154
|
+
- **Code Quality**: Follow existing patterns and use type hints
|
|
155
|
+
- **Testing**: See [TESTING.md](TESTING.md) - minimum: smoke test for strategies, basic tests for adapters
|
|
156
|
+
- **Documentation**: Update README files and add docstrings
|
|
157
|
+
- **Security**: Never hardcode API keys or private keys
|
|
158
|
+
- **Architecture**: Use adapters for external integrations, not direct API calls
|
|
159
|
+
|
|
160
|
+
### Development Setup
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# 1. Fork and clone the repository
|
|
164
|
+
git clone https://github.com/yourusername/wayfinder-paths.git
|
|
165
|
+
cd wayfinder-paths
|
|
166
|
+
|
|
167
|
+
# 2. Install dependencies
|
|
168
|
+
poetry install
|
|
169
|
+
|
|
170
|
+
# 3. Generate test wallets (required before testing!)
|
|
171
|
+
# Creates a main wallet (or use 'just create-strategy' which auto-creates wallets)
|
|
172
|
+
just create-wallets
|
|
173
|
+
# Or manually: poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
|
|
174
|
+
|
|
175
|
+
# 4. Create a new strategy (recommended - automatically creates wallet)
|
|
176
|
+
just create-strategy "My Strategy Name"
|
|
177
|
+
|
|
178
|
+
# Or manually copy a template:
|
|
179
|
+
# For adapters:
|
|
180
|
+
cp -r wayfinder_paths/templates/adapter wayfinder_paths/adapters/my_adapter
|
|
181
|
+
# For strategies:
|
|
182
|
+
cp -r wayfinder_paths/templates/strategy wayfinder_paths/strategies/my_strategy
|
|
183
|
+
|
|
184
|
+
# 5. Customize the template (see template README.md files for details)
|
|
185
|
+
|
|
186
|
+
# 6. Validate your manifest
|
|
187
|
+
just validate-manifests
|
|
188
|
+
|
|
189
|
+
# 7. Run tests
|
|
190
|
+
poetry run pytest -k smoke -v
|
|
191
|
+
|
|
192
|
+
# Or test your specific contribution
|
|
193
|
+
poetry run pytest wayfinder_paths/strategies/your_strategy/ -v
|
|
194
|
+
poetry run pytest wayfinder_paths/adapters/your_adapter/ -v
|
|
195
|
+
|
|
196
|
+
# 8. Test your contribution locally
|
|
197
|
+
poetry run python wayfinder_paths/run_strategy.py your_strategy --action status
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Getting Help
|
|
201
|
+
|
|
202
|
+
- 📖 Check existing adapters/strategies for examples
|
|
203
|
+
- 🐛 Open an issue for bugs or feature requests
|
|
204
|
+
|
|
205
|
+
## 🏗️ Architecture
|
|
206
|
+
|
|
207
|
+
### Client System
|
|
208
|
+
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
|
+
|
|
210
|
+
### Clients vs Adapters
|
|
211
|
+
|
|
212
|
+
- **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`, `TransactionClient`, `WalletClient`.
|
|
213
|
+
- **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.
|
|
214
|
+
|
|
215
|
+
Recommended usage:
|
|
216
|
+
|
|
217
|
+
- Strategies call adapters (not clients directly) for domain actions.
|
|
218
|
+
- Add or change a client when you need a new low-level capability shared across adapters.
|
|
219
|
+
- Add or change an adapter when integrating a new protocol/exchange or changing protocol-specific behavior.
|
|
220
|
+
|
|
221
|
+
Data flow: `Strategy` → `Adapter` → `Client(s)` → network/API.
|
|
222
|
+
|
|
223
|
+
### Manifests
|
|
224
|
+
|
|
225
|
+
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.
|
|
226
|
+
|
|
227
|
+
#### Adapter Manifests
|
|
228
|
+
|
|
229
|
+
Adapter manifests declare the capabilities an adapter provides and the clients it depends on.
|
|
230
|
+
|
|
231
|
+
**Template:** Copy `wayfinder_paths/templates/adapter/manifest.yaml` as a starting point.
|
|
232
|
+
|
|
233
|
+
**Schema:**
|
|
234
|
+
```yaml
|
|
235
|
+
schema_version: "0.1"
|
|
236
|
+
entrypoint: "adapters.my_adapter.adapter.MyAdapter"
|
|
237
|
+
capabilities:
|
|
238
|
+
- "pool.read"
|
|
239
|
+
- "pool.analytics"
|
|
240
|
+
dependencies:
|
|
241
|
+
- "PoolClient"
|
|
242
|
+
- "TokenClient"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Fields:**
|
|
246
|
+
- `schema_version`: Manifest schema version (currently `"0.1"`)
|
|
247
|
+
- `entrypoint`: Full Python import path to the adapter class (required)
|
|
248
|
+
- `capabilities`: List of abstract capabilities this adapter provides (required, non-empty)
|
|
249
|
+
- `dependencies`: List of client class names from `core.clients` that this adapter requires (required, non-empty)
|
|
250
|
+
|
|
251
|
+
**Example** (`wayfinder_paths/adapters/pool_adapter/manifest.yaml`):
|
|
252
|
+
```yaml
|
|
253
|
+
schema_version: "0.1"
|
|
254
|
+
entrypoint: "adapters.pool_adapter.adapter.PoolAdapter"
|
|
255
|
+
capabilities:
|
|
256
|
+
- "pool.read"
|
|
257
|
+
- "pool.analytics"
|
|
258
|
+
- "pool.discovery"
|
|
259
|
+
- "llama.data"
|
|
260
|
+
- "pool.reports"
|
|
261
|
+
dependencies:
|
|
262
|
+
- "PoolClient"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### Strategy Manifests
|
|
266
|
+
|
|
267
|
+
Strategy manifests declare permissions and required adapters with their capabilities.
|
|
268
|
+
|
|
269
|
+
**Template:** Copy `wayfinder_paths/templates/strategy/manifest.yaml` as a starting point.
|
|
270
|
+
|
|
271
|
+
**Schema:**
|
|
272
|
+
```yaml
|
|
273
|
+
schema_version: "0.1"
|
|
274
|
+
entrypoint: "strategies.my_strategy.strategy.MyStrategy"
|
|
275
|
+
permissions:
|
|
276
|
+
policy: "(wallet.id == 'FORMAT_WALLET_ID') && (eth.tx.to == '0x...')"
|
|
277
|
+
adapters:
|
|
278
|
+
- name: "POOL"
|
|
279
|
+
capabilities: ["pool.read", "pool.analytics"]
|
|
280
|
+
- name: "BRAP"
|
|
281
|
+
capabilities: ["swap.quote", "swap.execute"]
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Fields:**
|
|
285
|
+
- `schema_version`: Manifest schema version (currently `"0.1"`)
|
|
286
|
+
- `entrypoint`: Full Python import path to the strategy class (required)
|
|
287
|
+
- `name`: Strategy directory name (optional, used for wallet lookup - defaults to directory name)
|
|
288
|
+
- `permissions.policy`: Security policy string that defines transaction permissions (required, non-empty)
|
|
289
|
+
- `adapters`: List of required adapters with their names and needed capabilities (required, non-empty)
|
|
290
|
+
- `name`: Adapter type identifier (e.g., "POOL", "BRAP")
|
|
291
|
+
- `capabilities`: List of capabilities required from this adapter
|
|
292
|
+
|
|
293
|
+
**Example** (`wayfinder_paths/strategies/stablecoin_yield_strategy/manifest.yaml`):
|
|
294
|
+
```yaml
|
|
295
|
+
schema_version: "0.1"
|
|
296
|
+
entrypoint: "strategies.stablecoin_yield_strategy.strategy.StablecoinYieldStrategy"
|
|
297
|
+
permissions:
|
|
298
|
+
policy: "(wallet.id == 'FORMAT_WALLET_ID') && ((eth.tx.data[0..10] == '0x095ea7b3' && eth.tx.data[34..74] == 'f75584ef6673ad213a685a1b58cc0330b8ea22cf') || (eth.tx.to == '0xF75584eF6673aD213a685a1B58Cc0330B8eA22Cf'))"
|
|
299
|
+
adapters:
|
|
300
|
+
- name: "BALANCE"
|
|
301
|
+
capabilities: ["wallet_read", "wallet_transfer"]
|
|
302
|
+
- name: "POOL"
|
|
303
|
+
capabilities: ["pool.read", "pool.analytics"]
|
|
304
|
+
- name: "BRAP"
|
|
305
|
+
capabilities: ["swap.quote", "swap.execute"]
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### Manifest Validation
|
|
309
|
+
|
|
310
|
+
Manifests are automatically validated to ensure:
|
|
311
|
+
- Schema compliance (all required fields present, correct types)
|
|
312
|
+
- Entrypoint classes exist and are importable
|
|
313
|
+
- Dependencies are valid client classes
|
|
314
|
+
- Permissions policies are non-empty
|
|
315
|
+
|
|
316
|
+
**Validate locally:**
|
|
317
|
+
```bash
|
|
318
|
+
# Validate all manifests
|
|
319
|
+
just validate-manifests
|
|
320
|
+
|
|
321
|
+
# Or manually
|
|
322
|
+
PYTHONPATH=wayfinder_paths poetry run python wayfinder_paths/scripts/validate_manifests.py
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Validation runs automatically in CI/CD on every PR and push to main. All manifests must be valid before merging.
|
|
326
|
+
|
|
327
|
+
**How Validation Works:**
|
|
328
|
+
|
|
329
|
+
The `validate_manifests.py` script performs multi-stage validation:
|
|
330
|
+
|
|
331
|
+
1. **Schema Validation** (via Pydantic models):
|
|
332
|
+
- Loads YAML file and validates against `AdapterManifest` or `StrategyManifest` schema
|
|
333
|
+
- Checks required fields, types, and basic constraints (e.g., capabilities cannot be empty)
|
|
334
|
+
- Validates entrypoint format (must be full import path like `"adapters.pool_adapter.adapter.PoolAdapter"`)
|
|
335
|
+
|
|
336
|
+
2. **Entrypoint Verification**:
|
|
337
|
+
- **For Adapters**: Imports the entrypoint class and verifies it's a subclass of `BaseAdapter`
|
|
338
|
+
- **For Strategies**: Imports the entrypoint class and verifies it's a subclass of `Strategy`
|
|
339
|
+
- Uses Python's `__import__()` to dynamically import the module and class
|
|
340
|
+
- Catches import errors, missing classes, and type mismatches
|
|
341
|
+
|
|
342
|
+
3. **Dependency Verification** (adapters only):
|
|
343
|
+
- Validates that all declared dependencies (e.g., `PoolClient`, `TokenClient`) exist in `core.clients`
|
|
344
|
+
- Attempts to import each dependency as `core.clients.{DepName}`
|
|
345
|
+
|
|
346
|
+
4. **Permissions Validation** (strategies only):
|
|
347
|
+
- Validated by Pydantic: ensures `permissions.policy` exists and is non-empty
|
|
348
|
+
- Policy syntax is not parsed/validated (assumed to be valid at runtime)
|
|
349
|
+
|
|
350
|
+
**Validation Flow:**
|
|
351
|
+
```
|
|
352
|
+
For each manifest file:
|
|
353
|
+
1. Load YAML → Parse with Pydantic (schema validation)
|
|
354
|
+
2. Import entrypoint class → Verify inheritance (entrypoint validation)
|
|
355
|
+
3. For adapters: Import dependencies → Verify they exist (dependency validation)
|
|
356
|
+
4. Collect all errors → Report results
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
The script automatically discovers all manifests by scanning:
|
|
360
|
+
- `wayfinder_paths/adapters/*/manifest.yaml` for adapter manifests
|
|
361
|
+
- `wayfinder_paths/strategies/*/manifest.yaml` for strategy manifests
|
|
362
|
+
|
|
363
|
+
All errors are collected and reported at the end, with the script exiting with code 1 if any validation fails.
|
|
364
|
+
|
|
365
|
+
#### Capabilities
|
|
366
|
+
|
|
367
|
+
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
|
+
|
|
369
|
+
When creating an adapter:
|
|
370
|
+
1. Declare capabilities in your `manifest.yaml`
|
|
371
|
+
2. Implement methods that fulfill those capabilities
|
|
372
|
+
3. Capabilities are validated at manifest validation time (entrypoint must be importable)
|
|
373
|
+
|
|
374
|
+
### Configuration
|
|
375
|
+
Configuration is split between:
|
|
376
|
+
- **User Config**: Your credentials and preferences
|
|
377
|
+
- **System Config**: Platform settings
|
|
378
|
+
- **Strategy Config**: Strategy-specific parameters
|
|
379
|
+
|
|
380
|
+
See [CONFIG_GUIDE.md](wayfinder_paths/CONFIG_GUIDE.md) for details.
|
|
381
|
+
|
|
382
|
+
### Authentication
|
|
383
|
+
|
|
384
|
+
Wayfinder Paths supports two authentication methods:
|
|
385
|
+
|
|
386
|
+
#### 1. Service Account Authentication (API Key)
|
|
387
|
+
For backend services and automated systems with higher rate limits:
|
|
388
|
+
|
|
389
|
+
**Option A: Pass to Strategy Constructor**
|
|
390
|
+
```python
|
|
391
|
+
from wayfinder_paths.strategies.stablecoin_yield_strategy.strategy import StablecoinYieldStrategy
|
|
392
|
+
|
|
393
|
+
strategy = StablecoinYieldStrategy(
|
|
394
|
+
config={...},
|
|
395
|
+
api_key="sk_live_abc123..." # API key is auto-discovered by all clients
|
|
396
|
+
)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Option B: Set Environment Variable**
|
|
400
|
+
```bash
|
|
401
|
+
export WAYFINDER_API_KEY="sk_live_abc123..."
|
|
402
|
+
# All clients will automatically discover and use this
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**Option C: Add to config.json**
|
|
406
|
+
```json
|
|
407
|
+
{
|
|
408
|
+
"user": {
|
|
409
|
+
"api_key": "sk_live_abc123..."
|
|
410
|
+
},
|
|
411
|
+
"system": {
|
|
412
|
+
"api_key": "sk_live_abc123..." // Alternative: system-level API key
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Priority Order:** Constructor parameter > `config.json` (user.api_key or system.api_key) > `WAYFINDER_API_KEY` environment variable
|
|
418
|
+
|
|
419
|
+
**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
|
+
|
|
421
|
+
#### 2. Personal Access Authentication (OAuth)
|
|
422
|
+
For standalone SDK users with username/password:
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
{
|
|
426
|
+
"user": {
|
|
427
|
+
"username": "your_username",
|
|
428
|
+
"password": "your_password",
|
|
429
|
+
"refresh_token": null // Optional: use refresh token instead
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**How It Works:**
|
|
435
|
+
- API keys are automatically discovered by all clients (no need to pass explicitly)
|
|
436
|
+
- When an API key is available, it's used for all API requests (including public endpoints) for rate limiting
|
|
437
|
+
- If no API key is found, the system falls back to OAuth authentication
|
|
438
|
+
- All clients created by adapters automatically inherit the API key discovery mechanism
|
|
439
|
+
- API keys in `config.json` are loaded directly by `WayfinderClient._load_config_credentials()` from `user.api_key` or `system.api_key`, not stored in the `UserConfig` or `SystemConfig` dataclasses
|
|
440
|
+
|
|
441
|
+
See [CONFIG_GUIDE.md](wayfinder_paths/CONFIG_GUIDE.md) for detailed authentication documentation.
|
|
442
|
+
|
|
443
|
+
## 🔌 Creating Adapters
|
|
444
|
+
|
|
445
|
+
Adapters connect to exchanges and DeFi protocols using the client system.
|
|
446
|
+
|
|
447
|
+
```python
|
|
448
|
+
# wayfinder_paths/adapters/my_adapter/adapter.py
|
|
449
|
+
from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
|
|
450
|
+
from wayfinder_paths.core.clients.PoolClient import PoolClient
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
class MyAdapter(BaseAdapter):
|
|
454
|
+
"""Thin wrapper around PoolClient that exposes pool metadata to strategies."""
|
|
455
|
+
|
|
456
|
+
adapter_type = "POOL"
|
|
457
|
+
|
|
458
|
+
def __init__(self, config: dict | None = None):
|
|
459
|
+
super().__init__("my_adapter", config)
|
|
460
|
+
self.pool_client = PoolClient()
|
|
461
|
+
|
|
462
|
+
async def connect(self) -> bool:
|
|
463
|
+
"""No-op for read-only adapters, but kept for manifest compatibility."""
|
|
464
|
+
return True
|
|
465
|
+
|
|
466
|
+
async def get_pools(self, pool_ids: list[str]):
|
|
467
|
+
data = await self.pool_client.get_pools_by_ids(
|
|
468
|
+
pool_ids=",".join(pool_ids), merge_external=True
|
|
469
|
+
)
|
|
470
|
+
return (True, data)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## 📈 Building Strategies
|
|
474
|
+
|
|
475
|
+
Strategies implement trading logic using adapters and the unified client system.
|
|
476
|
+
|
|
477
|
+
```python
|
|
478
|
+
# wayfinder_paths/strategies/my_strategy/strategy.py
|
|
479
|
+
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
480
|
+
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
481
|
+
from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
class MyStrategy(Strategy):
|
|
485
|
+
name = "Demo Strategy"
|
|
486
|
+
|
|
487
|
+
def __init__(
|
|
488
|
+
self,
|
|
489
|
+
config: dict | None = None,
|
|
490
|
+
*,
|
|
491
|
+
api_key: str | None = None, # Optional: API key for service account auth
|
|
492
|
+
):
|
|
493
|
+
super().__init__(api_key=api_key) # Pass to base class for auto-discovery
|
|
494
|
+
self.config = config or {}
|
|
495
|
+
web3_service = DefaultWeb3Service(self.config)
|
|
496
|
+
# Adapters automatically discover API key from env var (set by Strategy.__init__)
|
|
497
|
+
balance_adapter = BalanceAdapter(self.config, web3_service=web3_service)
|
|
498
|
+
self.register_adapters([balance_adapter])
|
|
499
|
+
self.balance_adapter = balance_adapter
|
|
500
|
+
|
|
501
|
+
async def deposit(
|
|
502
|
+
self, main_token_amount: float = 0.0, gas_token_amount: float = 0.0
|
|
503
|
+
) -> StatusTuple:
|
|
504
|
+
"""Move funds from main wallet into the strategy wallet."""
|
|
505
|
+
if main_token_amount <= 0:
|
|
506
|
+
return (False, "Nothing to deposit")
|
|
507
|
+
|
|
508
|
+
success, _ = await self.balance_adapter.get_balance(
|
|
509
|
+
token_id=self.config.get("token_id"),
|
|
510
|
+
wallet_address=self.config.get("main_wallet", {}).get("address"),
|
|
511
|
+
)
|
|
512
|
+
if not success:
|
|
513
|
+
return (False, "Unable to fetch balances")
|
|
514
|
+
|
|
515
|
+
# Use BalanceAdapter (which leverages LocalTokenTxnService builders) for transfers here.
|
|
516
|
+
self.last_deposit = main_token_amount
|
|
517
|
+
return (True, f"Deposited {main_token_amount} tokens")
|
|
518
|
+
|
|
519
|
+
async def update(self) -> StatusTuple:
|
|
520
|
+
"""Periodic strategy update"""
|
|
521
|
+
return (True, "No-op update")
|
|
522
|
+
|
|
523
|
+
async def _status(self) -> StatusDict:
|
|
524
|
+
"""Report balances back to the runner"""
|
|
525
|
+
success, balance = await self.balance_adapter.get_balance(
|
|
526
|
+
token_id=self.config.get("token_id"),
|
|
527
|
+
wallet_address=self.config.get("strategy_wallet", {}).get("address"),
|
|
528
|
+
)
|
|
529
|
+
return {
|
|
530
|
+
"portfolio_value": float(balance or 0),
|
|
531
|
+
"net_deposit": float(getattr(self, "last_deposit", 0.0)),
|
|
532
|
+
"strategy_status": {"message": "healthy" if success else "unknown"},
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Built-in adapters
|
|
537
|
+
|
|
538
|
+
- **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.
|
|
539
|
+
- **POOL (PoolAdapter)**: composes `PoolClient` to fetch pools, llama analytics, combined reports, high-yield searches, and search helpers.
|
|
540
|
+
- **BRAP (BRAPAdapter)**: integrates the cross-chain quote service for swaps/bridges, including fee breakdowns, route comparisons, validation helpers, and swap execution/ledger recording when provided a `Web3Service`.
|
|
541
|
+
- **LEDGER (LedgerAdapter)**: records deposits, withdrawals, custom operations, and cashflows via `LedgerClient`, and can read strategy transaction summaries.
|
|
542
|
+
- **TOKEN (TokenAdapter)**: lightweight wrapper around `TokenClient` for token metadata, live price snapshots, and gas token lookups.
|
|
543
|
+
- **HYPERLEND (HyperlendAdapter)**: connects to `HyperlendClient` for lending/supply caps inside the HyperLend strategy.
|
|
544
|
+
|
|
545
|
+
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).
|
|
546
|
+
|
|
547
|
+
## 🧪 Testing
|
|
548
|
+
|
|
549
|
+
**📖 For detailed testing guidance, see [TESTING.md](TESTING.md)**
|
|
550
|
+
|
|
551
|
+
### Quick Start
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
# 1. Generate test wallets (required!)
|
|
555
|
+
# Creates a main wallet (or use 'just create-strategy' which auto-creates wallets)
|
|
556
|
+
just create-wallets
|
|
557
|
+
# Or manually: poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
|
|
558
|
+
|
|
559
|
+
# 2. Run smoke tests
|
|
560
|
+
poetry run pytest -k smoke -v
|
|
561
|
+
|
|
562
|
+
# 3. Test your specific contribution
|
|
563
|
+
poetry run pytest wayfinder_paths/strategies/my_strategy/ -v # Strategy
|
|
564
|
+
poetry run pytest wayfinder_paths/adapters/my_adapter/ -v # Adapter
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Testing Your Contribution
|
|
568
|
+
|
|
569
|
+
**Strategies**: Add a simple smoke test in `test_strategy.py` that exercises deposit → update → status → withdraw.
|
|
570
|
+
|
|
571
|
+
**Adapters**: Add basic functionality tests with mocked dependencies. Use `examples.json` to drive your tests.
|
|
572
|
+
|
|
573
|
+
See [TESTING.md](TESTING.md) for complete examples and best practices.
|
|
574
|
+
|
|
575
|
+
## 💻 Local Development
|
|
576
|
+
|
|
577
|
+
### Setup
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
# Clone repo
|
|
581
|
+
git clone https://github.com/wayfinder-ai/wayfinder-paths.git
|
|
582
|
+
cd wayfinder-paths
|
|
583
|
+
|
|
584
|
+
# Install dependencies
|
|
585
|
+
poetry install
|
|
586
|
+
|
|
587
|
+
# Generate test wallets (essential!)
|
|
588
|
+
# Creates a main wallet (or use 'just create-strategy' which auto-creates wallets)
|
|
589
|
+
just create-wallets
|
|
590
|
+
# Or manually: poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
|
|
591
|
+
|
|
592
|
+
# Copy and configure
|
|
593
|
+
cp wayfinder_paths/config.example.json config.json
|
|
594
|
+
# Edit config.json with your Wayfinder credentials
|
|
595
|
+
|
|
596
|
+
# Run a strategy (status check)
|
|
597
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --action status --config config.json
|
|
598
|
+
|
|
599
|
+
# Run with custom config
|
|
600
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --config my_config.json
|
|
601
|
+
|
|
602
|
+
# Run continuously with debug output
|
|
603
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --debug --config config.json
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Wallet Generation for Testing
|
|
607
|
+
|
|
608
|
+
**Before running any strategies, generate test wallets.** This creates `wallets.json` in the repository root with throwaway wallets for local testing:
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
# Essential: Create main wallet for testing
|
|
612
|
+
just create-wallets
|
|
613
|
+
# Or manually: poetry run python wayfinder_paths/scripts/make_wallets.py -n 1
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
This creates:
|
|
617
|
+
- `main` wallet - your main wallet for testing (labeled "main" in wallets.json)
|
|
618
|
+
- `wallets.json` - wallet addresses and private keys for local testing
|
|
619
|
+
|
|
620
|
+
**Note:** Strategy-specific wallets are automatically created when you use `just create-strategy "Strategy Name"`. For manual creation, use `just create-wallet "strategy_name"` or `poetry run python wayfinder_paths/scripts/make_wallets.py --label "strategy_name"`.
|
|
621
|
+
|
|
622
|
+
**Important:** These wallets are for testing only. Never use them with real funds or on mainnet.
|
|
623
|
+
|
|
624
|
+
**Per-Strategy Wallets:** Each strategy should have its own dedicated wallet. When you create a new strategy using `just create-strategy`, a wallet is automatically generated with a label matching the strategy directory name. The system automatically uses this wallet when running the strategy. See [CONFIG_GUIDE.md](wayfinder_paths/CONFIG_GUIDE.md) for details.
|
|
625
|
+
|
|
626
|
+
Additional options:
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
# Add 3 extra wallets for multi-account testing
|
|
630
|
+
poetry run python wayfinder_paths/scripts/make_wallets.py -n 3
|
|
631
|
+
|
|
632
|
+
# Create a wallet with a specific label (e.g., for a strategy)
|
|
633
|
+
poetry run python wayfinder_paths/scripts/make_wallets.py --label "my_strategy_name"
|
|
634
|
+
|
|
635
|
+
# Generate keystore files (for geth/web3 compatibility)
|
|
636
|
+
poetry run python wayfinder_paths/scripts/make_wallets.py -n 1 --keystore-password "my-password"
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Configuration
|
|
640
|
+
|
|
641
|
+
See [CONFIG_GUIDE.md](wayfinder_paths/CONFIG_GUIDE.md) for detailed configuration documentation.
|
|
642
|
+
|
|
643
|
+
#### Setup Configuration
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
# Copy example config
|
|
647
|
+
cp wayfinder_paths/config.example.json config.json
|
|
648
|
+
|
|
649
|
+
# Edit config.json with your settings
|
|
650
|
+
# Required fields:
|
|
651
|
+
# - user.username: Your Wayfinder username
|
|
652
|
+
# - user.password: Your Wayfinder password
|
|
653
|
+
# - OR user.refresh_token: Your refresh token
|
|
654
|
+
# - system.wallets_path: Path to wallets.json (default: "wallets.json")
|
|
655
|
+
#
|
|
656
|
+
# Wallet addresses are auto-loaded from wallets.json by default.
|
|
657
|
+
# Then run with:
|
|
658
|
+
poetry run python wayfinder_paths/run_strategy.py stablecoin_yield_strategy --config config.json
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
## 📦 Versioning
|
|
662
|
+
|
|
663
|
+
This package follows [Semantic Versioning](https://semver.org/) (SemVer) and is published to PyPI as a public package.
|
|
664
|
+
|
|
665
|
+
### Version Format: MAJOR.MINOR.PATCH
|
|
666
|
+
|
|
667
|
+
- **MAJOR** (X.0.0): Breaking changes that require code updates
|
|
668
|
+
- **MINOR** (0.X.0): New features, backward compatible
|
|
669
|
+
- **PATCH** (0.0.X): Bug fixes, backward compatible
|
|
670
|
+
|
|
671
|
+
### Version Bumping Rules
|
|
672
|
+
|
|
673
|
+
- **PATCH**: Bug fixes, security patches, documentation updates
|
|
674
|
+
- **MINOR**: New adapters, new strategies, new features (backward compatible)
|
|
675
|
+
- **MAJOR**: Breaking API changes, removed features, incompatible changes
|
|
676
|
+
|
|
677
|
+
### Important Notes
|
|
678
|
+
|
|
679
|
+
- **Versions are immutable**: Once published to PyPI, a version cannot be changed or deleted
|
|
680
|
+
- **Versions must be unique**: Each release must have a new, unique version number
|
|
681
|
+
- **Publishing is restricted**: Only publish from the `main` branch to prevent accidental releases
|
|
682
|
+
|
|
683
|
+
### Publishing Workflow and Order of Operations
|
|
684
|
+
|
|
685
|
+
**Critical**: Changes must follow this strict order:
|
|
686
|
+
|
|
687
|
+
1. **Merge to main**: All changes must be merged to the `main` branch first
|
|
688
|
+
2. **Publish to PyPI**: The new version must be published to PyPI from `main` branch
|
|
689
|
+
3. **Dependent changes**: Only after publishing can dependent changes be merged in other applications
|
|
690
|
+
|
|
691
|
+
**Why this order matters:**
|
|
692
|
+
- Other applications depend on this package from PyPI
|
|
693
|
+
- They cannot merge changes that depend on new versions until those versions are available on PyPI
|
|
694
|
+
- Publishing from `main` ensures the published version matches what's in the repository
|
|
695
|
+
- This prevents dependency resolution failures in downstream applications
|
|
696
|
+
|
|
697
|
+
**Example workflow:**
|
|
698
|
+
```bash
|
|
699
|
+
# 1. Make changes in a feature branch
|
|
700
|
+
git checkout -b feature/new-adapter
|
|
701
|
+
# ... make changes ...
|
|
702
|
+
git commit -m "Add new adapter"
|
|
703
|
+
|
|
704
|
+
# 2. Merge to main
|
|
705
|
+
git checkout main
|
|
706
|
+
git merge feature/new-adapter
|
|
707
|
+
|
|
708
|
+
# 3. Bump version in pyproject.toml (e.g., 0.1.3 → 0.2.0)
|
|
709
|
+
# Edit pyproject.toml: version = "0.2.0"
|
|
710
|
+
git commit -m "Bump version to 0.2.0"
|
|
711
|
+
git push origin main
|
|
712
|
+
|
|
713
|
+
# 4. Publish to PyPI (must be on main branch)
|
|
714
|
+
just publish
|
|
715
|
+
|
|
716
|
+
# 5. Now dependent applications can update their dependencies
|
|
717
|
+
# pip install wayfinder-paths==0.2.0
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
## 📦 Publishing
|
|
721
|
+
|
|
722
|
+
Publish to PyPI:
|
|
723
|
+
|
|
724
|
+
```bash
|
|
725
|
+
export PUBLISH_TOKEN="your_pypi_token"
|
|
726
|
+
just publish
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
**Important:**
|
|
730
|
+
- ⚠️ **Publishing is only allowed from the `main` branch** - the publish command will fail if run from any other branch
|
|
731
|
+
- ⚠️ **Versions must be unique** - ensure the version in `pyproject.toml` has been bumped and is unique
|
|
732
|
+
- ⚠️ **Follow the order of operations** - see [Versioning](#-versioning) section above for the required workflow
|
|
733
|
+
- ⚠️ **Versions are immutable** - once published, a version cannot be changed or deleted from PyPI
|
|
734
|
+
|
|
735
|
+
Install the published package:
|
|
736
|
+
|
|
737
|
+
```bash
|
|
738
|
+
pip install wayfinder-paths
|
|
739
|
+
# or
|
|
740
|
+
poetry add wayfinder-paths
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Install from Git (development):
|
|
744
|
+
|
|
745
|
+
```bash
|
|
746
|
+
pip install git+https://github.com/wayfinder-ai/wayfinder-paths.git
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### Managing Package Access
|
|
750
|
+
|
|
751
|
+
To add collaborators who can publish updates:
|
|
752
|
+
1. Go to https://pypi.org/project/wayfinder-paths/
|
|
753
|
+
2. Click "Manage" → "Collaborators"
|
|
754
|
+
3. Add users as "Maintainers" (can publish) or "Owners" (full control)
|
|
755
|
+
|
|
756
|
+
## 🔒 Security
|
|
757
|
+
|
|
758
|
+
- **Never hardcode API keys or Private keys** - use config.json for credentials
|
|
759
|
+
- **Never commit config.json** - add it to .gitignore
|
|
760
|
+
- **Test on testnet first** - use test network when available
|
|
761
|
+
- **Validate all inputs** - sanitize user data
|
|
762
|
+
- **Set gas limits** - prevent excessive fees
|
|
763
|
+
|
|
764
|
+
## 📊 Backtesting
|
|
765
|
+
|
|
766
|
+
Coming soon
|
|
767
|
+
|
|
768
|
+
## 🌟 Community
|
|
769
|
+
|
|
770
|
+
Need help or want to discuss strategies? Join our [Discord](https://discord.gg/fUVwGMXjm3)!
|
|
771
|
+
|
|
772
|
+
## 📄 License
|
|
773
|
+
|
|
774
|
+
MIT License - see [LICENSE](LICENSE) file for details
|
|
775
|
+
|
|
776
|
+
🚀 **Happy Wayfinding!**
|
|
777
|
+
|