wayfinder-paths 0.1.2__py3-none-any.whl → 0.1.3__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/abis/generic/erc20.json +383 -0
- wayfinder_paths/core/strategies/Strategy.py +3 -3
- wayfinder_paths/core/strategies/descriptors.py +80 -0
- wayfinder_paths/core/utils/evm_helpers.py +39 -0
- wayfinder_paths/vaults/policies/enso.py +17 -0
- wayfinder_paths/vaults/policies/erc20.py +34 -0
- wayfinder_paths/vaults/policies/evm.py +21 -0
- wayfinder_paths/vaults/policies/hyper_evm.py +19 -0
- wayfinder_paths/vaults/policies/hyperlend.py +12 -0
- wayfinder_paths/vaults/policies/hyperliquid.py +30 -0
- wayfinder_paths/vaults/policies/moonwell.py +54 -0
- wayfinder_paths/vaults/policies/prjx.py +30 -0
- wayfinder_paths/vaults/policies/util.py +27 -0
- wayfinder_paths/vaults/strategies/hyperlend_stable_yield_strategy/strategy.py +138 -76
- wayfinder_paths/vaults/strategies/stablecoin_yield_strategy/strategy.py +112 -75
- {wayfinder_paths-0.1.2.dist-info → wayfinder_paths-0.1.3.dist-info}/METADATA +1 -1
- {wayfinder_paths-0.1.2.dist-info → wayfinder_paths-0.1.3.dist-info}/RECORD +19 -8
- {wayfinder_paths-0.1.2.dist-info → wayfinder_paths-0.1.3.dist-info}/LICENSE +0 -0
- {wayfinder_paths-0.1.2.dist-info → wayfinder_paths-0.1.3.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from wayfinder_paths.vaults.policies.util import allow_functions
|
|
2
|
+
|
|
3
|
+
WETH = "0x4200000000000000000000000000000000000006"
|
|
4
|
+
|
|
5
|
+
M_USDC = "0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22"
|
|
6
|
+
M_WETH = "0x628ff693426583D9a7FB391E54366292F509D457"
|
|
7
|
+
M_WSTETH = "0x627Fe393Bc6EdDA28e99AE648fD6fF362514304b"
|
|
8
|
+
|
|
9
|
+
COMPTROLLER = "0xfbb21d0380bee3312b33c4353c8936a0f13ef26c"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def weth_deposit():
|
|
13
|
+
return await allow_functions(
|
|
14
|
+
policy_name="Allow WETH Deposit",
|
|
15
|
+
abi_chain_id=8453,
|
|
16
|
+
address=WETH,
|
|
17
|
+
function_names=["deposit"],
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def musdc_mint_or_approve_or_redeem():
|
|
22
|
+
return await allow_functions(
|
|
23
|
+
policy_name="Allow MUSDC Mint or Approve or Redeem",
|
|
24
|
+
abi_chain_id=8453,
|
|
25
|
+
address=M_USDC,
|
|
26
|
+
function_names=["mint", "approve", "redeem"],
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def mweth_approve_or_borrow_or_repay():
|
|
31
|
+
return await allow_functions(
|
|
32
|
+
policy_name="Allow MWETH Approve or Borrow or Repay",
|
|
33
|
+
abi_chain_id=8453,
|
|
34
|
+
address=M_WETH,
|
|
35
|
+
function_names=["approve", "borrow", "repayBorrow"],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def mwsteth_approve_or_mint_or_redeem():
|
|
40
|
+
return await allow_functions(
|
|
41
|
+
policy_name="Allow MWSTETH Approve or Mint or Redeem",
|
|
42
|
+
abi_chain_id=8453,
|
|
43
|
+
address=M_WSTETH,
|
|
44
|
+
function_names=["approve", "mint", "redeem"],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def moonwell_comptroller_enter_markets_or_claim_rewards():
|
|
49
|
+
return await allow_functions(
|
|
50
|
+
policy_name="Allow Moonwell Comptroller Enter Markets or Claim Rewards",
|
|
51
|
+
abi_chain_id=8453,
|
|
52
|
+
address=COMPTROLLER,
|
|
53
|
+
function_names=["enterMarkets", "claimReward"],
|
|
54
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from wayfinder_paths.vaults.policies.util import allow_functions
|
|
2
|
+
|
|
3
|
+
PRJX_ROUTER = "0x1ebdfc75ffe3ba3de61e7138a3e8706ac841af9b"
|
|
4
|
+
PRJX_NPM = "0xeAd19AE861c29bBb2101E834922B2FEee69B9091"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def prjx_swap():
|
|
8
|
+
return await allow_functions(
|
|
9
|
+
policy_name="Allow PRJX Swap",
|
|
10
|
+
abi_chain_id=999,
|
|
11
|
+
address=PRJX_ROUTER,
|
|
12
|
+
function_names=[
|
|
13
|
+
"exactInput",
|
|
14
|
+
"exactInputSingle",
|
|
15
|
+
"exactOutput",
|
|
16
|
+
"exactOutputSingle",
|
|
17
|
+
],
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def prjx_npm():
|
|
22
|
+
return await allow_functions(
|
|
23
|
+
policy_name="Allow PRJX NPM",
|
|
24
|
+
abi_chain_id=999,
|
|
25
|
+
address=PRJX_NPM,
|
|
26
|
+
function_names=[
|
|
27
|
+
"increaseLiquidity",
|
|
28
|
+
"decreaseLiquidity",
|
|
29
|
+
],
|
|
30
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from wayfinder_paths.core.utils.evm_helpers import get_abi_filtered
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
async def allow_functions(
|
|
5
|
+
policy_name: str, abi_chain_id: int, address: str, function_names: list[str]
|
|
6
|
+
):
|
|
7
|
+
# Note: ChainID is just for fetching ABI, doesn't appear in the final policy. Doesn't bind a strict chain.
|
|
8
|
+
return {
|
|
9
|
+
"name": policy_name,
|
|
10
|
+
"method": "eth_signTransaction",
|
|
11
|
+
"action": "ALLOW",
|
|
12
|
+
"conditions": [
|
|
13
|
+
{
|
|
14
|
+
"field_source": "ethereum_transaction",
|
|
15
|
+
"field": "to",
|
|
16
|
+
"operator": "eq",
|
|
17
|
+
"value": address,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"field_source": "ethereum_calldata",
|
|
21
|
+
"field": "function_name",
|
|
22
|
+
"abi": await get_abi_filtered(abi_chain_id, address, function_names),
|
|
23
|
+
"operator": "in",
|
|
24
|
+
"value": function_names,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}
|
|
@@ -17,6 +17,14 @@ from wayfinder_paths.core.services.local_token_txn import (
|
|
|
17
17
|
LocalTokenTxnService,
|
|
18
18
|
)
|
|
19
19
|
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
20
|
+
from wayfinder_paths.core.strategies.descriptors import (
|
|
21
|
+
Complexity,
|
|
22
|
+
Directionality,
|
|
23
|
+
Frequency,
|
|
24
|
+
StratDescriptor,
|
|
25
|
+
TokenExposure,
|
|
26
|
+
Volatility,
|
|
27
|
+
)
|
|
20
28
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
21
29
|
from wayfinder_paths.core.wallets.WalletManager import WalletManager
|
|
22
30
|
from wayfinder_paths.vaults.adapters.balance_adapter.adapter import BalanceAdapter
|
|
@@ -24,6 +32,21 @@ from wayfinder_paths.vaults.adapters.brap_adapter.adapter import BRAPAdapter
|
|
|
24
32
|
from wayfinder_paths.vaults.adapters.hyperlend_adapter.adapter import HyperlendAdapter
|
|
25
33
|
from wayfinder_paths.vaults.adapters.ledger_adapter.adapter import LedgerAdapter
|
|
26
34
|
from wayfinder_paths.vaults.adapters.token_adapter.adapter import TokenAdapter
|
|
35
|
+
from wayfinder_paths.vaults.policies.enso import ENSO_ROUTER, enso_swap
|
|
36
|
+
from wayfinder_paths.vaults.policies.erc20 import erc20_spender_for_any_token
|
|
37
|
+
from wayfinder_paths.vaults.policies.hyper_evm import (
|
|
38
|
+
hypecore_sentinel_deposit,
|
|
39
|
+
whype_deposit_and_withdraw,
|
|
40
|
+
)
|
|
41
|
+
from wayfinder_paths.vaults.policies.hyperlend import (
|
|
42
|
+
HYPERLEND_POOL,
|
|
43
|
+
hyperlend_supply_and_withdraw,
|
|
44
|
+
)
|
|
45
|
+
from wayfinder_paths.vaults.policies.hyperliquid import (
|
|
46
|
+
any_hyperliquid_l1_payload,
|
|
47
|
+
any_hyperliquid_user_payload,
|
|
48
|
+
)
|
|
49
|
+
from wayfinder_paths.vaults.policies.prjx import PRJX_ROUTER, prjx_swap
|
|
27
50
|
|
|
28
51
|
SYMBOL_TRANSLATION_TABLE = str.maketrans(
|
|
29
52
|
{
|
|
@@ -36,7 +59,7 @@ WRAPPED_HYPE_ADDRESS = "0x5555555555555555555555555555555555555555"
|
|
|
36
59
|
|
|
37
60
|
|
|
38
61
|
class HyperlendStableYieldStrategy(Strategy):
|
|
39
|
-
name = "
|
|
62
|
+
name = "HyperLend Stable Optimizer"
|
|
40
63
|
|
|
41
64
|
# Strategy parameters
|
|
42
65
|
APY_SHORT_CIRCUIT_THRESHOLD = None
|
|
@@ -61,82 +84,110 @@ class HyperlendStableYieldStrategy(Strategy):
|
|
|
61
84
|
P_BEST_ROTATION_THRESHOLD = 0.4
|
|
62
85
|
MAX_CANDIDATES = 5
|
|
63
86
|
MIN_STABLE_SWAP_TOKENS = 1e-3
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
MAX_GAS = 0.1 # hype float
|
|
88
|
+
|
|
89
|
+
INFO = StratDescriptor(
|
|
90
|
+
description=f"""Multi-strategy allocator that converts USDT0 into the most consistently rewarding HyperLend stablecoin and continuously checks if a rotation is justified.
|
|
91
|
+
**What it does:** Pulls USDT0 from the main wallet, ensures a small HYPE safety buffer for gas, swaps the remaining stable balance into candidate markets, and supplies
|
|
92
|
+
liquidity to HyperLend. Hourly rate histories are aggregated into a 7-day panel and routed through a block-bootstrap tournament (horizon {HORIZON_HOURS}h, block length {BLOCK_LEN}, {TRIALS:,}
|
|
93
|
+
trials, {HALFLIFE_DAYS}-day half-life weighting) to estimate which asset has the highest probability of outperforming peers. USDT0 is the LayerZero bridgable stablecoin for USDT.
|
|
94
|
+
**Exposure type:** Market-neutral stablecoin lending on HyperEVM with automated rotation into whichever pool offers the strongest risk-adjusted lending yield.
|
|
95
|
+
**Chains:** HyperEVM only (HyperLend pool suite).
|
|
96
|
+
**Deposit/Withdrawal:** Deposits move USDT0 from the main wallet into the strategy wallet, top up a minimal HYPE gas buffer, rotate into the selected stable, and lend it via HyperLend.
|
|
97
|
+
Withdrawals unwind the lend position, convert balances back to USDT, and return funds (plus residual HYPE) to the main wallet.
|
|
98
|
+
**Gas**: Requires HYPE on HypeEVM. Arbitrary amount of funding gas is accepted via vault wallet transfers.
|
|
99
|
+
""",
|
|
100
|
+
summary=(
|
|
101
|
+
"Recency-weighted HyperLend stablecoin optimizer that bootstraps 7-day rate history "
|
|
102
|
+
f"(horizon {HORIZON_HOURS}h, {BLOCK_LEN}-hour blocks, {TRIALS:,} simulations) to pick the top "
|
|
103
|
+
"performer, funds with USDT0, tops up a small HYPE gas buffer, and defaults to a hysteresis "
|
|
104
|
+
f"rotation band (dwell={HYSTERESIS_DWELL_HOURS}h, z={HYSTERESIS_Z:.2f}) to avoid churn while still "
|
|
105
|
+
"short-circuiting when yield gaps are extreme."
|
|
106
|
+
),
|
|
107
|
+
gas_token_symbol="HYPE",
|
|
108
|
+
gas_token_id="hyperliquid-hyperevm",
|
|
109
|
+
deposit_token_id="usdt0-hyperevm",
|
|
110
|
+
minimum_net_deposit=10,
|
|
111
|
+
gas_maximum=MAX_GAS, # hype float
|
|
112
|
+
gas_threshold=MAX_GAS / 3,
|
|
113
|
+
# risk indicators
|
|
114
|
+
volatility=Volatility.LOW,
|
|
115
|
+
volatility_description_short=(
|
|
116
|
+
"Pure HyperLend stablecoin lending keeps NAV steady aside from rate drift."
|
|
117
|
+
),
|
|
118
|
+
directionality=Directionality.MARKET_NEUTRAL,
|
|
119
|
+
directionality_description=(
|
|
120
|
+
"Rotates capital between USD stables so exposure stays market neutral."
|
|
121
|
+
),
|
|
122
|
+
complexity=Complexity.LOW,
|
|
123
|
+
complexity_description="Agent handles optimal pool finding, swaps, and lend transactions automatically.",
|
|
124
|
+
token_exposure=TokenExposure.STABLECOINS,
|
|
125
|
+
token_exposure_description=(
|
|
126
|
+
"Only HyperEVM USD stables (USDT0 and peers), no volatile tokens."
|
|
127
|
+
),
|
|
128
|
+
frequency=Frequency.LOW,
|
|
129
|
+
frequency_description=(
|
|
130
|
+
"Updates every 2 hours; rotations infrequent (weekly cooldowns)."
|
|
131
|
+
),
|
|
132
|
+
return_drivers=["lend APY", "pool yield"],
|
|
133
|
+
config={
|
|
134
|
+
"deposit": {
|
|
135
|
+
"description": "Move USDT0 into the vault, ensure a small HYPE gas buffer, and supply the best HyperLend stable.",
|
|
136
|
+
"parameters": {
|
|
137
|
+
"main_token_amount": {
|
|
138
|
+
"type": "float",
|
|
139
|
+
"unit": "USDT0 tokens",
|
|
140
|
+
"description": "Amount of USDT0 to allocate to HyperLend.",
|
|
141
|
+
"minimum": 1.0, # TODO: 10
|
|
142
|
+
"examples": ["100.0", "250.5"],
|
|
143
|
+
},
|
|
144
|
+
"gas_token_amount": {
|
|
145
|
+
"type": "float",
|
|
146
|
+
"unit": "HYPE tokens",
|
|
147
|
+
"description": "Amount of HYPE to top up into the vault wallet to cover gas costs.",
|
|
148
|
+
"minimum": 0.0,
|
|
149
|
+
"maximum": GAS_MAXIMUM,
|
|
150
|
+
"recommended": GAS_MAXIMUM,
|
|
151
|
+
},
|
|
101
152
|
},
|
|
153
|
+
"result": "USDT0 converted into the top-performing HyperLend stablecoin and supplied on-chain.",
|
|
154
|
+
},
|
|
155
|
+
"withdraw": {
|
|
156
|
+
"description": "Unwinds the position, converts balances to USDT0, and returns funds (plus HYPE buffer) to the main wallet.",
|
|
157
|
+
"parameters": {},
|
|
158
|
+
"result": "Principal and accrued gains returned in USDT0; residual HYPE buffer swept home.",
|
|
159
|
+
},
|
|
160
|
+
"update": {
|
|
161
|
+
"description": (
|
|
162
|
+
"Evaluates tournament projections and rotates when the hysteresis band is breached "
|
|
163
|
+
f"(dwell={HYSTERESIS_DWELL_HOURS}h, z={HYSTERESIS_Z:.2f}) or when a short-circuit gap is hit "
|
|
164
|
+
"(set HYPERLEND_ROTATION_POLICY=cooldown to restore the legacy threshold/cooldown rule)."
|
|
165
|
+
),
|
|
166
|
+
"parameters": {},
|
|
167
|
+
},
|
|
168
|
+
"status": {
|
|
169
|
+
"description": "Summarises current lend position, APY, and chosen asset.",
|
|
170
|
+
"provides": [
|
|
171
|
+
"lent_asset",
|
|
172
|
+
"lent_balance",
|
|
173
|
+
"current_apy",
|
|
174
|
+
"best_candidate",
|
|
175
|
+
"best_candidate_apy",
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
"points": {
|
|
179
|
+
"description": "Fetch the HyperLend points account snapshot for this vault wallet using a signed login.",
|
|
180
|
+
"parameters": {},
|
|
181
|
+
"result": "Returns the HyperLend points API payload for the strategy wallet.",
|
|
182
|
+
},
|
|
183
|
+
"technical_details": {
|
|
184
|
+
"rotation_policy": ROTATION_POLICY.lower(),
|
|
185
|
+
"hysteresis_dwell_hours": HYSTERESIS_DWELL_HOURS,
|
|
186
|
+
"hysteresis_z": HYSTERESIS_Z,
|
|
187
|
+
"rotation_tx_cost": ROTATION_TX_COST,
|
|
102
188
|
},
|
|
103
|
-
"result": "USDT0 converted into the top-performing HyperLend stablecoin and supplied on-chain.",
|
|
104
|
-
},
|
|
105
|
-
"withdraw": {
|
|
106
|
-
"description": "Unwinds the position, converts balances to USDT0, and returns funds (plus HYPE buffer) to the main wallet.",
|
|
107
|
-
"parameters": {},
|
|
108
|
-
"result": "Principal and accrued gains returned in USDT0; residual HYPE buffer swept home.",
|
|
109
|
-
},
|
|
110
|
-
"update": {
|
|
111
|
-
"description": (
|
|
112
|
-
"Evaluates tournament projections and rotates when the hysteresis band is breached "
|
|
113
|
-
f"(dwell={HYSTERESIS_DWELL_HOURS}h, z={HYSTERESIS_Z:.2f}) or when a short-circuit gap is hit "
|
|
114
|
-
"(set HYPERLEND_ROTATION_POLICY=cooldown to restore the legacy threshold/cooldown rule)."
|
|
115
|
-
),
|
|
116
|
-
"parameters": {},
|
|
117
|
-
},
|
|
118
|
-
"status": {
|
|
119
|
-
"description": "Summarises current lend position, APY, and chosen asset.",
|
|
120
|
-
"provides": [
|
|
121
|
-
"lent_asset",
|
|
122
|
-
"lent_balance",
|
|
123
|
-
"current_apy",
|
|
124
|
-
"best_candidate",
|
|
125
|
-
"best_candidate_apy",
|
|
126
|
-
],
|
|
127
|
-
},
|
|
128
|
-
"points": {
|
|
129
|
-
"description": "Fetch the HyperLend points account snapshot for this vault wallet using a signed login.",
|
|
130
|
-
"parameters": {},
|
|
131
|
-
"result": "Returns the HyperLend points API payload for the strategy wallet.",
|
|
132
|
-
},
|
|
133
|
-
"technical_details": {
|
|
134
|
-
"rotation_policy": ROTATION_POLICY.lower(),
|
|
135
|
-
"hysteresis_dwell_hours": HYSTERESIS_DWELL_HOURS,
|
|
136
|
-
"hysteresis_z": HYSTERESIS_Z,
|
|
137
|
-
"rotation_tx_cost": ROTATION_TX_COST,
|
|
138
189
|
},
|
|
139
|
-
|
|
190
|
+
)
|
|
140
191
|
|
|
141
192
|
def __init__(
|
|
142
193
|
self,
|
|
@@ -2323,6 +2374,17 @@ class HyperlendStableYieldStrategy(Strategy):
|
|
|
2323
2374
|
}
|
|
2324
2375
|
|
|
2325
2376
|
@staticmethod
|
|
2326
|
-
def policies() -> list[str]:
|
|
2377
|
+
async def policies() -> list[str]:
|
|
2327
2378
|
"""Return policy strings used to scope on-chain permissions."""
|
|
2328
|
-
return [
|
|
2379
|
+
return [
|
|
2380
|
+
any_hyperliquid_l1_payload(),
|
|
2381
|
+
any_hyperliquid_user_payload(),
|
|
2382
|
+
hypecore_sentinel_deposit(),
|
|
2383
|
+
await whype_deposit_and_withdraw(),
|
|
2384
|
+
erc20_spender_for_any_token(HYPERLEND_POOL),
|
|
2385
|
+
await hyperlend_supply_and_withdraw(),
|
|
2386
|
+
erc20_spender_for_any_token(ENSO_ROUTER),
|
|
2387
|
+
await enso_swap(),
|
|
2388
|
+
erc20_spender_for_any_token(PRJX_ROUTER),
|
|
2389
|
+
await prjx_swap(),
|
|
2390
|
+
]
|
|
@@ -11,6 +11,14 @@ from wayfinder_paths.core.services.local_token_txn import (
|
|
|
11
11
|
LocalTokenTxnService,
|
|
12
12
|
)
|
|
13
13
|
from wayfinder_paths.core.services.web3_service import DefaultWeb3Service
|
|
14
|
+
from wayfinder_paths.core.strategies.descriptors import (
|
|
15
|
+
Complexity,
|
|
16
|
+
Directionality,
|
|
17
|
+
Frequency,
|
|
18
|
+
StratDescriptor,
|
|
19
|
+
TokenExposure,
|
|
20
|
+
Volatility,
|
|
21
|
+
)
|
|
14
22
|
from wayfinder_paths.core.strategies.Strategy import StatusDict, StatusTuple, Strategy
|
|
15
23
|
from wayfinder_paths.core.wallets.WalletManager import WalletManager
|
|
16
24
|
from wayfinder_paths.vaults.adapters.balance_adapter.adapter import BalanceAdapter
|
|
@@ -33,84 +41,113 @@ class StablecoinYieldStrategy(Strategy):
|
|
|
33
41
|
SUPPORTED_NETWORK_CODES = {"base"}
|
|
34
42
|
ROTATION_MIN_INTERVAL = timedelta(days=14)
|
|
35
43
|
MINIMUM_APY_IMPROVEMENT = 0.01
|
|
36
|
-
GAS_MAXIMUM =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
44
|
+
GAS_MAXIMUM = 10e-4 # ethereum float
|
|
45
|
+
GAS_SAFETY_FRACTION = 1 / 3
|
|
46
|
+
|
|
47
|
+
INFO = StratDescriptor(
|
|
48
|
+
description=(
|
|
49
|
+
"An automated yield optimization strategy that maximizes returns on USDC deposits on Base.\n\n"
|
|
50
|
+
"What it does: Continuously scans and evaluates yield opportunities across Base-based DeFi protocols to find the "
|
|
51
|
+
"highest-yielding, low-risk positions for USDC. Automatically rebalances positions when better opportunities "
|
|
52
|
+
"emerge to maintain optimal yield generation.\n\n"
|
|
53
|
+
"Exposure type: Stable USD-denominated exposure with minimal impermanent loss risk. Focuses exclusively on USDC "
|
|
54
|
+
"and operations on the Base network to preserve capital and maximize yield.\n\n"
|
|
55
|
+
"Chains: Operates solely on the Base network.\n\n"
|
|
56
|
+
f"Deposit/Withdrawal: Accepts deposits only in USDC on Base with a minimum of {MIN_AMOUNT_USDC} USDC. Gas: Requires Base ETH "
|
|
57
|
+
"for gas fees during position entry, rebalancing, and exit (~0.001-0.02 ETH per rebalance cycle). Strategy automatically "
|
|
58
|
+
"deploys funds to an optimal yield farming position on Base. Withdrawals exit current positions and return USDC to the "
|
|
59
|
+
"user wallet.\n\n"
|
|
60
|
+
f"Risks: Primary risks include smart contract vulnerabilities in underlying Base DeFi protocols, temporary yield fluctuations, "
|
|
61
|
+
f"gas costs during rebalancing, and potential brief capital lock-up during protocol transitions. Strategy filters for a minimum TVL of ${MIN_TVL:,}."
|
|
62
|
+
),
|
|
63
|
+
summary=(
|
|
64
|
+
"Automated stablecoin yield farming across DeFi protocols on Base. "
|
|
65
|
+
f"Continuously optimizes positions for maximum stable yield while avoiding impermanent loss. "
|
|
66
|
+
f"Min: {MIN_AMOUNT_USDC} USDC + ETH gas. Filters for ${MIN_TVL:,}+ TVL protocols."
|
|
67
|
+
),
|
|
68
|
+
gas_token_symbol="ETH",
|
|
69
|
+
gas_token_id="ethereum-base",
|
|
70
|
+
deposit_token_id="usd-coin-base",
|
|
71
|
+
minimum_net_deposit=50,
|
|
72
|
+
gas_maximum=GAS_MAXIMUM,
|
|
73
|
+
# Anything below this level triggers a gas top-up
|
|
74
|
+
gas_threshold=GAS_MAXIMUM * GAS_SAFETY_FRACTION,
|
|
75
|
+
# risk indicators
|
|
76
|
+
volatility=Volatility.LOW,
|
|
77
|
+
volatility_description_short=(
|
|
78
|
+
"Capital sits in Base stablecoin lending pools, so price swings are minimal."
|
|
79
|
+
),
|
|
80
|
+
directionality=Directionality.MARKET_NEUTRAL,
|
|
81
|
+
directionality_description=(
|
|
82
|
+
"Fully USD-denominated yield farming with no directional crypto beta."
|
|
83
|
+
),
|
|
84
|
+
complexity=Complexity.LOW,
|
|
85
|
+
complexity_description="Agent handles optimal pool finding and rebalancing",
|
|
86
|
+
token_exposure=TokenExposure.STABLECOINS,
|
|
87
|
+
token_exposure_description=(
|
|
88
|
+
"Only Base USDC (and occasional stable swaps) with no volatile assets."
|
|
89
|
+
),
|
|
90
|
+
frequency=Frequency.LOW,
|
|
91
|
+
frequency_description=(
|
|
92
|
+
"Updates every 2 hours; rebalances infrequent (bi-weekly cooldowns)."
|
|
93
|
+
),
|
|
94
|
+
return_drivers=["pool yield"],
|
|
95
|
+
# config metadata for UIs/agents
|
|
96
|
+
config={
|
|
97
|
+
"deposit": {
|
|
98
|
+
"parameters": {
|
|
99
|
+
"main_token_amount": {
|
|
100
|
+
"type": "float",
|
|
101
|
+
"description": "amount of Base USDC (token id: usd-coin-base) to deposit",
|
|
102
|
+
},
|
|
103
|
+
"gas_token_amount": {
|
|
104
|
+
"type": "float",
|
|
105
|
+
"description": "amount of Base ETH (token id: ethereum-base) to deposit for gas fees",
|
|
106
|
+
"minimum": 0,
|
|
107
|
+
"maximum": GAS_MAXIMUM,
|
|
108
|
+
},
|
|
72
109
|
},
|
|
110
|
+
"process": "Deposits USDC on Base and searches for the highest yield opportunities among Base-based DeFi protocols",
|
|
111
|
+
"requirements": [
|
|
112
|
+
"Sufficient USDC balance on Base",
|
|
113
|
+
"Base ETH available for gas",
|
|
114
|
+
],
|
|
115
|
+
"result": "Funds deployed to a yield farming position on Base",
|
|
116
|
+
},
|
|
117
|
+
"withdraw": {
|
|
118
|
+
"parameters": {},
|
|
119
|
+
"process": "Exits yield positions on Base and returns USDC to the user wallet",
|
|
120
|
+
"requirements": [
|
|
121
|
+
"Active positions to exit",
|
|
122
|
+
"Gas for transactions on Base",
|
|
123
|
+
],
|
|
124
|
+
"result": "USDC returned to wallet and positions closed on Base",
|
|
125
|
+
},
|
|
126
|
+
"update": {
|
|
127
|
+
"parameters": {},
|
|
128
|
+
"process": "Scans for better yield opportunities on Base and rebalances positions automatically",
|
|
129
|
+
"frequency": "Call daily or when significant yield changes occur",
|
|
130
|
+
"requirements": [
|
|
131
|
+
"Active strategy positions on Base",
|
|
132
|
+
"Sufficient Base gas for rebalancing",
|
|
133
|
+
],
|
|
134
|
+
"result": "Positions optimized for maximum yield on Base",
|
|
135
|
+
},
|
|
136
|
+
"technical_details": {
|
|
137
|
+
"wallet_structure": "Uses strategy subwallet for isolation",
|
|
138
|
+
"chains": ["Base"],
|
|
139
|
+
"protocols": ["Various Base DeFi yield protocols"],
|
|
140
|
+
"tokens": ["USDC"],
|
|
141
|
+
"gas_requirements": "~0.001-0.02 ETH per rebalance on Base",
|
|
142
|
+
"search_depth": SEARCH_DEPTH,
|
|
143
|
+
"minimum_tvl": MIN_TVL,
|
|
144
|
+
"dust_apy_threshold": DUST_APY,
|
|
145
|
+
"minimum_apy_edge": MINIMUM_APY_IMPROVEMENT,
|
|
146
|
+
"rotation_cooldown_days": ROTATION_MIN_INTERVAL.days,
|
|
147
|
+
"profit_horizon_days": MINIMUM_DAYS_UNTIL_PROFIT,
|
|
73
148
|
},
|
|
74
|
-
"process": "Deposits USDC on Base and searches for the highest yield opportunities among Base-based DeFi protocols",
|
|
75
|
-
"requirements": [
|
|
76
|
-
"Sufficient USDC balance on Base",
|
|
77
|
-
"Base ETH available for gas",
|
|
78
|
-
],
|
|
79
|
-
"result": "Funds deployed to a yield farming position on Base",
|
|
80
|
-
},
|
|
81
|
-
"withdraw": {
|
|
82
|
-
"parameters": {},
|
|
83
|
-
"process": "Exits yield positions on Base and returns USDC to the user wallet",
|
|
84
|
-
"requirements": [
|
|
85
|
-
"Active positions to exit",
|
|
86
|
-
"Gas for transactions on Base",
|
|
87
|
-
],
|
|
88
|
-
"result": "USDC returned to wallet and positions closed on Base",
|
|
89
|
-
},
|
|
90
|
-
"update": {
|
|
91
|
-
"parameters": {},
|
|
92
|
-
"process": "Scans for better yield opportunities on Base and rebalances positions automatically",
|
|
93
|
-
"frequency": "Call daily or when significant yield changes occur",
|
|
94
|
-
"requirements": [
|
|
95
|
-
"Active strategy positions on Base",
|
|
96
|
-
"Sufficient Base gas for rebalancing",
|
|
97
|
-
],
|
|
98
|
-
"result": "Positions optimized for maximum yield on Base",
|
|
99
|
-
},
|
|
100
|
-
"technical_details": {
|
|
101
|
-
"wallet_structure": "Uses strategy subwallet for isolation",
|
|
102
|
-
"chains": ["Base"],
|
|
103
|
-
"protocols": ["Various Base DeFi yield protocols"],
|
|
104
|
-
"tokens": ["USDC"],
|
|
105
|
-
"gas_requirements": "~0.001-0.02 ETH per rebalance on Base",
|
|
106
|
-
"search_depth": SEARCH_DEPTH,
|
|
107
|
-
"minimum_tvl": MIN_TVL,
|
|
108
|
-
"dust_apy_threshold": DUST_APY,
|
|
109
|
-
"minimum_apy_edge": MINIMUM_APY_IMPROVEMENT,
|
|
110
|
-
"rotation_cooldown_days": ROTATION_MIN_INTERVAL.days,
|
|
111
|
-
"profit_horizon_days": MINIMUM_DAYS_UNTIL_PROFIT,
|
|
112
149
|
},
|
|
113
|
-
|
|
150
|
+
)
|
|
114
151
|
|
|
115
152
|
def __init__(
|
|
116
153
|
self,
|