File size: 13,747 Bytes
c3f6357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
"""
Dynamic RWA Yield Router β€” Configuration & Constants
=====================================================
All contract addresses, ABIs, chain configuration, and protocol parameters
for the Mantle L2 ecosystem (Chain ID 5000).
"""

import os
from dataclasses import dataclass, field
from typing import Dict, List, Optional
from enum import Enum

# ─────────────────────────── Chain Config ───────────────────────────

MANTLE_CHAIN_ID = 5000
MANTLE_RPC_URL = os.getenv("MANTLE_RPC_URL", "https://rpc.mantle.xyz")
MANTLE_WSS_URL = os.getenv("MANTLE_WSS_URL", "wss://ws.mantle.xyz")
MANTLE_EXPLORER = "https://explorer.mantle.xyz"
MANTLE_BLOCK_TIME_SECONDS = 2  # Mantle L2 ~2s blocks

# ─────────────────────────── Token Addresses (Mantle Mainnet) ───────

class Tokens:
    """Core token contract addresses on Mantle L2."""
    # Stablecoins
    USDC = "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9"
    USDT = "0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE"
    
    # Native / Wrapped
    WMNT = "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"
    WETH = "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111"
    
    # RWA Assets β€” Core Portfolio
    USDY = "0x5bE26527e817998A7206475496fDE1E68957c5A6"    # Ondo USDY (tokenized T-bills, ~4.25% APY)
    METH = "0xcDA86A272531e8640cD7F1a92c01839911B90bb0"    # Mantle Staked ETH (~3-5% APY)
    CMETH = "0xE6829d9a7eE3040e1276Fa75293Bde931859e8fD"   # Mantle Restaked ETH (cmETH)
    
    # MI4 β€” Mantle Index Four (multi-chain, primary on Avalanche)
    # On Mantle, MI4 exposure may be achieved via bridged tokens or Securitize portal
    MI4_AVALANCHE = "0xe87db19a4a45a804f9b6e8038777c9a0ffbc5808"
    MI4_PROXY = None  # Set via env if bridged to Mantle
    
    # Fluxion xStocks RWA tokens (on Mantle)
    XAAPL = "0x3E6f0A37E795dA0304a7fC400f4CF6D8D028e1Ee"
    XGOOG = "0x98a4eaB8B6CFE76EB8e36FcB5a0F09E2E4B62c2b"
    XAMZN = "0x3607c534e9Ae5B4f1e968d9E7480e9D8a5f22eAa"
    XTSLA = "0x5762E9828C8EEF98Ae08C7F8eB2C53C3dF6C4c2C"
    XSPY = "0x5D9D2F2d8b8E7B5C0E5d6A4b0E7F1c2A3D4E5F6A"  # Placeholder


# ─────────────────────────── DEX Router Addresses ───────────────────

class DEXRouters:
    """DEX router contracts on Mantle."""
    FLUXION_SWAP_ROUTER = "0x5628a59df0ecac3f3171f877a94beb26ba6dfaa0"
    AGNI_SWAP_ROUTER = "0x319B69888b0d11cEC22caA5034e25FfFBDc88421"
    MERCHANT_MOE_ROUTER = "0xeaEE7EE68874218c3558b40063c42B82D3E7232a"
    
    # Fluxion V3 (Uni V3 fork) β€” primary for RWA pairs
    FLUXION_FACTORY = "0x5CA14E40bB7Bc70A3c2e672D5F43e5B8cE48ec68"
    FLUXION_QUOTER = "0x64B421eE1a1Ed22ed2288B4e3e15Dd9bD5AC5B68"


# ─────────────────────────── Lending Protocol Addresses ─────────────

class LendingProtocols:
    """Lending/yield protocol contracts on Mantle."""
    # Aave V3 (Lendle fork on Mantle)
    AAVE_V3_POOL = "0x458F293454fE0d67EC0655f3672301301DD51422"
    AAVE_V3_POOL_DATA_PROVIDER = "0x5DA14e30e92E20C9B4Fe3e22c2B499D7EA0E8b02"
    
    # INIT Capital
    INIT_CORE = "0x972BcD3960c17E5e1f2B98713c2B1A1E1eE1e2D3"  # Verify on deploy
    
    # Pendle (yield tokenization)
    PENDLE_ROUTER = "0x00000000005BBB0EF59571E58418F9a4357b68A0"


# ─────────────────────────── Minimal ABIs ───────────────────────────

