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
@@ -1,17 +1,88 @@
1
- from .base import (
2
- CHAIN_CODE_TO_ID,
1
+ from wayfinder_paths.core.constants.base import (
2
+ ADAPTER_BALANCE,
3
+ ADAPTER_BRAP,
4
+ ADAPTER_HYPERLEND,
5
+ ADAPTER_HYPERLIQUID,
6
+ ADAPTER_LEDGER,
7
+ ADAPTER_MOONWELL,
8
+ ADAPTER_POOL,
9
+ ADAPTER_TOKEN,
10
+ DEFAULT_HTTP_TIMEOUT,
3
11
  DEFAULT_NATIVE_GAS_UNITS,
12
+ DEFAULT_PAGINATION_LIMIT,
4
13
  DEFAULT_SLIPPAGE,
5
14
  GAS_BUFFER_MULTIPLIER,
15
+ MANTISSA,
16
+ MAX_UINT256,
6
17
  ONE_GWEI,
18
+ SECONDS_PER_YEAR,
19
+ SUGGESTED_GAS_PRICE_MULTIPLIER,
20
+ SUGGESTED_PRIORITY_FEE_MULTIPLIER,
21
+ )
22
+ from wayfinder_paths.core.constants.chains import (
23
+ CHAIN_CODE_TO_ID,
24
+ CHAIN_ID_ARBITRUM,
25
+ CHAIN_ID_AVALANCHE,
26
+ CHAIN_ID_BASE,
27
+ CHAIN_ID_BSC,
28
+ CHAIN_ID_ETHEREUM,
29
+ CHAIN_ID_HYPEREVM,
30
+ CHAIN_ID_POLYGON,
31
+ POA_MIDDLEWARE_CHAIN_IDS,
32
+ PRE_EIP_1559_CHAIN_IDS,
33
+ SUPPORTED_CHAINS,
34
+ )
35
+ from wayfinder_paths.core.constants.contracts import (
36
+ NATIVE_TOKEN_SENTINEL,
7
37
  ZERO_ADDRESS,
8
38
  )
9
39
 
40
+ from .hyperliquid import (
41
+ ARBITRUM_USDC_ADDRESS,
42
+ ARBITRUM_USDC_TOKEN_ID,
43
+ DEFAULT_HYPERLIQUID_BUILDER_FEE,
44
+ DEFAULT_HYPERLIQUID_BUILDER_FEE_TENTHS_BP,
45
+ HYPE_FEE_WALLET,
46
+ HYPERLIQUID_BRIDGE_ADDRESS,
47
+ )
48
+
10
49
  __all__ = [
50
+ "NATIVE_TOKEN_SENTINEL",
11
51
  "ZERO_ADDRESS",
12
52
  "CHAIN_CODE_TO_ID",
13
53
  "DEFAULT_NATIVE_GAS_UNITS",
14
54
  "GAS_BUFFER_MULTIPLIER",
15
55
  "ONE_GWEI",
56
+ "SUGGESTED_PRIORITY_FEE_MULTIPLIER",
57
+ "SUGGESTED_GAS_PRICE_MULTIPLIER",
16
58
  "DEFAULT_SLIPPAGE",
59
+ "DEFAULT_HTTP_TIMEOUT",
60
+ "DEFAULT_PAGINATION_LIMIT",
61
+ "MANTISSA",
62
+ "SECONDS_PER_YEAR",
63
+ "MAX_UINT256",
64
+ "ADAPTER_BALANCE",
65
+ "ADAPTER_BRAP",
66
+ "ADAPTER_MOONWELL",
67
+ "ADAPTER_HYPERLIQUID",
68
+ "ADAPTER_POOL",
69
+ "ADAPTER_TOKEN",
70
+ "ADAPTER_LEDGER",
71
+ "ADAPTER_HYPERLEND",
72
+ "CHAIN_ID_ETHEREUM",
73
+ "CHAIN_ID_BASE",
74
+ "CHAIN_ID_ARBITRUM",
75
+ "CHAIN_ID_BSC",
76
+ "CHAIN_ID_POLYGON",
77
+ "CHAIN_ID_AVALANCHE",
78
+ "CHAIN_ID_HYPEREVM",
79
+ "SUPPORTED_CHAINS",
80
+ "POA_MIDDLEWARE_CHAIN_IDS",
81
+ "PRE_EIP_1559_CHAIN_IDS",
82
+ "HYPERLIQUID_BRIDGE_ADDRESS",
83
+ "ARBITRUM_USDC_ADDRESS",
84
+ "ARBITRUM_USDC_TOKEN_ID",
85
+ "HYPE_FEE_WALLET",
86
+ "DEFAULT_HYPERLIQUID_BUILDER_FEE_TENTHS_BP",
87
+ "DEFAULT_HYPERLIQUID_BUILDER_FEE",
17
88
  ]
@@ -1,21 +1,9 @@
1
- ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
2
-
3
- # Chain code to EVM chain id mapping
4
- CHAIN_CODE_TO_ID = {
5
- "base": 8453,
6
- "arbitrum": 42161,
7
- "arbitrum-one": 42161,
8
- "ethereum": 1,
9
- "mainnet": 1,
10
- "hyperevm": 999,
11
- }
12
-
13
- # Gas/defaults
14
1
  DEFAULT_NATIVE_GAS_UNITS = 21000
15
- # Fallback gas limit used only when RPC gas estimation fails for non-revert reasons.
16
- # Must be high enough for typical DeFi interactions (lending, swaps, etc.).
17
2
  GAS_BUFFER_MULTIPLIER = 1.1
18
3
  ONE_GWEI = 1_000_000_000
4
+ SUGGESTED_PRIORITY_FEE_MULTIPLIER = 1.5
5
+ SUGGESTED_GAS_PRICE_MULTIPLIER = 1.5
6
+
19
7
  DEFAULT_SLIPPAGE = 0.005
20
8
 
21
9
  # Timeout constants (seconds)
@@ -23,8 +11,8 @@ DEFAULT_SLIPPAGE = 0.005
23
11
  # even if the transaction is eventually mined. A longer timeout reduces false negatives that
24
12
  # can lead to unsafe retry behavior (nonce gaps, duplicate swaps, etc.).
25
13
  DEFAULT_HTTP_TIMEOUT = 30.0 # HTTP client timeout
14
+ DEFAULT_TRANSACTION_TIMEOUT = 180 # Transaction receipt timeout (seconds)
26
15
 
27
- # Adapter type identifiers
28
16
  ADAPTER_BALANCE = "BALANCE"
29
17
  ADAPTER_BRAP = "BRAP"
30
18
  ADAPTER_MOONWELL = "MOONWELL"
@@ -34,5 +22,8 @@ ADAPTER_TOKEN = "TOKEN"
34
22
  ADAPTER_LEDGER = "LEDGER"
35
23
  ADAPTER_HYPERLEND = "HYPERLEND"
36
24
 
37
- # Pagination defaults
38
25
  DEFAULT_PAGINATION_LIMIT = 50
26
+
27
+ MANTISSA = 10**18
28
+ SECONDS_PER_YEAR = 365 * 24 * 60 * 60
29
+ MAX_UINT256 = 2**256 - 1
@@ -0,0 +1,36 @@
1
+ CHAIN_ID_ETHEREUM = 1
2
+ CHAIN_ID_BASE = 8453
3
+ CHAIN_ID_ARBITRUM = 42161
4
+ CHAIN_ID_BSC = 56
5
+ CHAIN_ID_POLYGON = 137
6
+ CHAIN_ID_AVALANCHE = 43114
7
+ CHAIN_ID_HYPEREVM = 999
8
+
9
+ CHAIN_CODE_TO_ID = {
10
+ "base": CHAIN_ID_BASE,
11
+ "arbitrum": CHAIN_ID_ARBITRUM,
12
+ "arbitrum-one": CHAIN_ID_ARBITRUM,
13
+ "ethereum": CHAIN_ID_ETHEREUM,
14
+ "mainnet": CHAIN_ID_ETHEREUM,
15
+ "hyperevm": CHAIN_ID_HYPEREVM,
16
+ }
17
+
18
+ SUPPORTED_CHAINS = [
19
+ CHAIN_ID_ETHEREUM,
20
+ CHAIN_ID_BASE,
21
+ CHAIN_ID_BSC,
22
+ CHAIN_ID_ARBITRUM,
23
+ CHAIN_ID_POLYGON,
24
+ CHAIN_ID_HYPEREVM,
25
+ ]
26
+
27
+ POA_MIDDLEWARE_CHAIN_IDS: set[int] = {
28
+ CHAIN_ID_BSC,
29
+ CHAIN_ID_POLYGON,
30
+ CHAIN_ID_AVALANCHE,
31
+ }
32
+
33
+ PRE_EIP_1559_CHAIN_IDS: set[int] = {
34
+ CHAIN_ID_BSC,
35
+ CHAIN_ID_ARBITRUM,
36
+ }
@@ -0,0 +1,52 @@
1
+ from eth_utils import to_checksum_address
2
+
3
+ ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
4
+ NATIVE_TOKEN_SENTINEL = to_checksum_address(
5
+ "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
6
+ )
7
+
8
+ BASE_WETH = to_checksum_address("0x4200000000000000000000000000000000000006")
9
+ BASE_USDC = to_checksum_address("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913")
10
+ BASE_WSTETH = to_checksum_address("0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452")
11
+
12
+ MOONWELL_M_USDC = to_checksum_address("0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22")
13
+ MOONWELL_M_WETH = to_checksum_address("0x628ff693426583D9a7FB391E54366292F509D457")
14
+ MOONWELL_M_WSTETH = to_checksum_address("0x627Fe393Bc6EdDA28e99AE648fD6fF362514304b")
15
+ MOONWELL_COMPTROLLER = to_checksum_address("0xfBb21d0380beE3312B33c4353c8936a0F13EF26C")
16
+ MOONWELL_REWARD_DISTRIBUTOR = to_checksum_address(
17
+ "0xe9005b078701e2A0948D2EaC43010D35870Ad9d2"
18
+ )
19
+ MOONWELL_WELL_TOKEN = to_checksum_address("0xA88594D404727625A9437C3f886C7643872296AE")
20
+
21
+ ENSO_ROUTER = to_checksum_address("0xF75584eF6673aD213a685a1B58Cc0330B8eA22Cf")
22
+
23
+ HYPEREVM_WHYPE = to_checksum_address("0x5555555555555555555555555555555555555555")
24
+ HYPERCORE_SENTINEL_ADDRESS = to_checksum_address(
25
+ "0x2222222222222222222222222222222222222222"
26
+ )
27
+ HYPERCORE_SENTINEL_VALUE = 100_000_000_000
28
+
29
+ HYPERLEND_POOL = to_checksum_address("0x00A89d7a5A02160f20150EbEA7a2b5E4879A1A8b")
30
+ HYPERLEND_WRAPPED_TOKEN_GATEWAY = to_checksum_address(
31
+ "0x49558c794ea2aC8974C9F27886DDfAa951E99171"
32
+ )
33
+
34
+ PRJX_ROUTER = to_checksum_address("0x1EbDFC75FfE3ba3de61E7138a3E8706aC841Af9B")
35
+ PRJX_NPM = to_checksum_address("0xeaD19AE861c29bBb2101E834922B2FEee69B9091")
36
+
37
+ ARBITRUM_USDC = to_checksum_address("0xaf88d065e77c8cC2239327C5EDb3A432268e5831")
38
+
39
+ HYPERLIQUID_BRIDGE = to_checksum_address("0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7")
40
+
41
+ BOROS_ROUTER = to_checksum_address("0x8080808080dab95efed788a9214e400ba552def6")
42
+ BOROS_MARKET_HUB = to_checksum_address("0x1080808080f145b14228443212e62447c112adad")
43
+
44
+ USDT_ETHEREUM = to_checksum_address("0xdAC17F958D2ee523a2206206994597C13D831ec7")
45
+ USDT_POLYGON = to_checksum_address("0xc2132D05D31c914a87C6611C10748AEb04B58e8F")
46
+ USDT_BSC = to_checksum_address("0x55d398326f99059fF775485246999027B3197955")
47
+
48
+ TOKENS_REQUIRING_APPROVAL_RESET: set[tuple[int, str]] = {
49
+ (1, USDT_ETHEREUM),
50
+ (137, USDT_POLYGON),
51
+ (56, USDT_BSC),
52
+ }
@@ -1,4 +1,3 @@
1
- # Standard ERC20 ABI - includes common functions needed for token operations
2
1
  ERC20_ABI = [
3
2
  {
4
3
  "constant": True,
@@ -1,4 +1,3 @@
1
- # Minimal Pool ABI for supply and deposit operations
2
1
  POOL_ABI = [
3
2
  {
4
3
  "name": "supply",
@@ -37,7 +36,6 @@ POOL_ABI = [
37
36
  },
38
37
  ]
39
38
 
40
- # Protocol Data Provider ABI for reserve token addresses and user data
41
39
  PROTOCOL_DATA_PROVIDER_ABI = [
42
40
  {
43
41
  "type": "function",
@@ -71,7 +69,6 @@ PROTOCOL_DATA_PROVIDER_ABI = [
71
69
  },
72
70
  ]
73
71
 
74
- # Wrapped Token Gateway ABI for native token operations
75
72
  WRAPPED_TOKEN_GATEWAY_ABI = [
76
73
  {
77
74
  "type": "function",
@@ -126,7 +123,6 @@ WRAPPED_TOKEN_GATEWAY_ABI = [
126
123
  },
127
124
  ]
128
125
 
129
- # WETH ABI for native token wrapping
130
126
  WETH_ABI = [
131
127
  {
132
128
  "inputs": [],
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ HYPERLIQUID_BRIDGE_ADDRESS: str = "0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7"
6
+ ARBITRUM_USDC_ADDRESS: str = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
7
+ ARBITRUM_USDC_TOKEN_ID: str = "usd-coin-arbitrum"
8
+ HYPE_FEE_WALLET: str = "0xaA1D89f333857eD78F8434CC4f896A9293EFE65c"
9
+
10
+ # Tenths of a basis point: 30 -> 0.030% (3 bps)
11
+ DEFAULT_HYPERLIQUID_BUILDER_FEE_TENTHS_BP: int = 30
12
+
13
+ DEFAULT_HYPERLIQUID_BUILDER_FEE: dict[str, Any] = {
14
+ "b": HYPE_FEE_WALLET,
15
+ "f": DEFAULT_HYPERLIQUID_BUILDER_FEE_TENTHS_BP,
16
+ }
@@ -1,6 +1,4 @@
1
- # mToken (CErc20Delegator) ABI - for lending, borrowing, and position management
2
1
  MTOKEN_ABI = [
3
- # Lend (supply) tokens by minting mTokens
4
2
  {
5
3
  "name": "mint",
6
4
  "type": "function",
@@ -8,7 +6,6 @@ MTOKEN_ABI = [
8
6
  "inputs": [{"name": "mintAmount", "type": "uint256"}],
9
7
  "outputs": [{"name": "", "type": "uint256"}],
10
8
  },
11
- # Withdraw (redeem) underlying by burning mTokens
12
9
  {
13
10
  "name": "redeem",
14
11
  "type": "function",
@@ -16,7 +13,6 @@ MTOKEN_ABI = [
16
13
  "inputs": [{"name": "redeemTokens", "type": "uint256"}],
17
14
  "outputs": [{"name": "", "type": "uint256"}],
18
15
  },
19
- # Withdraw exact underlying amount
20
16
  {
21
17
  "name": "redeemUnderlying",
22
18
  "type": "function",
@@ -24,7 +20,6 @@ MTOKEN_ABI = [
24
20
  "inputs": [{"name": "redeemAmount", "type": "uint256"}],
25
21
  "outputs": [{"name": "", "type": "uint256"}],
26
22
  },
27
- # Borrow underlying tokens
28
23
  {
29
24
  "name": "borrow",
30
25
  "type": "function",
@@ -32,7 +27,6 @@ MTOKEN_ABI = [
32
27
  "inputs": [{"name": "borrowAmount", "type": "uint256"}],
33
28
  "outputs": [{"name": "", "type": "uint256"}],
34
29
  },
35
- # Repay borrowed tokens
36
30
  {
37
31
  "name": "repayBorrow",
38
32
  "type": "function",
@@ -124,7 +118,6 @@ MTOKEN_ABI = [
124
118
  "inputs": [],
125
119
  "outputs": [{"name": "", "type": "uint256"}],
126
120
  },
127
- # Accrue interest
128
121
  {
129
122
  "name": "accrueInterest",
130
123
  "type": "function",
@@ -141,9 +134,7 @@ MTOKEN_ABI = [
141
134
  },
142
135
  ]
143
136
 
144
- # Comptroller ABI - for collateral management and account liquidity
145
137
  COMPTROLLER_ABI = [
146
- # Enable a market as collateral
147
138
  {
148
139
  "name": "enterMarkets",
149
140
  "type": "function",
@@ -151,7 +142,6 @@ COMPTROLLER_ABI = [
151
142
  "inputs": [{"name": "mTokens", "type": "address[]"}],
152
143
  "outputs": [{"name": "", "type": "uint256[]"}],
153
144
  },
154
- # Disable a market as collateral
155
145
  {
156
146
  "name": "exitMarket",
157
147
  "type": "function",
@@ -234,7 +224,6 @@ COMPTROLLER_ABI = [
234
224
  "inputs": [],
235
225
  "outputs": [{"name": "", "type": "uint256"}],
236
226
  },
237
- # Claim rewards for a user (called on comptroller in some versions)
238
227
  {
239
228
  "name": "claimReward",
240
229
  "type": "function",
@@ -244,9 +233,7 @@ COMPTROLLER_ABI = [
244
233
  },
245
234
  ]
246
235
 
247
- # Reward Distributor ABI - for claiming WELL rewards
248
236
  REWARD_DISTRIBUTOR_ABI = [
249
- # Claim rewards for all markets
250
237
  {
251
238
  "name": "claimReward",
252
239
  "type": "function",
@@ -254,7 +241,6 @@ REWARD_DISTRIBUTOR_ABI = [
254
241
  "inputs": [],
255
242
  "outputs": [],
256
243
  },
257
- # Claim rewards for specific holder and markets
258
244
  {
259
245
  "name": "claimReward",
260
246
  "type": "function",
@@ -350,7 +336,6 @@ REWARD_DISTRIBUTOR_ABI = [
350
336
  },
351
337
  ]
352
338
 
353
- # WETH ABI for wrapping/unwrapping ETH
354
339
  WETH_ABI = [
355
340
  {
356
341
  "name": "deposit",
@@ -0,0 +1,9 @@
1
+ TOKEN_ID_USDC_BASE = "usd-coin-base"
2
+ TOKEN_ID_WETH_BASE = "l2-standard-bridged-weth-base-base"
3
+ TOKEN_ID_WSTETH_BASE = "superbridge-bridged-wsteth-base-base"
4
+ TOKEN_ID_ETH_BASE = "ethereum-base"
5
+ TOKEN_ID_WELL_BASE = "moonwell-artemis-base"
6
+
7
+ TOKEN_ID_STETH = "staked-ether-ethereum"
8
+
9
+ TOKEN_ID_USDC_ARBITRUM = "usd-coin-arbitrum"
@@ -0,0 +1,66 @@
1
+ from typing import Any
2
+
3
+ import yaml
4
+ from pydantic import BaseModel, Field, validator
5
+
6
+
7
+ class AdapterRequirement(BaseModel):
8
+ name: str = Field(
9
+ ..., description="Adapter symbolic name (e.g., BALANCE, HYPERLIQUID)"
10
+ )
11
+ capabilities: list[str] = Field(default_factory=list)
12
+
13
+
14
+ class StrategyManifest(BaseModel):
15
+ schema_version: str = Field(default="0.1")
16
+ entrypoint: str = Field(
17
+ ...,
18
+ description="Python path to class, e.g. strategies.funding_rate_strategy.FundingRateStrategy",
19
+ )
20
+ name: str | None = Field(
21
+ default=None,
22
+ description="Unique name identifier for this strategy instance. Used to look up dedicated wallet in wallets.json by label.",
23
+ )
24
+ permissions: dict[str, Any] = Field(default_factory=dict)
25
+ adapters: list[AdapterRequirement] = Field(default_factory=list)
26
+
27
+ @validator("entrypoint")
28
+ def validate_entrypoint(cls, v: str) -> str:
29
+ if "." not in v:
30
+ raise ValueError(
31
+ "entrypoint must be a full import path to a Strategy class"
32
+ )
33
+ return v
34
+
35
+ @validator("permissions")
36
+ def validate_permissions(cls, v: dict) -> dict:
37
+ if "policy" not in v:
38
+ raise ValueError("permissions.policy is required")
39
+ if not v["policy"]:
40
+ raise ValueError("permissions.policy cannot be empty")
41
+ return v
42
+
43
+ @validator("adapters")
44
+ def validate_adapters(cls, v: list) -> list:
45
+ if not v:
46
+ raise ValueError("adapters cannot be empty")
47
+ return v
48
+
49
+
50
+ def load_strategy_manifest(path: str) -> StrategyManifest:
51
+ with open(path) as f:
52
+ data = yaml.safe_load(f)
53
+ return StrategyManifest(**data)
54
+
55
+
56
+ def load_manifest(path: str) -> StrategyManifest:
57
+ """Legacy function for backward compatibility."""
58
+ return load_strategy_manifest(path)
59
+
60
+
61
+ def validate_manifest(manifest: StrategyManifest) -> None:
62
+ # Simple v0.1 rules: require at least one adapter and permissions.policy
63
+ if not manifest.adapters:
64
+ raise ValueError("Manifest must declare at least one adapter")
65
+ if "policy" not in manifest.permissions:
66
+ raise ValueError("Manifest.permissions must include 'policy'")
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import traceback
4
3
  from abc import ABC, abstractmethod
5
4
  from collections.abc import Awaitable, Callable
6
5
  from typing import Any, TypedDict
@@ -56,7 +55,6 @@ class Strategy(ABC):
56
55
  strategy_wallet_signing_callback: Callable[[dict], Awaitable[str]]
57
56
  | None = None,
58
57
  ):
59
- self.adapters = {}
60
58
  self.ledger_adapter = None
61
59
  self.logger = logger.bind(strategy=self.__class__.__name__)
62
60
  self.config = config
@@ -66,12 +64,6 @@ class Strategy(ABC):
66
64
  async def setup(self) -> None:
67
65
  pass
68
66
 
69
- async def log(self, msg: str) -> None:
70
- self.logger.info(msg)
71
-
72
- async def quote(self) -> None:
73
- pass
74
-
75
67
  def _get_strategy_wallet_address(self) -> str:
76
68
  strategy_wallet = self.config.get("strategy_wallet")
77
69
  if not strategy_wallet or not isinstance(strategy_wallet, dict):
@@ -95,16 +87,6 @@ class Strategy(ABC):
95
87
  pass
96
88
 
97
89
  async def withdraw(self, **kwargs) -> StatusTuple:
98
- if hasattr(self, "ledger_adapter") and self.ledger_adapter:
99
- while self.ledger_adapter.positions.operations:
100
- node = self.ledger_adapter.positions.operations[-1]
101
- adapter = self.adapters.get(node.adapter)
102
- if adapter and hasattr(adapter, "unwind_op"):
103
- await adapter.unwind_op(node)
104
- self.ledger_adapter.positions.operations.pop()
105
-
106
- await self.ledger_adapter.save()
107
-
108
90
  return (True, "Withdrawal complete")
109
91
 
110
92
  @abstractmethod
@@ -132,59 +114,6 @@ class Strategy(ABC):
132
114
 
133
115
  return status
134
116
 
135
- def register_adapters(self, adapters: list[Any]) -> None:
136
- self.adapters = {}
137
- for adapter in adapters:
138
- if hasattr(adapter, "adapter_type"):
139
- self.adapters[adapter.adapter_type] = adapter
140
- elif hasattr(adapter, "__class__"):
141
- self.adapters[adapter.__class__.__name__] = adapter
142
-
143
- def unwind_on_error(
144
- self, func: Callable[..., Awaitable[StatusTuple]]
145
- ) -> Callable[..., Awaitable[StatusTuple]]:
146
- async def wrapper(*args: Any, **kwargs: Any) -> StatusTuple:
147
- try:
148
- return await func(*args, **kwargs)
149
- except Exception:
150
- trace = traceback.format_exc()
151
- try:
152
- await self.withdraw()
153
- return (
154
- False,
155
- f"Strategy failed during operation and was unwound. Failure: {trace}",
156
- )
157
- except Exception:
158
- trace2 = traceback.format_exc()
159
- return (
160
- False,
161
- f"Strategy failed and unwinding also failed. Operation error: {trace}. Unwind error: {trace2}",
162
- )
163
- finally:
164
- if hasattr(self, "ledger_adapter") and self.ledger_adapter:
165
- await self.ledger_adapter.save()
166
-
167
- return wrapper
168
-
169
- @classmethod
170
- def get_metadata(cls) -> dict[str, Any]:
171
- return {
172
- "name": getattr(cls, "name", None),
173
- "description": getattr(cls, "description", None),
174
- "summary": getattr(cls, "summary", None),
175
- }
176
-
177
- async def health_check(self) -> dict[str, Any]:
178
- health = {"status": "healthy", "strategy": self.name, "adapters": {}}
179
-
180
- for name, adapter in self.adapters.items():
181
- if hasattr(adapter, "health_check"):
182
- health["adapters"][name] = await adapter.health_check()
183
- else:
184
- health["adapters"][name] = {"status": "unknown"}
185
-
186
- return health
187
-
188
117
  async def partial_liquidate(
189
118
  self, usd_value: float
190
119
  ) -> tuple[bool, LiquidationResult]:
@@ -1,3 +1,12 @@
1
1
  from .base import StatusDict, StatusTuple, Strategy
2
+ from .opa_loop import OPAConfig, OPALoopMixin, Plan, PlanStep
2
3
 
3
- __all__ = ["Strategy", "StatusDict", "StatusTuple"]
4
+ __all__ = [
5
+ "Strategy",
6
+ "StatusDict",
7
+ "StatusTuple",
8
+ "OPALoopMixin",
9
+ "OPAConfig",
10
+ "Plan",
11
+ "PlanStep",
12
+ ]