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