ERC20_ABI = [
    {"constant": True, "inputs": [], "name": "name", "outputs": [{"name": "", "type": "string"}], "type": "function"},
    {"constant": True, "inputs": [], "name": "symbol", "outputs": [{"name": "", "type": "string"}], "type": "function"},
    {"constant": True, "inputs": [], "name": "decimals", "outputs": [{"name": "", "type": "uint8"}], "type": "function"},
    {"constant": True, "inputs": [], "name": "totalSupply", "outputs": [{"name": "", "type": "uint256"}], "type": "function"},
    {"constant": True, "inputs": [{"name": "_owner", "type": "address"}], "name": "balanceOf", "outputs": [{"name": "balance", "type": "uint256"}], "type": "function"},
    {"constant": False, "inputs": [{"name": "_spender", "type": "address"}, {"name": "_value", "type": "uint256"}], "name": "approve", "outputs": [{"name": "", "type": "bool"}], "type": "function"},
    {"constant": True, "inputs": [{"name": "_owner", "type": "address"}, {"name": "_spender", "type": "address"}], "name": "allowance", "outputs": [{"name": "", "type": "uint256"}], "type": "function"},
    {"constant": False, "inputs": [{"name": "_to", "type": "address"}, {"name": "_value", "type": "uint256"}], "name": "transfer", "outputs": [{"name": "", "type": "bool"}], "type": "function"},
]

# Uniswap V3 SwapRouter (Fluxion/Agni compatible)
SWAP_ROUTER_ABI = [
    {
        "inputs": [
            {
                "components": [
                    {"name": "tokenIn", "type": "address"},
                    {"name": "tokenOut", "type": "address"},
                    {"name": "fee", "type": "uint24"},
                    {"name": "recipient", "type": "address"},
                    {"name": "deadline", "type": "uint256"},
                    {"name": "amountIn", "type": "uint256"},
                    {"name": "amountOutMinimum", "type": "uint256"},
                    {"name": "sqrtPriceLimitX96", "type": "uint160"},
                ],
                "name": "params",
                "type": "tuple",
            }
        ],
        "name": "exactInputSingle",
        "outputs": [{"name": "amountOut", "type": "uint256"}],
        "type": "function",
    },
    {
        "inputs": [
            {
                "components": [
                    {"name": "path", "type": "bytes"},
                    {"name": "recipient", "type": "address"},
                    {"name": "deadline", "type": "uint256"},
                    {"name": "amountIn", "type": "uint256"},
                    {"name": "amountOutMinimum", "type": "uint256"},
                ],
                "name": "params",
                "type": "tuple",
            }
        ],
        "name": "exactInput",
        "outputs": [{"name": "amountOut", "type": "uint256"}],
        "type": "function",
    },
]

# Aave V3 Pool β€” supply/withdraw
AAVE_POOL_ABI = [
    {
        "inputs": [
            {"name": "asset", "type": "address"},
            {"name": "amount", "type": "uint256"},
            {"name": "onBehalfOf", "type": "address"},
            {"name": "referralCode", "type": "uint16"},
        ],
        "name": "supply",
        "outputs": [],
        "type": "function",
    },
    {
        "inputs": [
            {"name": "asset", "type": "address"},
            {"name": "amount", "type": "uint256"},
            {"name": "to", "type": "address"},
        ],
        "name": "withdraw",
        "outputs": [{"name": "", "type": "uint256"}],
        "type": "function",
    },
    {
        "inputs": [{"name": "asset", "type": "address"}],
        "name": "getReserveData",
        "outputs": [
            {
                "components": [
                    {"name": "configuration", "type": "uint256"},
                    {"name": "liquidityIndex", "type": "uint128"},
                    {"name": "currentLiquidityRate", "type": "uint128"},
                    {"name": "variableBorrowIndex", "type": "uint128"},
                    {"name": "currentVariableBorrowRate", "type": "uint128"},
                    {"name": "currentStableBorrowRate", "type": "uint128"},
                    {"name": "lastUpdateTimestamp", "type": "uint40"},
                    {"name": "id", "type": "uint16"},
                    {"name": "aTokenAddress", "type": "address"},
                    {"name": "stableDebtTokenAddress", "type": "address"},
                    {"name": "variableDebtTokenAddress", "type": "address"},
                    {"name": "interestRateStrategyAddress", "type": "address"},
                    {"name": "accruedToTreasury", "type": "uint128"},
                    {"name": "unbacked", "type": "uint128"},
                    {"name": "isolationModeTotalDebt", "type": "uint128"},
                ],
                "name": "",
                "type": "tuple",
            }
        ],
        "type": "function",
    },
]

# mETH staking β€” read staking yield
METH_STAKING_ABI = [
    {"constant": True, "inputs": [], "name": "mETHToETH", "outputs": [{"name": "", "type": "uint256"}], "type": "function"},
    {"constant": True, "inputs": [], "name": "totalControlled", "outputs": [{"name": "", "type": "uint256"}], "type": "function"},
    {"constant": True, "inputs": [], "name": "exchangeRateUpdatedAt", "outputs": [{"name": "", "type": "uint256"}], "type": "function"},
]


# ─────────────────────────── Portfolio Parameters ───────────────────

