wayfinder-paths 0.1.22__py3-none-any.whl → 0.1.24__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 (156) 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 +313 -167
  4. wayfinder_paths/adapters/balance_adapter/manifest.yaml +8 -0
  5. wayfinder_paths/adapters/balance_adapter/test_adapter.py +41 -124
  6. wayfinder_paths/adapters/boros_adapter/__init__.py +17 -0
  7. wayfinder_paths/adapters/boros_adapter/adapter.py +1574 -0
  8. wayfinder_paths/adapters/boros_adapter/client.py +476 -0
  9. wayfinder_paths/adapters/boros_adapter/manifest.yaml +10 -0
  10. wayfinder_paths/adapters/boros_adapter/parsers.py +88 -0
  11. wayfinder_paths/adapters/boros_adapter/test_adapter.py +460 -0
  12. wayfinder_paths/adapters/boros_adapter/test_golden.py +156 -0
  13. wayfinder_paths/adapters/boros_adapter/types.py +70 -0
  14. wayfinder_paths/adapters/boros_adapter/utils.py +85 -0
  15. wayfinder_paths/adapters/brap_adapter/README.md +22 -75
  16. wayfinder_paths/adapters/brap_adapter/adapter.py +187 -576
  17. wayfinder_paths/adapters/brap_adapter/examples.json +21 -140
  18. wayfinder_paths/adapters/brap_adapter/manifest.yaml +9 -0
  19. wayfinder_paths/adapters/brap_adapter/test_adapter.py +6 -234
  20. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +180 -92
  21. wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml +9 -0
  22. wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +82 -14
  23. wayfinder_paths/adapters/hyperliquid_adapter/__init__.py +2 -9
  24. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +586 -61
  25. wayfinder_paths/adapters/hyperliquid_adapter/executor.py +47 -68
  26. wayfinder_paths/adapters/hyperliquid_adapter/manifest.yaml +14 -0
  27. wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +2 -3
  28. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +17 -21
  29. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +3 -6
  30. wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +4 -8
  31. wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +2 -2
  32. wayfinder_paths/adapters/ledger_adapter/README.md +4 -1
  33. wayfinder_paths/adapters/ledger_adapter/adapter.py +3 -3
  34. wayfinder_paths/adapters/ledger_adapter/manifest.yaml +7 -0
  35. wayfinder_paths/adapters/ledger_adapter/test_adapter.py +1 -2
  36. wayfinder_paths/adapters/moonwell_adapter/adapter.py +649 -547
  37. wayfinder_paths/adapters/moonwell_adapter/manifest.yaml +14 -0
  38. wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +160 -239
  39. wayfinder_paths/adapters/multicall_adapter/__init__.py +7 -0
  40. wayfinder_paths/adapters/multicall_adapter/adapter.py +166 -0
  41. wayfinder_paths/adapters/multicall_adapter/manifest.yaml +5 -0
  42. wayfinder_paths/adapters/multicall_adapter/test_adapter.py +97 -0
  43. wayfinder_paths/adapters/pendle_adapter/README.md +102 -0
  44. wayfinder_paths/adapters/pendle_adapter/__init__.py +7 -0
  45. wayfinder_paths/adapters/pendle_adapter/adapter.py +1992 -0
  46. wayfinder_paths/adapters/pendle_adapter/examples.json +11 -0
  47. wayfinder_paths/adapters/pendle_adapter/manifest.yaml +21 -0
  48. wayfinder_paths/adapters/pendle_adapter/test_adapter.py +666 -0
  49. wayfinder_paths/adapters/pool_adapter/manifest.yaml +6 -0
  50. wayfinder_paths/adapters/token_adapter/adapter.py +14 -0
  51. wayfinder_paths/adapters/token_adapter/examples.json +0 -4
  52. wayfinder_paths/adapters/token_adapter/manifest.yaml +7 -0
  53. wayfinder_paths/conftest.py +24 -17
  54. wayfinder_paths/core/__init__.py +0 -3
  55. wayfinder_paths/core/adapters/BaseAdapter.py +0 -25
  56. wayfinder_paths/core/adapters/models.py +17 -7
  57. wayfinder_paths/core/clients/BRAPClient.py +4 -1
  58. wayfinder_paths/core/clients/ClientManager.py +0 -7
  59. wayfinder_paths/core/clients/LedgerClient.py +196 -172
  60. wayfinder_paths/core/clients/TokenClient.py +47 -1
  61. wayfinder_paths/core/clients/WayfinderClient.py +1 -3
  62. wayfinder_paths/core/clients/__init__.py +0 -5
  63. wayfinder_paths/core/clients/protocols.py +21 -35
  64. wayfinder_paths/core/clients/test_ledger_client.py +448 -0
  65. wayfinder_paths/core/config.py +10 -162
  66. wayfinder_paths/core/constants/__init__.py +73 -2
  67. wayfinder_paths/core/constants/base.py +8 -17
  68. wayfinder_paths/core/constants/chains.py +36 -0
  69. wayfinder_paths/core/constants/contracts.py +52 -0
  70. wayfinder_paths/core/constants/erc20_abi.py +0 -1
  71. wayfinder_paths/core/constants/hyperlend_abi.py +0 -4
  72. wayfinder_paths/core/constants/hyperliquid.py +16 -0
  73. wayfinder_paths/core/constants/moonwell_abi.py +0 -15
  74. wayfinder_paths/core/constants/tokens.py +9 -0
  75. wayfinder_paths/core/engine/manifest.py +66 -0
  76. wayfinder_paths/core/strategies/Strategy.py +0 -71
  77. wayfinder_paths/core/strategies/__init__.py +10 -1
  78. wayfinder_paths/core/strategies/opa_loop.py +167 -0
  79. wayfinder_paths/core/utils/evm_helpers.py +5 -15
  80. wayfinder_paths/core/utils/test_transaction.py +289 -0
  81. wayfinder_paths/core/utils/tokens.py +28 -0
  82. wayfinder_paths/core/utils/transaction.py +57 -8
  83. wayfinder_paths/core/utils/web3.py +8 -3
  84. wayfinder_paths/mcp/__init__.py +5 -0
  85. wayfinder_paths/mcp/preview.py +185 -0
  86. wayfinder_paths/mcp/scripting.py +84 -0
  87. wayfinder_paths/mcp/server.py +52 -0
  88. wayfinder_paths/mcp/state/profile_store.py +195 -0
  89. wayfinder_paths/mcp/state/store.py +89 -0
  90. wayfinder_paths/mcp/test_scripting.py +267 -0
  91. wayfinder_paths/mcp/tools/__init__.py +0 -0
  92. wayfinder_paths/mcp/tools/balances.py +290 -0
  93. wayfinder_paths/mcp/tools/discovery.py +158 -0
  94. wayfinder_paths/mcp/tools/execute.py +770 -0
  95. wayfinder_paths/mcp/tools/hyperliquid.py +931 -0
  96. wayfinder_paths/mcp/tools/quotes.py +288 -0
  97. wayfinder_paths/mcp/tools/run_script.py +286 -0
  98. wayfinder_paths/mcp/tools/strategies.py +188 -0
  99. wayfinder_paths/mcp/tools/tokens.py +46 -0
  100. wayfinder_paths/mcp/tools/wallets.py +354 -0
  101. wayfinder_paths/mcp/utils.py +129 -0
  102. wayfinder_paths/policies/enso.py +1 -2
  103. wayfinder_paths/policies/hyper_evm.py +6 -3
  104. wayfinder_paths/policies/hyperlend.py +1 -2
  105. wayfinder_paths/policies/hyperliquid.py +1 -1
  106. wayfinder_paths/policies/lifi.py +18 -0
  107. wayfinder_paths/policies/moonwell.py +12 -7
  108. wayfinder_paths/policies/prjx.py +1 -3
  109. wayfinder_paths/policies/util.py +8 -2
  110. wayfinder_paths/run_strategy.py +97 -300
  111. wayfinder_paths/strategies/basis_trading_strategy/constants.py +3 -1
  112. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +47 -133
  113. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +24 -53
  114. wayfinder_paths/strategies/boros_hype_strategy/__init__.py +3 -0
  115. wayfinder_paths/strategies/boros_hype_strategy/boros_ops_mixin.py +450 -0
  116. wayfinder_paths/strategies/boros_hype_strategy/constants.py +255 -0
  117. wayfinder_paths/strategies/boros_hype_strategy/examples.json +37 -0
  118. wayfinder_paths/strategies/boros_hype_strategy/hyperevm_ops_mixin.py +114 -0
  119. wayfinder_paths/strategies/boros_hype_strategy/hyperliquid_ops_mixin.py +642 -0
  120. wayfinder_paths/strategies/boros_hype_strategy/manifest.yaml +36 -0
  121. wayfinder_paths/strategies/boros_hype_strategy/planner.py +460 -0
  122. wayfinder_paths/strategies/boros_hype_strategy/risk_ops_mixin.py +886 -0
  123. wayfinder_paths/strategies/boros_hype_strategy/snapshot_mixin.py +494 -0
  124. wayfinder_paths/strategies/boros_hype_strategy/strategy.py +1194 -0
  125. wayfinder_paths/strategies/boros_hype_strategy/test_planner_golden.py +374 -0
  126. wayfinder_paths/{templates/strategy → strategies/boros_hype_strategy}/test_strategy.py +99 -63
  127. wayfinder_paths/strategies/boros_hype_strategy/types.py +365 -0
  128. wayfinder_paths/strategies/boros_hype_strategy/withdraw_mixin.py +997 -0
  129. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +15 -23
  130. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +27 -62
  131. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +84 -58
  132. wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +5 -15
  133. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +69 -164
  134. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +43 -76
  135. wayfinder_paths/tests/test_mcp_quote_swap.py +165 -0
  136. wayfinder_paths/tests/test_test_coverage.py +1 -4
  137. wayfinder_paths-0.1.24.dist-info/METADATA +378 -0
  138. wayfinder_paths-0.1.24.dist-info/RECORD +185 -0
  139. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.24.dist-info}/WHEEL +1 -1
  140. wayfinder_paths/core/clients/WalletClient.py +0 -41
  141. wayfinder_paths/core/engine/StrategyJob.py +0 -110
  142. wayfinder_paths/core/services/test_local_evm_txn.py +0 -145
  143. wayfinder_paths/scripts/create_strategy.py +0 -139
  144. wayfinder_paths/scripts/make_wallets.py +0 -142
  145. wayfinder_paths/templates/adapter/README.md +0 -150
  146. wayfinder_paths/templates/adapter/adapter.py +0 -16
  147. wayfinder_paths/templates/adapter/examples.json +0 -8
  148. wayfinder_paths/templates/adapter/test_adapter.py +0 -30
  149. wayfinder_paths/templates/strategy/README.md +0 -186
  150. wayfinder_paths/templates/strategy/examples.json +0 -11
  151. wayfinder_paths/templates/strategy/strategy.py +0 -35
  152. wayfinder_paths/tests/test_smoke_manifest.py +0 -63
  153. wayfinder_paths-0.1.22.dist-info/METADATA +0 -355
  154. wayfinder_paths-0.1.22.dist-info/RECORD +0 -129
  155. /wayfinder_paths/{scripts → mcp/state}/__init__.py +0 -0
  156. {wayfinder_paths-0.1.22.dist-info → wayfinder_paths-0.1.24.dist-info}/LICENSE +0 -0
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import os
6
+ from decimal import ROUND_DOWN, Decimal, InvalidOperation, getcontext
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import yaml
11
+
12
+ getcontext().prec = 78
13
+
14
+
15
+ def ok(result: Any) -> dict[str, Any]:
16
+ return {"ok": True, "result": result}
17
+
18
+
19
+ def err(code: str, message: str, details: Any | None = None) -> dict[str, Any]:
20
+ return {
21
+ "ok": False,
22
+ "error": {"code": str(code), "message": str(message), "details": details},
23
+ }
24
+
25
+
26
+ def repo_root() -> Path:
27
+ cur = Path(__file__).resolve()
28
+ for parent in [cur, *cur.parents]:
29
+ if (parent / "pyproject.toml").exists():
30
+ return parent
31
+ return Path.cwd()
32
+
33
+
34
+ def read_yaml(path: Path) -> dict[str, Any]:
35
+ data = yaml.safe_load(path.read_text())
36
+ return data if isinstance(data, dict) else {}
37
+
38
+
39
+ def read_text_excerpt(path: Path, *, max_chars: int = 1200) -> str | None:
40
+ try:
41
+ text = path.read_text(encoding="utf-8", errors="replace").strip()
42
+ except OSError:
43
+ return None
44
+ if not text:
45
+ return None
46
+ if len(text) <= max_chars:
47
+ return text
48
+ return text[: max_chars - 3] + "..."
49
+
50
+
51
+ def load_json_file(path: Path) -> Any:
52
+ try:
53
+ return json.loads(path.read_text())
54
+ except Exception:
55
+ return None
56
+
57
+
58
+ def load_config_json() -> dict[str, Any]:
59
+ cfg_path = os.getenv("WAYFINDER_CONFIG_PATH", "config.json")
60
+ path = (
61
+ repo_root() / cfg_path if not Path(cfg_path).is_absolute() else Path(cfg_path)
62
+ )
63
+ parsed = load_json_file(path)
64
+ return parsed if isinstance(parsed, dict) else {}
65
+
66
+
67
+ def wallets_path() -> Path:
68
+ cfg = load_config_json()
69
+ system = cfg.get("system") if isinstance(cfg.get("system"), dict) else {}
70
+ candidate = (
71
+ (system or {}).get("wallets_path")
72
+ or os.getenv("WALLETS_PATH")
73
+ or "wallets.json"
74
+ )
75
+ p = Path(candidate)
76
+ if not p.is_absolute():
77
+ p = repo_root() / p
78
+ return p
79
+
80
+
81
+ def load_wallets() -> list[dict[str, Any]]:
82
+ cfg = load_config_json()
83
+ if isinstance(cfg.get("wallets"), list):
84
+ return [w for w in cfg["wallets"] if isinstance(w, dict)]
85
+
86
+ p = wallets_path()
87
+ if p.exists():
88
+ parsed = load_json_file(p)
89
+ if isinstance(parsed, list):
90
+ return [w for w in parsed if isinstance(w, dict)]
91
+ if isinstance(parsed, dict) and isinstance(parsed.get("wallets"), list):
92
+ return [w for w in parsed["wallets"] if isinstance(w, dict)]
93
+ return []
94
+
95
+
96
+ def find_wallet_by_label(label: str) -> dict[str, Any] | None:
97
+ want = str(label).strip()
98
+ if not want:
99
+ return None
100
+ for w in load_wallets():
101
+ if str(w.get("label", "")).strip() == want:
102
+ return w
103
+ return None
104
+
105
+
106
+ def normalize_address(addr: str | None) -> str | None:
107
+ if not addr:
108
+ return None
109
+ a = str(addr).strip()
110
+ return a if a else None
111
+
112
+
113
+ def parse_amount_to_raw(amount: str, decimals: int) -> int:
114
+ try:
115
+ d = Decimal(str(amount).strip())
116
+ except (InvalidOperation, ValueError) as exc:
117
+ raise ValueError(f"Invalid amount: {amount}") from exc
118
+ if d <= 0:
119
+ raise ValueError("Amount must be positive")
120
+ scale = Decimal(10) ** int(decimals)
121
+ raw = (d * scale).to_integral_value(rounding=ROUND_DOWN)
122
+ if raw <= 0:
123
+ raise ValueError("Amount is too small after decimal scaling")
124
+ return int(raw)
125
+
126
+
127
+ def sha256_json(obj: Any) -> str:
128
+ payload = json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
129
+ return "sha256:" + hashlib.sha256(payload.encode("utf-8")).hexdigest()
@@ -1,7 +1,6 @@
1
+ from wayfinder_paths.core.constants.contracts import ENSO_ROUTER
1
2
  from wayfinder_paths.policies.util import allow_functions
