Metadata-Version: 2.4
Name: wayfinder-paths
Version: 0.11.0
Summary: Wayfinder Path: strategies and adapters
License-File: LICENSE
Author: Wayfinder
Author-email: dev@wayfinder.ai
Requires-Python: >=3.12,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: aiocache (>=0.12.3,<0.13.0)
Requires-Dist: aiohttp (>=3.13.0,<4.0.0)
Requires-Dist: ccxt (>=4.0,<5.0)
Requires-Dist: click (>=8.1.7,<9.0.0)
Requires-Dist: croniter (>=6.0.0,<7.0.0)
Requires-Dist: eth-account (>=0.13.7,<0.14.0)
Requires-Dist: httpx (>=0.28.1,<0.29.0)
Requires-Dist: hyperliquid-felix (>=0.23.1,<0.24.0)
Requires-Dist: loguru (>=0.7.3,<0.8.0)
Requires-Dist: matplotlib (>=3.10.8,<4.0.0)
Requires-Dist: numpy (>=1.26.0,<2.0.0)
Requires-Dist: packaging (>=25.0,<26.0)
Requires-Dist: pandas (>=2.2.0,<3.0.0)
Requires-Dist: py-clob-client-v2-felix (==1.0.2)
Requires-Dist: py-order-utils (==0.3.2)
Requires-Dist: py-solc-x (>=2.0.0,<3.0.0)
Requires-Dist: pydantic (>=2.11.9,<3.0.0)
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
Requires-Dist: web3 (>=7.13.0,<8.0.0)
Description-Content-Type: text/markdown

# Wayfinder Paths SDK