@dataclass
class PortfolioConfig:
    """Default portfolio allocation parameters."""
    # Asset universe
    assets: List[str] = field(default_factory=lambda: ["USDY", "mETH", "MI4"])
    
    # Target yield (annualized)
    min_target_apy: float = 3.5  # minimum acceptable APY %
    max_target_apy: float = 12.0  # aspirational max
    
    # Risk constraints
    max_single_asset_weight: float = 0.60  # no single asset > 60%
    min_single_asset_weight: float = 0.05  # minimum 5% in each active asset
    max_drawdown_pct: float = 0.10  # 10% max drawdown trigger
    
    # Rebalancing
    rebalance_threshold_pct: float = 0.05  # rebalance when drift > 5%
    min_rebalance_interval_hours: int = 4   # no more frequent than 4h
    max_rebalance_interval_hours: int = 168  # at least weekly
    
    # Gas budget
    max_gas_per_rebalance_usd: float = 5.0  # Mantle gas is cheap (~$0.01-0.10/tx)
    
    # Slippage
    max_slippage_bps: int = 50  # 0.5% max slippage


@dataclass
class RiskConfig:
    """Risk management parameters."""
    # Depeg detection thresholds
    usdy_depeg_threshold: float = 0.005   # USDY/USD deviation > 0.5%
    meth_depeg_threshold: float = 0.02    # mETH/ETH deviation > 2%
    
    # Circuit breakers
    circuit_breaker_cooldown_hours: int = 24
    emergency_exit_to: str = "USDC"  # flee to stablecoin on emergency
    
    # Smart contract risk scores (0-1, higher = riskier)
    protocol_risk_scores: Dict[str, float] = field(default_factory=lambda: {
        "USDY": 0.15,   # Ondo β€” audited, regulated, low risk
        "mETH": 0.25,   # Mantle LSP β€” battle-tested but smart contract risk
        "MI4": 0.30,    # Securitize β€” newer product, moderate risk
        "Aave": 0.10,   # Heavily audited
        "Fluxion": 0.35, # Newer DEX, higher risk
    })
    
    # Volatility lookback
    volatility_window_days: int = 30
    correlation_window_days: int = 90


@dataclass 
class RLConfig:
    """Reinforcement Learning hyperparameters."""
    # PPO parameters
    learning_rate: float = 3e-4
    gamma: float = 0.99          # discount factor
    gae_lambda: float = 0.95     # GAE lambda
    clip_range: float = 0.2      # PPO clip
    entropy_coef: float = 0.01   # exploration bonus
    value_coef: float = 0.5
    max_grad_norm: float = 0.5
    
    # Training
    n_steps: int = 2048
    batch_size: int = 64
    n_epochs: int = 10
    total_timesteps: int = 1_000_000
    
    # State space dimension
    state_dim: int = 15  # yield rates, prices, volatilities, portfolio weights, macro
    action_dim: int = 3  # weights for [USDY, mETH, MI4]
    
    # Environment
    episode_length_days: int = 30
    reward_scaling: float = 100.0  # scale small yield differences


# ─────────────────────────── API Endpoints ──────────────────────────

class APIEndpoints:
    """External data source endpoints."""
    DEFILLAMA_YIELDS = "https://yields.llama.fi/pools"
    DEFILLAMA_PROTOCOL = "https://api.llama.fi/protocol/{protocol}"
    DEFILLAMA_TVL = "https://api.llama.fi/tvl/{protocol}"
    
    COINGECKO_PRICE = "https://api.coingecko.com/api/v3/simple/price"
    COINGECKO_HISTORY = "https://api.coingecko.com/api/v3/coins/{coin_id}/market_chart"
    
    BYBIT_TICKER = "https://api.bybit.com/v5/market/tickers"
    BYBIT_KLINE = "https://api.bybit.com/v5/market/kline"
    
    # Federal Reserve data
    FRED_API = "https://api.stlouisfed.org/fred/series/observations"
    
    # Mantle-specific
    MANTLE_SUBGRAPH = "https://subgraph.mantle.xyz/subgraphs/name/{name}"


# ─────────────────────────── Logging Config ─────────────────────────

LOG_FORMAT = "%(asctime)s | %(name)-20s | %(levelname)-7s | %(message)s"
LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")

# ─────────────────────────── ERC-8004 Agent Identity ────────────────

ERC8004_CAPABILITIES = [
    "yield_optimization",
    "portfolio_rebalancing",
    "risk_assessment",
    "market_analysis",
    "strategy_reporting",
]

AGENT_METADATA = {
    "name": "Dynamic RWA Yield Router",
    "version": "1.0.0",
    "description": "Autonomous AI agent for yield-optimized RWA portfolio management on Mantle",
    "chain_id": MANTLE_CHAIN_ID,
    "supported_assets": ["USDY", "mETH", "MI4"],
    "risk_framework": "risk-parity-adaptive",
    "rl_algorithm": "PPO",
}