2
3
 
3
- ENSO_ROUTER = "0xf75584ef6673ad213a685a1b58cc0330b8ea22cf"
4
-
5
4
 
6
5
  async def enso_swap():
7
6
  return await allow_functions(
@@ -1,9 +1,12 @@
1
+ from wayfinder_paths.core.constants.contracts import (
2
+ HYPERCORE_SENTINEL_ADDRESS,
3
+ HYPERCORE_SENTINEL_VALUE,
4
+ HYPEREVM_WHYPE,
5
+ )
1
6
  from wayfinder_paths.policies.evm import native_transfer
2
7
  from wayfinder_paths.policies.util import allow_functions
3
8
 
4
- WHYPE_TOKEN = "0x5555555555555555555555555555555555555555"
5
- HYPERCORE_SENTINEL_ADDRESS = "0x2222222222222222222222222222222222222222"
6
- HYPERCORE_SENTINEL_VALUE = 100_000_000_000
9
+ WHYPE_TOKEN = HYPEREVM_WHYPE
7
10
 
8
11
 
9
12
  def hypecore_sentinel_deposit():
@@ -1,7 +1,6 @@
1
+ from wayfinder_paths.core.constants.contracts import HYPERLEND_POOL
1
2
  from wayfinder_paths.policies.util import allow_functions
2
3
 
3
- HYPERLEND_POOL = "0x00A89d7a5A02160f20150EbEA7a2b5E4879A1A8b"
4
-
5
4
 
6
5
  async def hyperlend_supply_and_withdraw():
7
6
  return await allow_functions(
@@ -24,7 +24,7 @@ def any_hyperliquid_user_payload():
24
24
  "field": "chainId",
25
25
  "field_source": "ethereum_typed_data_domain",
26
26
  "operator": "eq",
27
- "value": "421614",
27
+ "value": "42161",
28
28
  }
29
29
  ],
