wayfinder-paths 0.1.23__py3-none-any.whl → 0.1.25__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.
- wayfinder_paths/__init__.py +2 -0
- wayfinder_paths/adapters/balance_adapter/adapter.py +250 -0
- wayfinder_paths/adapters/balance_adapter/manifest.yaml +8 -0
- wayfinder_paths/adapters/balance_adapter/test_adapter.py +0 -11
- wayfinder_paths/adapters/boros_adapter/__init__.py +17 -0
- wayfinder_paths/adapters/boros_adapter/adapter.py +1574 -0
- wayfinder_paths/adapters/boros_adapter/client.py +476 -0
- wayfinder_paths/adapters/boros_adapter/manifest.yaml +10 -0
- wayfinder_paths/adapters/boros_adapter/parsers.py +88 -0
- wayfinder_paths/adapters/boros_adapter/test_adapter.py +460 -0
- wayfinder_paths/adapters/boros_adapter/test_golden.py +156 -0
- wayfinder_paths/adapters/boros_adapter/types.py +70 -0
- wayfinder_paths/adapters/boros_adapter/utils.py +85 -0
- wayfinder_paths/adapters/brap_adapter/adapter.py +1 -1
- wayfinder_paths/adapters/brap_adapter/manifest.yaml +9 -0
- wayfinder_paths/adapters/hyperlend_adapter/adapter.py +161 -26
- wayfinder_paths/adapters/hyperlend_adapter/manifest.yaml +9 -0
- wayfinder_paths/adapters/hyperlend_adapter/test_adapter.py +77 -13
- wayfinder_paths/adapters/hyperliquid_adapter/__init__.py +2 -9
- wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +585 -61
- wayfinder_paths/adapters/hyperliquid_adapter/executor.py +47 -68
- wayfinder_paths/adapters/hyperliquid_adapter/manifest.yaml +14 -0
- wayfinder_paths/adapters/hyperliquid_adapter/paired_filler.py +2 -3
- wayfinder_paths/adapters/hyperliquid_adapter/test_adapter.py +17 -21
- wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +3 -6
- wayfinder_paths/adapters/hyperliquid_adapter/test_executor.py +4 -8
- wayfinder_paths/adapters/hyperliquid_adapter/test_utils.py +2 -2
- wayfinder_paths/adapters/ledger_adapter/manifest.yaml +7 -0
- wayfinder_paths/adapters/ledger_adapter/test_adapter.py +1 -2
- wayfinder_paths/adapters/moonwell_adapter/adapter.py +592 -400
- wayfinder_paths/adapters/moonwell_adapter/manifest.yaml +14 -0
- wayfinder_paths/adapters/moonwell_adapter/test_adapter.py +126 -219
- wayfinder_paths/adapters/multicall_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/multicall_adapter/adapter.py +166 -0
- wayfinder_paths/adapters/multicall_adapter/manifest.yaml +5 -0
- wayfinder_paths/adapters/multicall_adapter/test_adapter.py +97 -0
- wayfinder_paths/adapters/pendle_adapter/README.md +102 -0
- wayfinder_paths/adapters/pendle_adapter/__init__.py +7 -0
- wayfinder_paths/adapters/pendle_adapter/adapter.py +1992 -0
- wayfinder_paths/adapters/pendle_adapter/examples.json +11 -0
- wayfinder_paths/adapters/pendle_adapter/manifest.yaml +21 -0
- wayfinder_paths/adapters/pendle_adapter/test_adapter.py +666 -0
- wayfinder_paths/adapters/pool_adapter/manifest.yaml +6 -0
- wayfinder_paths/adapters/token_adapter/examples.json +0 -4
- wayfinder_paths/adapters/token_adapter/manifest.yaml +7 -0
- wayfinder_paths/conftest.py +24 -17
- wayfinder_paths/core/__init__.py +2 -0
- wayfinder_paths/core/adapters/BaseAdapter.py +0 -25
- wayfinder_paths/core/adapters/models.py +17 -7
- wayfinder_paths/core/clients/BRAPClient.py +1 -1
- wayfinder_paths/core/clients/TokenClient.py +47 -1
- wayfinder_paths/core/clients/WayfinderClient.py +1 -2
- wayfinder_paths/core/clients/protocols.py +21 -22
- wayfinder_paths/core/clients/test_ledger_client.py +448 -0
- wayfinder_paths/core/config.py +12 -0
- wayfinder_paths/core/constants/__init__.py +15 -0
- wayfinder_paths/core/constants/base.py +6 -1
- wayfinder_paths/core/constants/contracts.py +39 -26
- wayfinder_paths/core/constants/erc20_abi.py +0 -1
- wayfinder_paths/core/constants/hyperlend_abi.py +0 -4
- wayfinder_paths/core/constants/hyperliquid.py +16 -0
- wayfinder_paths/core/constants/moonwell_abi.py +0 -15
- wayfinder_paths/core/engine/manifest.py +66 -0
- wayfinder_paths/core/strategies/Strategy.py +0 -61
- wayfinder_paths/core/strategies/__init__.py +10 -1
- wayfinder_paths/core/strategies/opa_loop.py +167 -0
- wayfinder_paths/core/utils/test_transaction.py +289 -0
- wayfinder_paths/core/utils/transaction.py +44 -1
- wayfinder_paths/core/utils/web3.py +3 -0
- wayfinder_paths/mcp/__init__.py +5 -0
- wayfinder_paths/mcp/preview.py +185 -0
- wayfinder_paths/mcp/scripting.py +84 -0
- wayfinder_paths/mcp/server.py +52 -0
- wayfinder_paths/mcp/state/profile_store.py +195 -0
- wayfinder_paths/mcp/state/store.py +89 -0
- wayfinder_paths/mcp/test_scripting.py +267 -0
- wayfinder_paths/mcp/tools/__init__.py +0 -0
- wayfinder_paths/mcp/tools/balances.py +290 -0
- wayfinder_paths/mcp/tools/discovery.py +158 -0
- wayfinder_paths/mcp/tools/execute.py +770 -0
- wayfinder_paths/mcp/tools/hyperliquid.py +931 -0
- wayfinder_paths/mcp/tools/quotes.py +288 -0
- wayfinder_paths/mcp/tools/run_script.py +286 -0
- wayfinder_paths/mcp/tools/strategies.py +188 -0
- wayfinder_paths/mcp/tools/tokens.py +46 -0
- wayfinder_paths/mcp/tools/wallets.py +354 -0
- wayfinder_paths/mcp/utils.py +129 -0
- wayfinder_paths/policies/hyperliquid.py +1 -1
- wayfinder_paths/policies/lifi.py +18 -0
- wayfinder_paths/policies/util.py +8 -2
- wayfinder_paths/strategies/basis_trading_strategy/strategy.py +28 -119
- wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +24 -53
- wayfinder_paths/strategies/boros_hype_strategy/__init__.py +3 -0
- wayfinder_paths/strategies/boros_hype_strategy/boros_ops_mixin.py +450 -0
- wayfinder_paths/strategies/boros_hype_strategy/constants.py +255 -0
- wayfinder_paths/strategies/boros_hype_strategy/examples.json +37 -0
- wayfinder_paths/strategies/boros_hype_strategy/hyperevm_ops_mixin.py +114 -0
- wayfinder_paths/strategies/boros_hype_strategy/hyperliquid_ops_mixin.py +642 -0
- wayfinder_paths/strategies/boros_hype_strategy/manifest.yaml +36 -0
- wayfinder_paths/strategies/boros_hype_strategy/planner.py +460 -0
- wayfinder_paths/strategies/boros_hype_strategy/risk_ops_mixin.py +886 -0
- wayfinder_paths/strategies/boros_hype_strategy/snapshot_mixin.py +494 -0
- wayfinder_paths/strategies/boros_hype_strategy/strategy.py +1194 -0
- wayfinder_paths/strategies/boros_hype_strategy/test_planner_golden.py +374 -0
- wayfinder_paths/strategies/boros_hype_strategy/test_strategy.py +202 -0
- wayfinder_paths/strategies/boros_hype_strategy/types.py +365 -0
- wayfinder_paths/strategies/boros_hype_strategy/withdraw_mixin.py +997 -0
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +3 -12
- wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +7 -29
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/strategy.py +63 -40
- wayfinder_paths/strategies/moonwell_wsteth_loop_strategy/test_strategy.py +5 -15
- wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +0 -34
- wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +11 -34
- wayfinder_paths/tests/test_mcp_quote_swap.py +165 -0
- wayfinder_paths/tests/test_test_coverage.py +1 -4
- wayfinder_paths-0.1.25.dist-info/METADATA +377 -0
- wayfinder_paths-0.1.25.dist-info/RECORD +185 -0
- wayfinder_paths/scripts/create_strategy.py +0 -139
- wayfinder_paths/scripts/make_wallets.py +0 -142
- wayfinder_paths-0.1.23.dist-info/METADATA +0 -354
- wayfinder_paths-0.1.23.dist-info/RECORD +0 -120
- /wayfinder_paths/{scripts → mcp/state}/__init__.py +0 -0
- {wayfinder_paths-0.1.23.dist-info → wayfinder_paths-0.1.25.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.23.dist-info → wayfinder_paths-0.1.25.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from enum import Enum, auto
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .constants import (
|
|
9
|
+
ALLOCATION_DEVIATION_THRESHOLD,
|
|
10
|
+
BOROS_ENABLE_MIN_TOTAL_USD,
|
|
11
|
+
FULL_REBALANCE_THRESHOLD,
|
|
12
|
+
PARTIAL_TRIM_THRESHOLD,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
# CONFIGURATION
|
|
17
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class HedgeConfig:
|
|
22
|
+
spot_pct: float # Total allocation to spot (kHYPE + looped HYPE)
|
|
23
|
+
khype_fraction: float # Fraction of spot allocation for kHYPE
|
|
24
|
+
looped_hype_fraction: float # Fraction of spot allocation for looped HYPE
|
|
25
|
+
hyperliquid_pct: float # Allocation to Hyperliquid perp margin
|
|
26
|
+
boros_pct: float # Allocation to Boros rate lock
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def default(cls) -> HedgeConfig:
|
|
30
|
+
return cls(
|
|
31
|
+
# New routing:
|
|
32
|
+
# - Send 100% of Arbitrum USDC to Hyperliquid first.
|
|
33
|
+
# - Target ~50% of portfolio value staying on Hyperliquid (margin + cash buffer).
|
|
34
|
+
# - Target ~50% HYPE exposure split between HyperEVM spot (≈47.5%) and Boros HYPE collateral (≈2.5%).
|
|
35
|
+
spot_pct=0.475,
|
|
36
|
+
khype_fraction=0.5,
|
|
37
|
+
looped_hype_fraction=0.5,
|
|
38
|
+
hyperliquid_pct=0.50,
|
|
39
|
+
boros_pct=0.025,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
44
|
+
# INVENTORY (World Model)
|
|
45
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class Inventory:
|
|
50
|
+
# HyperEVM wallet balances
|
|
51
|
+
hype_hyperevm_balance: float
|
|
52
|
+
hype_hyperevm_value_usd: float
|
|
53
|
+
whype_balance: float # Wrapped HYPE balance on HyperEVM
|
|
54
|
+
whype_value_usd: float # Value in USD (1:1 with HYPE)
|
|
55
|
+
khype_balance: float
|
|
56
|
+
khype_value_usd: float
|
|
57
|
+
looped_hype_balance: float
|
|
58
|
+
looped_hype_value_usd: float
|
|
59
|
+
|
|
60
|
+
# Arbitrum wallet balances
|
|
61
|
+
usdc_arb_idle: float
|
|
62
|
+
usdt_arb_idle: float
|
|
63
|
+
eth_arb_balance: float # For gas
|
|
64
|
+
|
|
65
|
+
# Arbitrum OFT HYPE (bridged from HyperEVM)
|
|
66
|
+
hype_oft_arb_balance: float
|
|
67
|
+
hype_oft_arb_value_usd: float
|
|
68
|
+
|
|
69
|
+
# Hyperliquid venue
|
|
70
|
+
hl_perp_margin: float
|
|
71
|
+
hl_spot_usdc: float
|
|
72
|
+
hl_spot_hype: float
|
|
73
|
+
hl_spot_hype_value_usd: float
|
|
74
|
+
hl_short_size_hype: float
|
|
75
|
+
hl_short_value_usd: float
|
|
76
|
+
hl_unrealized_pnl: float
|
|
77
|
+
hl_withdrawable_usd: float
|
|
78
|
+
|
|
79
|
+
# Boros venue
|
|
80
|
+
boros_idle_collateral_isolated: float # HYPE units
|
|
81
|
+
boros_idle_collateral_cross: float # HYPE units
|
|
82
|
+
boros_collateral_hype: float # Total HYPE collateral in Boros
|
|
83
|
+
boros_collateral_usd: float # USD value (HYPE * hype_price_usd)
|
|
84
|
+
boros_pending_withdrawal_hype: float # HYPE units
|
|
85
|
+
boros_pending_withdrawal_usd: float # USD value
|
|
86
|
+
boros_committed_collateral_usd: float # boros_collateral_usd + hype_oft_arb_value_usd (+ any in-flight OFT bridge)
|
|
87
|
+
boros_position_size: float # YU notional
|
|
88
|
+
boros_position_value: float # Unrealized PnL
|
|
89
|
+
|
|
90
|
+
# Exchange rates
|
|
91
|
+
khype_to_hype_ratio: float
|
|
92
|
+
looped_hype_to_hype_ratio: float
|
|
93
|
+
hype_price_usd: float
|
|
94
|
+
|
|
95
|
+
# Aggregates
|
|
96
|
+
spot_value_usd: float
|
|
97
|
+
total_hype_exposure: float
|
|
98
|
+
total_value: float
|
|
99
|
+
|
|
100
|
+
# Optional
|
|
101
|
+
boros_position_market_ids: list[int] | None = None
|
|
102
|
+
|
|
103
|
+
# Liquidation detection
|
|
104
|
+
hl_liquidation_detected: bool = False
|
|
105
|
+
hl_liquidation_fills: list[dict] = field(default_factory=list)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class AllocationStatus:
|
|
110
|
+
# Actual values
|
|
111
|
+
spot_value: float
|
|
112
|
+
hl_value: float
|
|
113
|
+
boros_value: float
|
|
114
|
+
idle_value: float
|
|
115
|
+
total_value: float
|
|
116
|
+
|
|
117
|
+
# Actual percentages
|
|
118
|
+
spot_pct_actual: float
|
|
119
|
+
hl_pct_actual: float
|
|
120
|
+
boros_pct_actual: float
|
|
121
|
+
|
|
122
|
+
# Deviations from target (negative = underallocated)
|
|
123
|
+
spot_deviation: float
|
|
124
|
+
hl_deviation: float
|
|
125
|
+
boros_deviation: float
|
|
126
|
+
|
|
127
|
+
# Dollar amounts needed to reach target
|
|
128
|
+
spot_needed_usd: float
|
|
129
|
+
hl_needed_usd: float
|
|
130
|
+
boros_needed_usd: float
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@dataclass
|
|
134
|
+
class YieldInfo:
|
|
135
|
+
khype_apy: float | None = None
|
|
136
|
+
lhype_apy: float | None = None
|
|
137
|
+
boros_apr: float | None = None
|
|
138
|
+
hl_funding_rate: float | None = None
|
|
139
|
+
|
|
140
|
+
khype_expected_yield_usd: float = 0.0
|
|
141
|
+
lhype_expected_yield_usd: float = 0.0
|
|
142
|
+
boros_expected_yield_usd: float = 0.0
|
|
143
|
+
hl_expected_yield_usd: float = 0.0
|
|
144
|
+
|
|
145
|
+
total_expected_yield_usd: float = 0.0
|
|
146
|
+
blended_apy: float | None = None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
150
|
+
# PLANNING ENUMS
|
|
151
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class Mode(Enum):
|
|
155
|
+
NORMAL = auto() # Regular operations
|
|
156
|
+
TRIM = auto() # Risk at 75%+: reduce exposure
|
|
157
|
+
REDEPLOY = auto() # Risk at 90%+: emergency redeploy
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class PlanOp(Enum):
|
|
161
|
+
# Priority 0: Safety/Risk mitigation
|
|
162
|
+
CLOSE_AND_REDEPLOY = "close_and_redeploy"
|
|
163
|
+
PARTIAL_TRIM_SPOT = "partial_trim_spot"
|
|
164
|
+
COMPLETE_PENDING_WITHDRAWAL = "complete_pending_withdrawal"
|
|
165
|
+
|
|
166
|
+
# Priority 5: Gas routing (must happen first!)
|
|
167
|
+
ENSURE_GAS_ON_HYPEREVM = "ensure_gas_on_hyperevm"
|
|
168
|
+
ENSURE_GAS_ON_ARBITRUM = "ensure_gas_on_arbitrum"
|
|
169
|
+
|
|
170
|
+
# Priority 10: Capital routing
|
|
171
|
+
FUND_BOROS = "fund_boros"
|
|
172
|
+
SEND_USDC_TO_HL = "send_usdc_to_hl"
|
|
173
|
+
BRIDGE_TO_HYPEREVM = "bridge_to_hyperevm"
|
|
174
|
+
TRANSFER_HL_SPOT_TO_HYPEREVM = "transfer_hl_spot_to_hyperevm"
|
|
175
|
+
DEPLOY_EXCESS_HL_MARGIN = "deploy_excess_hl_margin"
|
|
176
|
+
|
|
177
|
+
# Priority 20: Position management
|
|
178
|
+
SWAP_HYPE_TO_LST = "swap_hype_to_lst"
|
|
179
|
+
ENSURE_HL_SHORT = "ensure_hl_short"
|
|
180
|
+
|
|
181
|
+
# Priority 30: Rate positions
|
|
182
|
+
ENSURE_BOROS_POSITION = "ensure_boros_position"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
186
|
+
# PLANNING DATACLASSES
|
|
187
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@dataclass
|
|
191
|
+
class PlanStep:
|
|
192
|
+
op: PlanOp
|
|
193
|
+
priority: int # Lower = execute first
|
|
194
|
+
key: str # Unique identifier for deduplication
|
|
195
|
+
params: dict[str, Any] = field(default_factory=dict)
|
|
196
|
+
reason: str = ""
|
|
197
|
+
|
|
198
|
+
def __lt__(self, other: PlanStep) -> bool:
|
|
199
|
+
return self.priority < other.priority
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass
|
|
203
|
+
class PlannerConfig:
|
|
204
|
+
# Risk thresholds
|
|
205
|
+
partial_trim_threshold: float = PARTIAL_TRIM_THRESHOLD
|
|
206
|
+
full_rebalance_threshold: float = FULL_REBALANCE_THRESHOLD
|
|
207
|
+
|
|
208
|
+
# Allocation thresholds
|
|
209
|
+
allocation_deviation_threshold: float = ALLOCATION_DEVIATION_THRESHOLD
|
|
210
|
+
position_size_tolerance: float = 0.05
|
|
211
|
+
|
|
212
|
+
# Minimum amounts to act on
|
|
213
|
+
min_usdc_action: float = 5.0
|
|
214
|
+
min_usdt_action: float = 1.0
|
|
215
|
+
min_hype_swap: float = 0.1
|
|
216
|
+
|
|
217
|
+
# Boros guard
|
|
218
|
+
min_total_for_boros: float = BOROS_ENABLE_MIN_TOTAL_USD
|
|
219
|
+
|
|
220
|
+
# Hyperliquid guardrails
|
|
221
|
+
hl_withdrawable_buffer_usd: float = 5.0
|
|
222
|
+
hl_withdraw_for_boros_cooldown_minutes: int = 30
|
|
223
|
+
hl_max_withdraw_for_boros_usd: float = 25.0
|
|
224
|
+
|
|
225
|
+
# HL margin management
|
|
226
|
+
hl_target_margin_ratio: float = 0.50
|
|
227
|
+
hl_margin_buffer_ratio: float = 0.15
|
|
228
|
+
|
|
229
|
+
# Boros hysteresis
|
|
230
|
+
boros_market_switch_cooldown_hours: int = 24
|
|
231
|
+
boros_apr_improvement_threshold: float = 0.02
|
|
232
|
+
|
|
233
|
+
# Boros coverage - target 100%, resize threshold is the hysteresis band
|
|
234
|
+
boros_coverage_target: float = 1.0
|
|
235
|
+
boros_resize_min_excess_usd: float = (
|
|
236
|
+
10.0 # Min YU diff to trigger resize (hysteresis)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Delta neutral tolerances
|
|
240
|
+
delta_neutral_rel_tol: float = 0.02
|
|
241
|
+
delta_neutral_abs_tol_hype: float = 0.11
|
|
242
|
+
|
|
243
|
+
# Execution limits
|
|
244
|
+
max_steps_per_iteration: int = 5
|
|
245
|
+
max_iterations_per_tick: int = 4
|
|
246
|
+
max_total_steps_per_tick: int = 15
|
|
247
|
+
|
|
248
|
+
@classmethod
|
|
249
|
+
def default(cls) -> PlannerConfig:
|
|
250
|
+
return cls()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@dataclass
|
|
254
|
+
class PlannerRuntime:
|
|
255
|
+
# Boros market selection (persistent state for hysteresis)
|
|
256
|
+
current_boros_market_id: int | None = None
|
|
257
|
+
current_boros_token_id: int | None = None
|
|
258
|
+
current_boros_collateral_address: str | None = None
|
|
259
|
+
boros_market_selected_at: datetime | None = None
|
|
260
|
+
|
|
261
|
+
# Execution tracking
|
|
262
|
+
last_update_at: datetime | None = None
|
|
263
|
+
steps_executed_this_session: int = 0
|
|
264
|
+
|
|
265
|
+
# Virtual ledger for same-tick tracking
|
|
266
|
+
committed_usdc_arb: float = 0.0
|
|
267
|
+
committed_usdt_arb: float = 0.0
|
|
268
|
+
funded_boros_this_tick: bool = False
|
|
269
|
+
|
|
270
|
+
last_hl_withdraw_for_boros_at: datetime | None = None
|
|
271
|
+
|
|
272
|
+
# OFT bridge tracking (HyperEVM native HYPE -> Arbitrum OFT HYPE) so we don't
|
|
273
|
+
# repeatedly fund Boros while the bridge is still settling.
|
|
274
|
+
in_flight_boros_oft_hype: float = 0.0
|
|
275
|
+
in_flight_boros_oft_hype_balance_before: float = 0.0
|
|
276
|
+
in_flight_boros_oft_hype_started_at: datetime | None = None
|
|
277
|
+
|
|
278
|
+
# HL state
|
|
279
|
+
leverage_set_for_hype: bool = False
|
|
280
|
+
builder_fee_approved: bool = False
|
|
281
|
+
|
|
282
|
+
def reset_virtual_ledger(self) -> None:
|
|
283
|
+
self.committed_usdc_arb = 0.0
|
|
284
|
+
self.committed_usdt_arb = 0.0
|
|
285
|
+
|
|
286
|
+
def reset_tick_flags(self) -> None:
|
|
287
|
+
self.funded_boros_this_tick = False
|
|
288
|
+
|
|
289
|
+
def available_usdc_arb(self, inv_usdc: float) -> float:
|
|
290
|
+
return max(0.0, inv_usdc - self.committed_usdc_arb)
|
|
291
|
+
|
|
292
|
+
def available_usdt_arb(self, inv_usdt: float) -> float:
|
|
293
|
+
return max(0.0, inv_usdt - self.committed_usdt_arb)
|
|
294
|
+
|
|
295
|
+
def commit_usdc(self, amount: float) -> None:
|
|
296
|
+
self.committed_usdc_arb += amount
|
|
297
|
+
|
|
298
|
+
def commit_usdt(self, amount: float) -> None:
|
|
299
|
+
self.committed_usdt_arb += amount
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
@dataclass
|
|
303
|
+
class DesiredState:
|
|
304
|
+
mode: Mode
|
|
305
|
+
|
|
306
|
+
# Target allocations (USD)
|
|
307
|
+
target_spot_usd: float
|
|
308
|
+
target_hl_margin_usd: float
|
|
309
|
+
target_boros_collateral_usd: float
|
|
310
|
+
|
|
311
|
+
# Target positions
|
|
312
|
+
target_hype_short_size: float
|
|
313
|
+
target_boros_position_usd: float
|
|
314
|
+
|
|
315
|
+
# Selected Boros market
|
|
316
|
+
boros_market_id: int | None = None
|
|
317
|
+
boros_market_symbol: str | None = None
|
|
318
|
+
boros_tenor_days: float | None = None
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@dataclass
|
|
322
|
+
class Plan:
|
|
323
|
+
desired_state: DesiredState
|
|
324
|
+
steps: list[PlanStep] = field(default_factory=list)
|
|
325
|
+
messages: list[str] = field(default_factory=list)
|
|
326
|
+
|
|
327
|
+
def add_step(
|
|
328
|
+
self,
|
|
329
|
+
op: PlanOp,
|
|
330
|
+
priority: int,
|
|
331
|
+
key: str,
|
|
332
|
+
params: dict[str, Any] | None = None,
|
|
333
|
+
reason: str = "",
|
|
334
|
+
) -> None:
|
|
335
|
+
if not any(s.key == key for s in self.steps):
|
|
336
|
+
self.steps.append(
|
|
337
|
+
PlanStep(
|
|
338
|
+
op=op,
|
|
339
|
+
priority=priority,
|
|
340
|
+
key=key,
|
|
341
|
+
params=params or {},
|
|
342
|
+
reason=reason,
|
|
343
|
+
)
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
def sort_steps(self) -> None:
|
|
347
|
+
self.steps.sort()
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# Operations that change inventory and require re-observing
|
|
351
|
+
# Note: ENSURE_GAS_ON_HYPEREVM is excluded because it may return early
|
|
352
|
+
# without actually changing anything (e.g., "will be provisioned during routing")
|
|
353
|
+
INVENTORY_CHANGING_OPS: set[PlanOp] = {
|
|
354
|
+
PlanOp.CLOSE_AND_REDEPLOY,
|
|
355
|
+
PlanOp.PARTIAL_TRIM_SPOT,
|
|
356
|
+
PlanOp.COMPLETE_PENDING_WITHDRAWAL,
|
|
357
|
+
PlanOp.FUND_BOROS,
|
|
358
|
+
PlanOp.SEND_USDC_TO_HL,
|
|
359
|
+
PlanOp.BRIDGE_TO_HYPEREVM,
|
|
360
|
+
PlanOp.TRANSFER_HL_SPOT_TO_HYPEREVM,
|
|
361
|
+
PlanOp.DEPLOY_EXCESS_HL_MARGIN,
|
|
362
|
+
PlanOp.SWAP_HYPE_TO_LST,
|
|
363
|
+
PlanOp.ENSURE_HL_SHORT,
|
|
364
|
+
PlanOp.ENSURE_BOROS_POSITION,
|
|
365
|
+
}
|