wayfinder-paths 0.1.22__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.22.dist-info → wayfinder_paths-0.1.23.dist-info}/METADATA +2 -3
  49. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.23.dist-info}/RECORD +51 -60
  50. {wayfinder_paths-0.1.22.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.22.dist-info → wayfinder_paths-0.1.23.dist-info}/LICENSE +0 -0
@@ -1,166 +0,0 @@
1
- import sys
2
- from pathlib import Path
3
-
4
- # TODO: Replace MyStrategy with your actual strategy class name
5
- from wayfinder_paths.strategies.your_strategy.strategy import (
6
- MyStrategy, # noqa: E402
7
- )
8
-
9
- # Ensure wayfinder-paths is on path for tests.test_utils import
10
- # This is a workaround until conftest loading order is resolved
11
- _wayfinder_path_dir = Path(__file__).parent.parent.parent.parent.resolve()
12
- _wayfinder_path_str = str(_wayfinder_path_dir)
13
- if _wayfinder_path_str not in sys.path:
14
- sys.path.insert(0, _wayfinder_path_str)
15
- elif sys.path.index(_wayfinder_path_str) > 0:
16
- # Move to front to take precedence
17
- sys.path.remove(_wayfinder_path_str)
18
- sys.path.insert(0, _wayfinder_path_str)
19
-
20
- import pytest # noqa: E402
21
-
22
- try:
23
- from tests.test_utils import get_canonical_examples, load_strategy_examples
24
- except ImportError:
25
- # Fallback if path setup didn't work
26
- import importlib.util
27
-
28
- test_utils_path = Path(_wayfinder_path_dir) / "tests" / "test_utils.py"
29
- spec = importlib.util.spec_from_file_location("tests.test_utils", test_utils_path)
30
- test_utils = importlib.util.module_from_spec(spec)
31
- spec.loader.exec_module(test_utils)
32
- get_canonical_examples = test_utils.get_canonical_examples
33
- load_strategy_examples = test_utils.load_strategy_examples
34
-
35
-
36
- @pytest.fixture
37
- def strategy():
38
- mock_config = {
39
- "main_wallet": {"address": "0x1234567890123456789012345678901234567890"},
40
- "strategy_wallet": {"address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"},
41
- }
42
-
43
- s = MyStrategy(
44
- config=mock_config,
45
- main_wallet=mock_config["main_wallet"],
46
- strategy_wallet=mock_config["strategy_wallet"],
47
- )
48
-
49
- # TODO: Add mocking for your adapters here if needed
50
- # Example for balance_adapter:
51
- # if hasattr(s, "balance_adapter") and s.balance_adapter:
52
- # usdc_balance_mock = AsyncMock(return_value=(True, 60000000))
53
- # gas_balance_mock = AsyncMock(return_value=(True, 2000000000000000))
54
- #
55
- # def get_balance_side_effect(query, wallet_address, **kwargs):
56
- # token_id = query if isinstance(query, str) else (query or {}).get("token_id")
57
- # if token_id == "usd-coin-base" or token_id == "usd-coin":
58
- # elif token_id == "ethereum-base" or token_id == "ethereum":
59
- #
60
- # s.balance_adapter.get_balance = AsyncMock(
61
- # side_effect=get_balance_side_effect
62
- # )
63
-
64
- # Example for token_adapter:
65
- # if hasattr(s, "token_adapter") and s.token_adapter:
66
- # default_token = {
67
- # "id": "usd-coin-base",
68
- # "symbol": "USDC",
69
- # "name": "USD Coin",
70
- # "decimals": 6,
71
- # "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
72
- # "chain": {"code": "base", "id": 8453, "name": "Base"},
73
- # }
74
- # s.token_adapter.get_token = AsyncMock(return_value=(True, default_token))
75
- # s.token_adapter.get_gas_token = AsyncMock(return_value=(True, default_token))
76
-
77
- # Example for transaction adapters:
78
- # if hasattr(s, "tx_adapter") and s.tx_adapter:
79
- # s.tx_adapter.move_from_main_wallet_to_strategy_wallet = AsyncMock(
80
- # )
81
- # s.tx_adapter.move_from_strategy_wallet_to_main_wallet = AsyncMock(
82
- # )
83
-
84
- # Example for ledger_adapter:
85
- # if hasattr(s, "ledger_adapter") and s.ledger_adapter:
86
- # s.ledger_adapter.get_strategy_net_deposit = AsyncMock(
87
- # )
88
- # s.ledger_adapter.get_strategy_transactions = AsyncMock(
89
- # )
90
-
91
- return s
92
-
93
-
94
- @pytest.mark.asyncio
95
- @pytest.mark.smoke
96
- async def test_smoke(strategy):
97
- examples = load_strategy_examples(Path(__file__))
98
- smoke_data = examples["smoke"]
99
-
100
- st = await strategy.status()
101
- assert isinstance(st, dict)
102
- assert "portfolio_value" in st or "net_deposit" in st or "strategy_status" in st
103
-
104
- deposit_params = smoke_data.get("deposit", {})
105
- ok, msg = await strategy.deposit(**deposit_params)
106
- assert isinstance(ok, bool)
107
- assert isinstance(msg, str)
108
-
109
- ok, msg = await strategy.update(**smoke_data.get("update", {}))
110
- assert isinstance(ok, bool)
111
-
112
- ok, msg = await strategy.withdraw(**smoke_data.get("withdraw", {}))
113
- assert isinstance(ok, bool)
114
-
115
-
116
- @pytest.mark.asyncio
117
- async def test_canonical_usage(strategy):
118
- examples = load_strategy_examples(Path(__file__))
119
- canonical = get_canonical_examples(examples)
120
-
121
- for example_name, example_data in canonical.items():
122
- if "deposit" in example_data:
123
- deposit_params = example_data.get("deposit", {})
124
- ok, _ = await strategy.deposit(**deposit_params)
125
- assert ok, f"Canonical example '{example_name}' deposit failed"
126
-
127
- if "update" in example_data:
128
- ok, msg = await strategy.update()
129
- assert ok, f"Canonical example '{example_name}' update failed: {msg}"
130
-
131
- if "status" in example_data:
132
- st = await strategy.status()
133
- assert isinstance(st, dict), (
134
- f"Canonical example '{example_name}' status failed"
135
- )
136
-
137
-
138
- @pytest.mark.asyncio
139
- async def test_error_cases(strategy):
140
- examples = load_strategy_examples(Path(__file__))
141
-
142
- for example_name, example_data in examples.items():
143
- if isinstance(example_data, dict) and "expect" in example_data:
144
- expect = example_data.get("expect", {})
145
-
146
- if "deposit" in example_data:
147
- deposit_params = example_data.get("deposit", {})
148
- ok, _ = await strategy.deposit(**deposit_params)
149
-
150
- if expect.get("success") is False:
151
- assert ok is False, (
152
- f"Expected {example_name} deposit to fail but it succeeded"
153
- )
154
- elif expect.get("success") is True:
155
- assert ok is True, (
156
- f"Expected {example_name} deposit to succeed but it failed"
157
- )
158
-
159
- if "update" in example_data:
160
- ok, _ = await strategy.update()
161
- if "success" in expect:
162
- expected_success = expect.get("success")
163
- assert ok == expected_success, (
164
- f"Expected {example_name} update to "
165
- f"{'succeed' if expected_success else 'fail'} but got opposite"
166
- )
@@ -1,63 +0,0 @@
1
- import pytest
2
-
3
- from wayfinder_paths.core.adapters.BaseAdapter import BaseAdapter
4
- from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
5
-
6
-
7
- class FakeAdapter(BaseAdapter):
8
- adapter_type = "FAKE"
9
-
10
- async def connect(self) -> bool:
11
- return True
12
-
13
- async def get_balance(self, asset: str):
14
- return {"asset": asset, "amount": 100}
15
-
16
-
17
- class FakeLedgerAdapter(BaseAdapter):
18
- adapter_type = "LEDGER"
19
-
20
- async def connect(self) -> bool:
21
- return True
22
-
23
- async def record_strategy_snapshot(self, **kwargs):
24
- pass
25
-
26
-
27
- class FakeStrategy(Strategy):
28
- name = "Fake Strategy"
29
-
30
- async def deposit(self, amount: float = 0) -> StatusTuple:
31
- return (True, "deposited")
32
-
33
- async def update(self) -> StatusTuple:
34
- return (True, "updated")
35
-
36
- async def withdraw(self, amount: float = 0) -> StatusTuple:
37
- return (True, "withdrew")
38
-
39
- async def _status(self) -> StatusDict:
40
- return {"total_earned": 0.0, "strategy_status": {"ok": True}}
41
-
42
- @staticmethod
43
- def policy() -> str:
44
- return "wallet.id == 'TEST'"
45
-
46
-
47
- @pytest.mark.asyncio
48
- async def test_smoke_deposit_update_withdraw_status():
49
- s = FakeStrategy(
50
- config={
51
- "strategy_wallet": {"address": "0x1234567890123456789012345678901234567890"}
52
- }
53
- )
54
- s.register_adapters([FakeAdapter("fake")])
55
- s.ledger_adapter = FakeLedgerAdapter("ledger")
56
- ok, msg = await s.deposit(amount=1)
57
- assert ok
58
- ok, msg = await s.update()
59
- assert ok
60
- ok, msg = await s.withdraw(amount=1)
61
- assert ok
62
- st = await s.status()
63
- assert "total_earned" in st