30
30
  }
@@ -0,0 +1,18 @@
1
+ from wayfinder_paths.policies.util import allow_functions
2
+
3
+ LIFI_ROUTERS: dict[int:str] = {999: "0x0a0758d937d1059c356D4714e57F5df0239bce1A"}
4
+ LIFI_GENERIC = "0x31a9b1835864706Af10103b31Ea2b79bdb995F5F"
5
+
6
+
7
+ async def lifi_swap(chain_id):
8
+ # NOTE: we get the abi from the base contract as it is a generic abi used everywhere
9
+ # and not all chains have this ABI published
10
+ return await allow_functions(
11
+ policy_name="Allow LIFI Swap",
12
+ abi_chain_id=8453,
13
+ address=LIFI_ROUTERS[chain_id],
14
+ function_names=[
15
+ "swapTokensMultipleV3ERC20ToERC20",
16
+ ],
17
+ abi_address_override=LIFI_GENERIC,
18
+ )
@@ -1,12 +1,17 @@
1
+ from wayfinder_paths.core.constants.contracts import (
2
+ BASE_WETH,
3
+ MOONWELL_COMPTROLLER,
4
+ MOONWELL_M_USDC,
5
+ MOONWELL_M_WETH,
6
+ MOONWELL_M_WSTETH,
7
+ )
1
8
  from wayfinder_paths.policies.util import allow_functions
