wayfinder-paths 0.1.21__py3-none-any.whl → 0.1.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wayfinder-paths might be problematic. Click here for more details.

Files changed (63) hide show
  1. wayfinder_paths/__init__.py +0 -4
  2. wayfinder_paths/adapters/balance_adapter/README.md +0 -1
  3. wayfinder_paths/adapters/balance_adapter/adapter.py +65 -169
  4. wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -113
  5. wayfinder_paths/adapters/brap_adapter/README.md +22 -75
  6. wayfinder_paths/adapters/brap_adapter/adapter.py +187 -576
  7. wayfinder_paths/adapters/brap_adapter/examples.json +21 -140
  8. wayfinder_paths/adapters/brap_adapter/test_adapter.py +6 -234
  9. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +39 -86
  10. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +5 -1
  11. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +6 -5
  12. wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
  13. wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
  14. wayfinder_paths/adapters/moonwell_adapter/adapter.py +108 -198
  15. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +37 -23
  16. wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
  17. wayfinder_paths/core/__init__.py +0 -3
  18. wayfinder_paths/core/clients/BRAPClient.py +3 -0
  19. wayfinder_paths/core/clients/ClientManager.py +0 -7
  20. wayfinder_paths/core/clients/LedgerClient.py +196 -172
  21. wayfinder_paths/core/clients/WayfinderClient.py +0 -1
  22. wayfinder_paths/core/clients/__init__.py +0 -5
  23. wayfinder_paths/core/clients/protocols.py +0 -13
  24. wayfinder_paths/core/config.py +0 -164
  25. wayfinder_paths/core/constants/__init__.py +58 -2
  26. wayfinder_paths/core/constants/base.py +8 -22
  27. wayfinder_paths/core/constants/chains.py +36 -0
  28. wayfinder_paths/core/constants/contracts.py +39 -0
  29. wayfinder_paths/core/constants/tokens.py +9 -0
  30. wayfinder_paths/core/strategies/Strategy.py +0 -10
  31. wayfinder_paths/core/utils/evm_helpers.py +5 -15
  32. wayfinder_paths/core/utils/tokens.py +28 -0
  33. wayfinder_paths/core/utils/transaction.py +13 -7
  34. wayfinder_paths/core/utils/web3.py +5 -3
  35. wayfinder_paths/policies/enso.py +1 -2
  36. wayfinder_paths/policies/hyper_evm.py +6 -3
  37. wayfinder_paths/policies/hyperlend.py +1 -2
  38. wayfinder_paths/policies/moonwell.py +12 -7
  39. wayfinder_paths/policies/prjx.py +1 -3
  40. wayfinder_paths/run_strategy.py +97 -300
  41. wayfinder_paths/strategies/basis_trading_strategy/constants.py +3 -1
  42. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +19 -14
  43. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +12 -11
  44. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +20 -33
  45. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +21 -18
  46. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -130
  47. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +32 -42
  48. {wayfinder_paths-0.1.21.dist-info → wayfinder_paths-0.1.23.dist-info}/METADATA +3 -4
  49. {wayfinder_paths-0.1.21.dist-info → wayfinder_paths-0.1.23.dist-info}/RECORD +51 -60
  50. {wayfinder_paths-0.1.21.dist-info → wayfinder_paths-0.1.23.dist-info}/WHEEL +1 -1
  51. wayfinder_paths/core/clients/WalletClient.py +0 -41
  52. wayfinder_paths/core/engine/StrategyJob.py +0 -110
  53. wayfinder_paths/core/services/test_local_evm_txn.py +0 -145
  54. wayfinder_paths/templates/adapter/README.md +0 -150
  55. wayfinder_paths/templates/adapter/adapter.py +0 -16
  56. wayfinder_paths/templates/adapter/examples.json +0 -8
  57. wayfinder_paths/templates/adapter/test_adapter.py +0 -30
  58. wayfinder_paths/templates/strategy/README.md +0 -186
  59. wayfinder_paths/templates/strategy/examples.json +0 -11
  60. wayfinder_paths/templates/strategy/strategy.py +0 -35
  61. wayfinder_paths/templates/strategy/test_strategy.py +0 -166
  62. wayfinder_paths/tests/test_smoke_manifest.py +0 -63
  63. {wayfinder_paths-0.1.21.dist-info → wayfinder_paths-0.1.23.dist-info}/LICENSE +0 -0