[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/)
[![PyPI](https://img.shields.io/pypi/v/wayfinder-paths.svg)](https://pypi.org/project/wayfinder-paths/)
[![Discord](https://img.shields.io/badge/discord-join-7289da.svg)](https://discord.gg/fUVwGMXjm3)

**An open-source SDK for building and managing automated DeFi strategies.**
It provides strategy abstractions, protocol adapters, and an MCP server for Claude Code.

## What is Wayfinder Paths?

Wayfinder Paths is a Python SDK that lets you:

- **Run DeFi strategies**: deposit, rebalance, withdraw, and exit across multiple chains
- **Build new paths**: create adapters and strategies for any protocol
- **Expose safe operations to Claude**: local MCP server for balances, swaps, perps, and strategy management

Think of it as programmable DeFi infrastructure that connects your wallets to yield strategies, perpetuals, lending markets, and cross-chain routers.

## Repository Layout

- `wayfinder_paths/core`: shared config, clients, constants, and utilities
- `wayfinder_paths/adapters`: protocol integrations (Moonwell, Hyperliquid, etc.)
- `wayfinder_paths/strategies`: strategy implementations and metadata
- `wayfinder_paths/mcp`: MCP server and tools for Claude Code/OpenCode
- `scripts/`: setup, wallet generation, and scaffolding helpers
- `tests/` and `wayfinder_paths/tests`: test suites

## Requirements

- Python 3.12
- Poetry (recommended)

## Quick Start

```bash
# Clone the repository
git clone https://github.com/WayfinderFoundation/wayfinder-paths-sdk.git
cd wayfinder-paths

# One-command setup (installs Poetry + deps, writes config.json, updates .mcp.json)
python3 scripts/setup.py

# One-command setup with deterministic wallets (generates + saves wallet_mnemonic)
python3 scripts/setup.py --mnemonic

# Remote two-stage setup (stage 1 installs deps + writes config.json)
python3 scripts/remote_setup_stage1.py --api-key wk_...
# Stage 2 option A (recommended): generate + persist a mnemonic (prints once)
python3 scripts/remote_setup_stage2.py --mnemonic
# Stage 2 option B: load mnemonic from file (avoids shell history)
python3 scripts/remote_setup_stage2.py --mnemonic-file /path/to/mnemonic.txt

# Check strategy status
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action status --config config.json
```

### Manual Setup (if you don't want the bootstrap script)

```bash
poetry install
cp config.example.json config.json
# Edit config.json and set system.api_key

# Create a main wallet for local testing
poetry run python scripts/make_wallets.py -n 1

# Or: create deterministic wallets from a generated mnemonic (saved to config.json)
poetry run python scripts/make_wallets.py -n 1 --mnemonic
```

## Configuration

Use `config.example.json` as a template. The SDK reads `config.json` by default.

Key fields:

- `system.api_key`: Wayfinder API key (or set `WAYFINDER_API_KEY` env var)
- `system.api_base_url`: API base URL (defaults to `https://wayfinder.ai/api/v1` if omitted)
- `strategy.rpc_urls`: *(optional)* chain ID -> RPC URL(s) (string or list). If omitted for a chain, reads default to the Wayfinder proxy RPC at `${system.api_base_url}/blockchain/rpc/<chain_id>/`.
- `wallets`: local wallets with `label`, `address`, and `private_key_hex`. Remote wallets (Privy server wallets) are auto-fetched when `system.api_key` is configured.

Example:

```json
{
  "system": {
    "api_base_url": "https://wayfinder.ai/api/v1",
    "api_key": "wk_your_api_key_here"
  },
  "strategy": {
    "rpc_urls": {
      "1": ["https://eth.llamarpc.com"],
      "8453": ["https://mainnet.base.org"],
      "42161": ["https://arb1.arbitrum.io/rpc"],
      "999": ["https://rpc.hyperliquid.xyz/evm"]
    }
  },
  "wallets": [
    {
      "label": "main",
      "address": "0x...",
      "private_key_hex": "0x..."
    }
  ]
}
```

> **Important:** The RPC URLs in the example above are public endpoints and may rate limit. For reliable adapter reads, set `strategy.rpc_urls` to your own RPC provider(s) (Alchemy/Infura/QuickNode/Tenderly/etc) and put the most reliable URL first.

For detailed config documentation, see `CONFIG_GUIDE.md`.

### Config Resolution (scripts)

By default, the SDK reads `config.json` from the repo root. To use a different file, set `WAYFINDER_CONFIG_PATH` before starting Python (or call `wayfinder_paths.core.config.load_config()` in your script).

Quick sanity check:

```bash
poetry run python - <<'PY'
from wayfinder_paths.core.config import resolve_config_path, get_rpc_urls
print("config_path:", resolve_config_path())
print("base_rpc:", (get_rpc_urls() or {}).get("8453"))
PY
```

### Supported Chains

The SDK includes built-in support for these chain IDs:

| Chain    | ID    | Code       |
| -------- | ----- | ---------- |
| Ethereum | 1     | `ethereum` |
| Base     | 8453  | `base`     |
| Arbitrum | 42161 | `arbitrum` |
| Polygon  | 137   | `polygon`  |
| BSC      | 56    | `bsc`      |
| Avalanche | 43114 | `avalanche` |
| Plasma   | 9745  | `plasma`   |
| HyperEVM | 999   | `hyperevm` |

## Strategies

The repository ships with several strategies. Each strategy folder contains a README with details.

| Strategy (directory) | Summary | Primary Chain | Status | Docs |
| --- | --- | --- | --- | --- |
| `stablecoin_yield_strategy` | USDC yield optimization across Base pools | Base | WIP | `wayfinder_paths/strategies/stablecoin_yield_strategy/README.md` |
| `hyperlend_stable_yield_strategy` | HyperLend stablecoin allocator | HyperEVM | Stable | `wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md` |
| `moonwell_wsteth_loop_strategy` | Leveraged wstETH carry trade | Base | Stable | `wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/README.md` |
| `basis_trading_strategy` | Delta-neutral funding rate capture | Hyperliquid | Stable | `wayfinder_paths/strategies/basis_trading_strategy/README.md` |
| `boros_hype_strategy` | HYPE yield with Boros + Hyperliquid hedging | Multi-chain | Stable | `wayfinder_paths/strategies/boros_hype_strategy/README.md` |
| `multi_vault_split_strategy` | Diversified USDC vault allocation across HLP, Boros, and Avantis | Multi-chain | Stable | `wayfinder_paths/strategies/multi_vault_split_strategy/README.md` |
| `projectx_thbill_usdc_strategy` | THBILL/USDC concentrated LP with fee compounding and recentering | HyperEVM | Stable | `wayfinder_paths/strategies/projectx_thbill_usdc_strategy/README.md` |

> **Note:** WIP (work-in-progress) strategies may have incomplete features or known issues. Running them via MCP will show a warning but execution is not blocked.

## Adapters

Adapters live in `wayfinder_paths/adapters` and encapsulate protocol-specific logic:

- `AaveV3Adapter` (Aave V3 lending/borrowing across Ethereum, Base, and Arbitrum)
- `AerodromeAdapter` (Aerodrome classic Pool/Gauge/veAERO on Base, including Sugar read analytics)
- `AerodromeSlipstreamAdapter` (Aerodrome Slipstream concentrated liquidity, CL gauges, and veAERO on Base)
- `AvantisAdapter` (Avantis avUSDC ERC-4626 vault on Base)
- `BalanceAdapter` (wallet balances + transfers)
- `BorosAdapter` (Boros fixed-rate markets, margin accounts, and vaults)
- `BRAPAdapter` (cross-chain swaps + bridges)
- `CCXTAdapter` (multi-exchange CEX trading via CCXT)
- `EthenaVaultAdapter` (Ethena sUSDe staking vault with cooldown withdrawals)
- `EtherfiAdapter` (ether.fi ETH liquid restaking via eETH / weETH with async withdrawals)
- `HyperlendAdapter` (HyperLend lending/borrowing)
- `HyperliquidAdapter` (perps, spot, deposits, withdrawals)
- `LedgerAdapter` (transaction recording)
- `LidoAdapter` (Lido ETH staking, wrapping/unwrapping stETH/wstETH, and withdrawal queue)
- `MoonwellAdapter` (Moonwell lending/borrowing)
- `MorphoAdapter` (Morpho Blue markets, MetaMorpho vaults, rewards, and public allocator)
- `MulticallAdapter` (batch contract calls)
- `PendleAdapter` (PT/YT and hosted SDK operations)
- `PolymarketAdapter` (Polymarket markets, orderbooks, history, and trading)
- `PoolAdapter` (pool analytics)
- `ProjectXLiquidityAdapter` (ProjectX V3 concentrated liquidity on HyperEVM)
- `SparkLendAdapter` (SparkLend Aave v3-style lending/borrowing on Ethereum)
- `TokenAdapter` (token metadata + pricing)
- `UniswapAdapter` (Uniswap V3 concentrated liquidity management)

## CLI Reference

Run strategies from the CLI via `wayfinder_paths.run_strategy`:

```bash
# Status
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action status --config config.json

# Deposit
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action deposit \
  --main-token-amount 100 --gas-token-amount 0.01 --config config.json

# Update / Exit / Withdraw
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action update --config config.json
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action exit --config config.json
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action withdraw --config config.json

# Analyze / Quote (if supported by the strategy)
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action analyze --main-token-amount 1000
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action quote --amount 100

# Run continuously (loop interval defaults to 60s)
poetry run python -m wayfinder_paths.run_strategy boros_hype_strategy --action run --interval 300
```

## Runner (local scheduler)

Run strategies on an interval or cron-style schedule without external cron:

```bash
# Start the daemon (idempotent)
poetry run wayfinder runner start

# Add a job (run update every 10 minutes)
poetry run wayfinder runner add-job \
  --name basis-update \
  --type strategy \
  --strategy basis_trading_strategy \
  --action update \
  --interval 600 \
  --config ./config.json

# Add a cron job (weekdays at 9am Toronto time)
poetry run wayfinder runner add-job \
  --name weekday-basis-update \
  --type strategy \
  --strategy basis_trading_strategy \
  --action update \
  --cron "0 9 * * 1-5" \
  --timezone America/Toronto \
  --config ./config.json

# Schedule a local one-off script (must live in .wayfinder_runs/ by default)
poetry run wayfinder runner add-job \
  --name hourly-report \
  --type script \
  --script-path .wayfinder_runs/report.py \
  --arg --verbose \
  --interval 3600

# Observe / control
poetry run wayfinder runner status
poetry run wayfinder runner run-once basis-update
poetry run wayfinder runner pause basis-update
poetry run wayfinder runner resume basis-update
poetry run wayfinder runner delete basis-update
poetry run wayfinder runner runs basis-update --limit 20
poetry run wayfinder runner run-report 1 --tail-bytes 4000
poetry run wayfinder runner stop
```

Runner state (SQLite + per-run logs) is stored in `./.wayfinder/runner/`.

For architecture/extensibility notes (e.g. future Docker/VM runner), see `RUNNER_ARCHITECTURE.md`.

## Simulation / Dry-Runs (virtual testnets)

Before broadcasting complex fund-moving flows, you can run them on a **virtual testnet** (vnet) first. The SDK integrates with **Gorlami**, Wayfinder's fork service, which creates a temporary EVM fork where each step updates on-chain state for the next — without risking real funds.

```bash
# Dry-run a strategy on a Base fork
poetry run python wayfinder_paths/run_strategy.py moonwell_wsteth_loop_strategy \
  --action deposit --main-token-amount 100 --gas-token-amount 0.01 \
  --gorlami --chain-id 8453

# Dry-run a local script
poetry run python wayfinder_paths/run_strategy.py --script .wayfinder_runs/my_flow.py \
  --gorlami --chain-id 8453
```

**Scope:** Vnets fork EVM chains (Base, Arbitrum, Ethereum, etc.) only. Off-chain or non-EVM protocols like Hyperliquid **cannot** be simulated — dry-runs only apply to on-chain EVM transactions.

Uses your existing Wayfinder API key — no extra config needed. See the `/simulation-dry-run` skill for full details.

## Paths

Wayfinder paths bundle a manifest, runtime component, optional applet, and optional host skill exports into a publishable artifact.

### Publish a path

```bash
export WAYFINDER_PATHS_API_URL="https://strategies-dev.wayfinder.ai"
export WAYFINDER_API_KEY="wk_..."

poetry run wayfinder path fmt --path examples/paths/virtual-delta-neutral
poetry run wayfinder path doctor --path examples/paths/virtual-delta-neutral
poetry run wayfinder path publish --path examples/paths/virtual-delta-neutral
```

For bonded publishes, add the owner wallet and requested risk tier:

```bash
poetry run wayfinder path publish \
  --path examples/paths/virtual-delta-neutral \
  --bonded \
  --owner-wallet 0xYourWallet \
  --risk-tier execution
```

What `wayfinder path publish` does now:

- builds `bundle.zip` and `source.zip`
- renders thin host skill exports when the path has a skill
- calls `POST /api/v1/paths/publish/init/`
- uploads artifacts directly to signed object-storage URLs
- calls `POST /api/v1/paths/publish/finalize/`
- prints the resulting `manageUrl`, `reviewState`, `publishState`, and `nextAction`

The backend no longer proxies archive bytes during ingest. Uploaded artifacts land in quarantine storage first, then E2B performs review and rebuild verification before approved artifacts are promoted to the published bucket.

### Agent Guidance

If you are automating path publication:

- prefer `wayfinder path publish` over custom multipart upload scripts
- create a browser applet by default (`wayfinder path init ... --applet` is the default); use `--no-applet` only when the owner explicitly wants a path without presentation UI
- run `wayfinder path fmt` and `wayfinder path doctor` before publish
- assume `WAYFINDER_PATHS_API_URL` points at the Strategies backend and `WAYFINDER_API_KEY` provides auth when required
- surface `manageUrl`, `ownerLinkRequired`, `reviewState`, `publishState`, and `nextAction` exactly as returned
- if `ownerLinkRequired` is `true`, the next step is owner wallet linking and bonding, not another publish
- if `reviewState` is `review`, direct the owner to the submissions page to read the recommended changes

### Delta Lab For Applets

Use two different Delta Lab access patterns depending on what is running:

- SDK scripts, MCP tools, and agent-side Python should use `DELTA_LAB_CLIENT` with `system.api_base_url`, for example `https://wayfinder.ai/api/v1/delta-lab/...`
- presentation applets shown on the public path page should use the public browser-safe timeseries endpoint:
  - prod: `https://wayfinder.ai/api/v1/delta-lab/public/assets/<symbol>/timeseries/`
  - dev: `https://strategies-dev.wayfinder.ai/api/v1/delta-lab/public/assets/<symbol>/timeseries/`

For applet authors and agents:

- if the applet is served by the path page on Strategies, same-origin `/api/v1/delta-lab/public/assets/...` is acceptable
- if the applet may run in preview, E2B, or any static host, take the base from the host bridge (`wf:state.apiBase` first, then `wf:hello` origin) instead of inventing one in the browser
- do not probe both dev and prod from the same applet build
- do not call `/api/v1/delta-lab/symbols/`; that route does not exist
- use the public `.../public/assets/<symbol>/timeseries/` route for presentation data, and reserve authenticated Delta Lab routes for SDK/server-side use
- treat non-200 responses, especially `404`, as expected unavailability and show a clear fallback UI instead of crashing the applet
- make sure every referenced static asset exists under `applet/dist/`
- include explicit `icon`, `shortcut icon`, and `apple-touch-icon` tags in the applet HTML to avoid implicit browser favicon 404s

## Claude MCP Integration

The repo includes an MCP server for Claude Code (see `.mcp.json`).
Start it with:

```bash
poetry run python -m wayfinder_paths.mcp.server
```

### MCP Tools (actions)

| Tool | Description |
| --- | --- |
| `core_get_adapters_and_strategies` | Discover installed adapters and strategies |
| `core_get_wallets` / `core_wallets` | Read wallets, wallet profiles, and protocol-tracked portfolios |
| `onchain_quote_swap` / `onchain_swap` / `onchain_send` | Quote then execute on-chain swaps; ERC-20 / native transfers |
| `hyperliquid_get_state` / `_search_market` / `_search_mid_prices` | Read Hyperliquid account, market, and price data |
| `hyperliquid_place_market_order` / `_place_limit_order` / `_place_trigger_order` / `_cancel_order` / `_update_leverage` / `_deposit` / `_withdraw` | Per-action Hyperliquid writes |
| `polymarket_read` / `polymarket_get_state` | Read Polymarket markets, prices, orders, and account state |
| `polymarket_deposit_pusd` / `_withdraw` / `_place_market_order` / `_place_limit_order` / `_cancel_order` / `_redeem_positions` | Per-action Polymarket writes |
| `contracts_list` / `_get` / `_compile` / `_call` / `_deploy` / `_execute` | Solidity contract artifact, read, deploy, and write tools |
| `research_*` | Web, X, DeFiLlama, Goldsky, Alpha Lab, and Delta Lab research tools |
| `core_run_script` / `core_run_strategy` / `core_runner` | Execute bounded scripts, strategy actions, and runner jobs |

The SDK exposes one MCP catalog. OpenCode scopes per-agent visibility with `permission` wildcard rules, while Claude and OpenCode permissions still gate sensitive calls.

## Scripts and Helpers

- `scripts/setup.py`: bootstrap Poetry, config, wallets, and MCP
- `scripts/make_wallets.py`: create local dev wallets (optionally keystores)
- `scripts/create_strategy.py`: scaffold a new strategy

`justfile` shortcuts (requires `just`):

```bash
just lint
just format
just test
just test-smoke
just create-strategy "My Strategy Name"
just create-wallets
just create-wallet stablecoin_yield_strategy
```

## Contributing

We welcome contributions!

### Add a New Strategy

```bash
just create-strategy "My Strategy Name"
# or
poetry run python scripts/create_strategy.py "My Strategy Name"
```

Implement:

- `deposit()`
- `update()`
- `exit()`
- `_status()`

### Add a New Adapter

Create a new directory under `wayfinder_paths/adapters/` with a `manifest.yaml` and adapter implementation. Implement protocol-specific methods and return `(success, data)` tuples.

### Tests and Style

- Tests: `poetry run pytest -v`
- Smoke tests: `poetry run pytest -k smoke -v`
- Adapter/strategy tests: `just test-adapter <name>` / `just test-strategy <name>`
- Lint/format: `just lint` and `just format`

More details in `TESTING.md`.

## Security Notes

- **Never commit `config.json`** (contains private keys)
- **Use test wallets** for development
- **RPCs are optional**: if `strategy.rpc_urls` is not set for a chain, reads default to the Wayfinder proxy RPC at `${system.api_base_url}/blockchain/rpc/<chain_id>/` (requires `system.api_key`). Set `strategy.rpc_urls` to use your own RPC provider(s).

## Community

- [Discord](https://discord.gg/fUVwGMXjm3)
- [GitHub Issues](https://github.com/WayfinderFoundation/wayfinder-paths/issues)
- [Wayfinder](https://wayfinder.ai)

## License

MIT License - see [LICENSE](LICENSE) for details.