2
9
 
3
- WETH = "0x4200000000000000000000000000000000000006"
4
-
5
- M_USDC = "0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22"
6
- M_WETH = "0x628ff693426583D9a7FB391E54366292F509D457"
7
- M_WSTETH = "0x627Fe393Bc6EdDA28e99AE648fD6fF362514304b"
8
-
9
- COMPTROLLER = "0xfbb21d0380bee3312b33c4353c8936a0f13ef26c"
10
+ WETH = BASE_WETH
11
+ M_USDC = MOONWELL_M_USDC
12
+ M_WETH = MOONWELL_M_WETH
13
+ M_WSTETH = MOONWELL_M_WSTETH
14
+ COMPTROLLER = MOONWELL_COMPTROLLER
10
15
 
11
16
 
12
17
  async def weth_deposit():
@@ -1,8 +1,6 @@
1
+ from wayfinder_paths.core.constants.contracts import PRJX_NPM, PRJX_ROUTER
1
2
  from wayfinder_paths.policies.util import allow_functions
2
3
 
3
- PRJX_ROUTER = "0x1ebdfc75ffe3ba3de61e7138a3e8706ac841af9b"
4
- PRJX_NPM = "0xeAd19AE861c29bBb2101E834922B2FEee69B9091"
5
-
6
4
 
7
5
  async def prjx_swap():
8
6
  return await allow_functions(
@@ -2,7 +2,11 @@ from wayfinder_paths.core.utils.evm_helpers import get_abi_filtered
2
2
 
3
3
 
4
4
  async def allow_functions(
5
- policy_name: str, abi_chain_id: int, address: str, function_names: list[str]
5
+ policy_name: str,
6
+ abi_chain_id: int,
7
+ address: str,
8
+ function_names: list[str],
9
+ abi_address_override=None,
6
10
  ):
7
11
  # Note: ChainID is just for fetching ABI, doesn't appear in the final policy. Doesn't bind a strict chain.
8
12
  return {
@@ -19,7 +23,9 @@ async def allow_functions(
19
23
  {
20
24
  "field_source": "ethereum_calldata",
21
25
  "field": "function_name",
22
- "abi": await get_abi_filtered(abi_chain_id, address, function_names),
26
+ "abi": await get_abi_filtered(
27
+ abi_chain_id, abi_address_override or address, function_names
28
+ ),
23
29
  "operator": "in",
24
30
  "value": function_names,
25
31
  },