@@ -1,145 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from unittest.mock import AsyncMock, MagicMock
4
-
5
- import pytest
6
-
7
- from wayfinder_paths.core.services.local_evm_txn import BASE_CHAIN_ID, LocalEvmTxn
8
-
9
-
10
- class _FakeTxHash:
11
- def __init__(self, value: str):
12
- self._value = value
13
-
14
- def hex(self) -> str:
15
- return self._value
16
-
17
-
18
- @pytest.mark.asyncio
19
- async def test_base_defaults_to_two_confirmations():
20
- txn = LocalEvmTxn(config={})
21
-
22
- fake_web3 = MagicMock()
23
- fake_web3.eth = MagicMock()
24
- fake_web3.eth.send_raw_transaction = AsyncMock(return_value=_FakeTxHash("0x1"))
25
- fake_web3.eth.wait_for_transaction_receipt = AsyncMock(
26
- return_value={
27
- "status": 1,
28
- "blockNumber": 100,
29
- "transactionHash": "0x1",
30
- "gasUsed": 21_000,
31
- "logs": [],
32
- }
33
- )
34
-
35
- txn.get_web3 = MagicMock(return_value=fake_web3)
36
- txn._validate_transaction = MagicMock(side_effect=lambda tx: tx)
37
- txn._nonce_transaction = AsyncMock(side_effect=lambda tx, _w3: tx)
38
- txn._gas_limit_transaction = AsyncMock(side_effect=lambda tx, _w3: tx)
39
- txn._gas_price_transaction = AsyncMock(side_effect=lambda tx, _chain_id, _w3: tx)
40
- txn._sign_transaction = MagicMock(return_value=b"signed")
41
- txn._close_web3 = AsyncMock()
42
- txn._wait_for_confirmations = AsyncMock()
43
-
44
- ok, result = await txn.broadcast_transaction(
45
- {
46
- "chainId": BASE_CHAIN_ID,
47
- "from": "0x0000000000000000000000000000000000000001",
48
- "to": "0x0000000000000000000000000000000000000002",
49
- "value": 0,
50
- },
51
- wait_for_receipt=True,
52
- timeout=1,
53
- )
54
-
55
- assert ok is True
56
- txn._wait_for_confirmations.assert_awaited_once_with(fake_web3, 100, 2)
57
- assert result["confirmations"] == 2
58
- assert result["confirmed_block_number"] == 102
59
-
60
-
61
- @pytest.mark.asyncio
62
- async def test_non_base_defaults_to_zero_confirmations():
63
- txn = LocalEvmTxn(config={})
64
-
65
- fake_web3 = MagicMock()
66
- fake_web3.eth = MagicMock()
67
- fake_web3.eth.send_raw_transaction = AsyncMock(return_value=_FakeTxHash("0x1"))
68
- fake_web3.eth.wait_for_transaction_receipt = AsyncMock(
69
- return_value={
70
- "status": 1,
71
- "blockNumber": 100,
72
- "transactionHash": "0x1",
73
- "gasUsed": 21_000,
74
- "logs": [],
75
- }
76
- )
77
-
78
- txn.get_web3 = MagicMock(return_value=fake_web3)
79
- txn._validate_transaction = MagicMock(side_effect=lambda tx: tx)
80
- txn._nonce_transaction = AsyncMock(side_effect=lambda tx, _w3: tx)
81
- txn._gas_limit_transaction = AsyncMock(side_effect=lambda tx, _w3: tx)
82
- txn._gas_price_transaction = AsyncMock(side_effect=lambda tx, _chain_id, _w3: tx)
83
- txn._sign_transaction = MagicMock(return_value=b"signed")
84
- txn._close_web3 = AsyncMock()
85
- txn._wait_for_confirmations = AsyncMock()
86
-
87
- ok, result = await txn.broadcast_transaction(
88
- {
89
- "chainId": 1,
90
- "from": "0x0000000000000000000000000000000000000001",
91
- "to": "0x0000000000000000000000000000000000000002",
92
- "value": 0,
93
- },
94
- wait_for_receipt=True,
95
- timeout=1,
96
- )
97
-
98
- assert ok is True
99
- txn._wait_for_confirmations.assert_not_awaited()
100
- assert result["confirmations"] == 0
101
- assert result["confirmed_block_number"] == 100
102
-
103
-
104
- @pytest.mark.asyncio
105
- async def test_explicit_confirmations_override_defaults():
106
- txn = LocalEvmTxn(config={})
107
-
108
- fake_web3 = MagicMock()
109
- fake_web3.eth = MagicMock()
110
- fake_web3.eth.send_raw_transaction = AsyncMock(return_value=_FakeTxHash("0x1"))
111
- fake_web3.eth.wait_for_transaction_receipt = AsyncMock(
112
- return_value={
113
- "status": 1,
114
- "blockNumber": 100,
115
- "transactionHash": "0x1",
116
- "gasUsed": 21_000,
117
- "logs": [],
118
- }
119
- )
120
-
121
- txn.get_web3 = MagicMock(return_value=fake_web3)
122
- txn._validate_transaction = MagicMock(side_effect=lambda tx: tx)
123
- txn._nonce_transaction = AsyncMock(side_effect=lambda tx, _w3: tx)
124
- txn._gas_limit_transaction = AsyncMock(side_effect=lambda tx, _w3: tx)
125
- txn._gas_price_transaction = AsyncMock(side_effect=lambda tx, _chain_id, _w3: tx)
126
- txn._sign_transaction = MagicMock(return_value=b"signed")
127
- txn._close_web3 = AsyncMock()
128
- txn._wait_for_confirmations = AsyncMock()
129
-
130
- ok, result = await txn.broadcast_transaction(
131
- {
132
- "chainId": BASE_CHAIN_ID,
133
- "from": "0x0000000000000000000000000000000000000001",
134
- "to": "0x0000000000000000000000000000000000000002",
135
- "value": 0,
136
- },
137
- wait_for_receipt=True,
138
- timeout=1,
139
- confirmations=0,
140
- )
141
-
142
- assert ok is True
143
- txn._wait_for_confirmations.assert_not_awaited()
144
- assert result["confirmations"] == 0
145
- assert result["confirmed_block_number"] == 100
@@ -1,150 +0,0 @@
1
- # Adapter Template
2
-
3
- Adapters expose protocol-specific capabilities to strategies. They wrap one or more clients from `wayfinder_paths.core.clients`.
4
-
5
- ## Quick Start
6
-
7
- 1. Copy the template:
8
- ```bash
9
- cp -r wayfinder_paths/templates/adapter wayfinder_paths/adapters/my_adapter
10
- ```
11
- 2. Rename `MyAdapter` in `adapter.py` to match your adapter's purpose.
12
- 3. Set `adapter_type` to a unique identifier (e.g., `"MY_PROTOCOL"`).
13
- 4. Implement your public methods.
14
- 5. Add tests in `test_adapter.py`.
15
-
16
- ## Directory Structure
17
-
18
- ```
19
- my_adapter/
20
- ├── adapter.py # Adapter implementation
21
- ├── examples.json # Example payloads (optional)
22
- ├── test_adapter.py # Pytest tests
23
- └── README.md # Adapter documentation
24
- ```
25
-
26
- ## Adapter Structure
27
-
28
- ```python
29
- from typing import Any
30
-
31
- from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
32
- from wayfinder_paths.core.clients.SomeClient import SomeClient
33
-
34
-
35
- class MyAdapter(BaseAdapter):
36
- """Adapter for MyProtocol operations."""
37
-
38
- adapter_type = "MY_PROTOCOL"
39
-
40
- def __init__(self, config: dict[str, Any] | None = None):
41
- super().__init__("my_adapter", config)
42
- self.client = SomeClient()
43
-
44
- async def connect(self) -> bool:
45
- """Optional: Establish connectivity."""
46
- return True
47
-
48
- async def do_something(self, param: str) -> tuple[bool, Any]:
49
- """
50
- Execute an operation.
51
-
52
- Args:
53
- param: Operation parameter
54
-
55
- Returns:
56
- Tuple of (success, data) where data is result or error message
57
- """
58
- try:
59
- result = await self.client.call(param)
60
- return (True, result)
61
- except Exception as e:
62
- self.logger.error(f"Operation failed: {e}")
63
- return (False, str(e))
64
- ```
65
-
66
- ## Key Conventions
67
-
68
- 1. **Return tuples**: All methods return `(success: bool, data: Any)`
69
- 2. **Adapter type**: Set `adapter_type` for registry lookups
70
- 3. **Config access**: Use `self.config` for configuration
71
- 4. **Logging**: Use `self.logger` for consistent logging
72
- 5. **Error handling**: Catch exceptions and return `(False, error_message)`
73
-
74
- ## BaseAdapter Interface
75
-
76
- ```python
77
- class BaseAdapter(ABC):
78
- adapter_type: str | None = None
79
-
80
- def __init__(self, name: str, config: dict | None = None):
81
- self.name = name
82
- self.config = config or {}
83
- self.logger = logger.bind(adapter=self.__class__.__name__)
84
-
85
- async def connect(self) -> bool:
86
- """Establish connectivity (default: True)."""
87
- return True
88
-
89
- async def get_balance(self, asset: str) -> dict:
90
- """Get balance (raises NotImplementedError by default)."""
91
- raise NotImplementedError
92
-
93
- async def health_check(self) -> dict:
94
- """Check adapter health."""
95
- ...
96
-
97
- async def close(self) -> None:
98
- """Clean up resources."""
99
- pass
100
- ```
101
-
102
- ## Testing
103
-
104
- Create `test_adapter.py`:
105
-
106
- ```python
107
- import pytest
108
- from unittest.mock import AsyncMock, patch
109
- from .adapter import MyAdapter
110
-
111
-
112
- class TestMyAdapter:
113
- @pytest.fixture
114
- def adapter(self):
115
- return MyAdapter()
116
-
117
- @pytest.mark.asyncio
118
- async def test_do_something_success(self, adapter):
119
- with patch.object(adapter, "client") as mock_client:
120
- mock_client.call = AsyncMock(return_value={"result": "ok"})
121
-
122
- success, data = await adapter.do_something(param="test")
123
-
124
- assert success
125
- assert data["result"] == "ok"
126
-
127
- @pytest.mark.asyncio
128
- async def test_do_something_failure(self, adapter):
129
- with patch.object(adapter, "client") as mock_client:
130
- mock_client.call = AsyncMock(side_effect=Exception("API error"))
131
-
132
- success, data = await adapter.do_something(param="test")
133
-
134
- assert not success
135
- assert "error" in data.lower()
136
- ```
137
-
138
- Run tests:
139
-
140
- ```bash
141
- poetry run pytest wayfinder_paths/adapters/my_adapter/ -v
142
- ```
143
-
144
- ## Best Practices
145
-
146
- - Keep adapters thin - business logic belongs in strategies
147
- - Mock clients in tests, not adapters
148
- - Document each public method with Args/Returns docstrings
149
- - Use type hints for all parameters and return values
150
- - Log errors with context for debugging
@@ -1,16 +0,0 @@
1
- from typing import Any
2
-
3
- from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
4
-
5
-
6
- class MyAdapter(BaseAdapter):
7
- adapter_type: str = "MY_ADAPTER"
8
-
9
- def __init__(self, config: dict[str, Any] | None = None):
10
- super().__init__("my_adapter", config)
11
-
12
- async def connect(self) -> bool:
13
- return True
14
-
15
- async def example_operation(self, **kwargs) -> tuple[bool, str]:
16
- return (True, "example.op executed")
@@ -1,8 +0,0 @@
1
- {
2
- "connect": {},
3
- "example_operation": {
4
- "args": {"foo": "bar"}
5
- }
6
- }
7
-
8
-
@@ -1,30 +0,0 @@
1
- import pytest
2
-
3
- # TODO: Replace MyAdapter with your actual adapter class name
4
- from .adapter import MyAdapter
5
-
6
- # For mocking clients, uncomment when needed:
7
-
8
-
9
- class TestMyAdapter:
10
- @pytest.fixture
11
- def adapter(self):
12
- return MyAdapter(config={})
13
-
14
- @pytest.mark.asyncio
15
- async def test_health_check(self, adapter):
16
- health = await adapter.health_check()
17
- assert isinstance(health, dict)
18
- assert health.get("status") in {"healthy", "unhealthy", "error"}
19
-
20
- @pytest.mark.asyncio
21
- async def test_connect(self, adapter):
22
- ok = await adapter.connect()
23
- assert isinstance(ok, bool)
24
-
25
- def test_capabilities(self, adapter):
26
- assert hasattr(adapter, "adapter_type")
27
-
28
- @pytest.mark.asyncio
29
- async def test_basic_functionality(self, adapter):
30
- assert adapter is not None
@@ -1,186 +0,0 @@
1
- # Strategy Template
2
-
3
- This template provides scaffolding for a new strategy.
4
-
5
- ## Quick Start
6
-
7
- 1. Copy the template:
8
- ```bash
9
- cp -r wayfinder_paths/templates/strategy wayfinder_paths/strategies/my_strategy
10
- ```
11
- Or use the convenience command:
12
- ```bash
13
- just create-strategy "My Strategy Name"
14
- ```
15
- 2. Rename the class in `strategy.py` to match your strategy name.
16
- 3. Implement the required methods (`deposit`, `update`, `exit`, `_status`).
17
- 4. Add tests in `test_strategy.py`.
18
- 5. Fill out `examples.json` with sample CLI invocations.
19
-
20
- ## Directory Structure
21
-
22
- ```
23
- my_strategy/
24
- ├── strategy.py # Strategy implementation
25
- ├── examples.json # Example CLI payloads
26
- ├── test_strategy.py # Pytest tests
27
- └── README.md # Strategy documentation
28
- ```
29
-
30
- ## Required Methods
31
-
32
- ```python
33
- async def deposit(self, main_token_amount: float, gas_token_amount: float) -> StatusTuple:
34
- """Move funds from main wallet into strategy wallet and deploy capital."""
35
-
36
- async def update(self) -> StatusTuple:
37
- """Periodic rebalance/optimization loop."""
38
-
39
- async def exit(self, **kwargs) -> StatusTuple:
40
- """Transfer funds from strategy wallet back to main wallet."""
41
-
42
- async def _status(self) -> StatusDict:
43
- """Return portfolio_value, net_deposit, and strategy_status."""
44
- ```
45
-
46
- ## Optional Methods
47
-
48
- ```python
49
- async def withdraw(self, **kwargs) -> StatusTuple:
50
- """Unwind positions. Default implementation unwinds ledger operations."""
51
-
52
- async def partial_liquidate(self, usd_value: float) -> tuple[bool, LiquidationResult]:
53
- """Liquidate a portion of the position by USD value."""
54
-
55
- async def setup(self) -> None:
56
- """Post-construction initialization."""
57
-
58
- async def health_check(self) -> dict:
59
- """Check strategy and adapter health."""
60
- ```
61
-
62
- ## Strategy Structure
63
-
64
- ```python
65
- from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
66
- from wayfinder_paths.adapters.balance_adapter.adapter import BalanceAdapter
67
-
68
-
69
- class MyStrategy(Strategy):
70
- name = "My Strategy"
71
-
72
- def __init__(self, config: dict | None = None, **kwargs):
73
- super().__init__(config, **kwargs)
74
- self.config = config or {}
75
-
76
- # Initialize and register adapters
77
- balance_adapter = BalanceAdapter(
78
- self.config,
79
- main_wallet_signing_callback=kwargs.get("main_wallet_signing_callback"),
80
- strategy_wallet_signing_callback=kwargs.get("strategy_wallet_signing_callback"),
81
- )
82
- self.register_adapters([balance_adapter])
83
- self.balance_adapter = balance_adapter
84
-
85
- async def deposit(
86
- self, main_token_amount: float = 0.0, gas_token_amount: float = 0.0
87
- ) -> StatusTuple:
88
- if main_token_amount <= 0:
89
- return (False, "Nothing to deposit")
90
-
91
- # Implement deposit logic
92
- return (True, f"Deposited {main_token_amount} tokens")
93
-
94
- async def update(self) -> StatusTuple:
95
- # Implement rebalancing logic
96
- return (True, "Update complete")
97
-
98
- async def exit(self, **kwargs) -> StatusTuple:
99
- # Implement exit logic
100
- return (True, "Exit complete")
101
-
102
- async def _status(self) -> StatusDict:
103
- return {
104
- "portfolio_value": 0.0,
105
- "net_deposit": 0.0,
106
- "strategy_status": {"message": "healthy"},
107
- "gas_available": 0.0,
108
- "gassed_up": True,
109
- }
110
- ```
111
-
112
- ## Testing
113
-
114
- Create `test_strategy.py` using `examples.json`:
115
-
116
- ```python
117
- import pytest
118
- from pathlib import Path
119
- from tests.test_utils import load_strategy_examples
120
- from .strategy import MyStrategy
121
-
122
-
123
- @pytest.mark.asyncio
124
- async def test_smoke():
125
- """Basic strategy lifecycle test."""
126
- examples = load_strategy_examples(Path(__file__))
127
- smoke_example = examples["smoke"]
128
-
129
- s = MyStrategy()
130
-
131
- # Deposit
132
- deposit_params = smoke_example.get("deposit", {})
133
- ok, _ = await s.deposit(**deposit_params)
134
- assert ok
135
-
136
- # Update
137
- ok, _ = await s.update()
138
- assert ok
139
-
140
- # Status
141
- st = await s._status()
142
- assert "portfolio_value" in st
143
- assert "net_deposit" in st
144
- assert "strategy_status" in st
145
- ```
146
-
147
- Run tests:
148
-
149
- ```bash
150
- poetry run pytest wayfinder_paths/strategies/my_strategy/ -v
151
- ```
152
-
153
- ## Running the Strategy
154
-
155
- ```bash
156
- # Install dependencies
157
- poetry install
158
-
159
- # Generate wallets
160
- just create-wallets
161
- just create-wallet my_strategy
162
-
163
- # Configure API key in config.json
164
-
165
- # Check status
166
- poetry run python wayfinder_paths/run_strategy.py my_strategy --action status --config config.json
167
-
168
- # Deposit
169
- poetry run python wayfinder_paths/run_strategy.py my_strategy \
170
- --action deposit --main-token-amount 100 --gas-token-amount 0.01 --config config.json
171
-
172
- # Run update
173
- poetry run python wayfinder_paths/run_strategy.py my_strategy --action update --config config.json
174
-
175
- # Withdraw
176
- poetry run python wayfinder_paths/run_strategy.py my_strategy --action withdraw --config config.json
177
- ```
178
-
179
- ## Best Practices
180
-
181
- - Return `(success: bool, message: str)` tuples from all action methods
182
- - Always populate `portfolio_value`, `net_deposit`, and `strategy_status` in `_status`
183
- - Register adapters via `register_adapters()` in `__init__`
184
- - Use adapters for external operations, not clients directly
185
- - Keep strategy logic clear and well-documented
186
- - Add error handling with informative messages
@@ -1,11 +0,0 @@
1
- {
2
- "deposit": {
3
- "main_token_amount": 100,
4
- "gas_token_amount": 0.001
5
- },
6
- "update": {},
7
- "status": {},
8
- "withdraw": {}
9
- }
10
-
11
-
@@ -1,35 +0,0 @@
1
- from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
2
-
3
-
4
- class MyStrategy(Strategy):
5
- name = "My Strategy"
6
- description = "Short description of what the strategy does."
7
- summary = "One-line summary for discovery."
8
-
9
- def __init__(self):
10
- super().__init__()
11
-
12
- async def setup(self):
13
- return None
14
-
15
- async def deposit(
16
- self, main_token_amount: float, gas_token_amount: float
17
- ) -> StatusTuple:
18
- return (True, "Deposit successful")
19
-
20
- async def withdraw(self, amount: float | None = None) -> StatusTuple:
21
- return await super().withdraw(amount=amount)
22
-
23
- async def update(self) -> StatusTuple:
24
- return (True, "Update successful")
25
-
26
- async def _status(self) -> StatusDict:
27
- return {
28
- "portfolio_value": 0.0,
29
- "net_deposit": 0.0,
30
- "strategy_status": {},
31
- }
32
-
33
- @staticmethod
34
- def policies() -> list[str]:
35
- return []