primecli 0.5.6__tar.gz → 0.5.8__tar.gz
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.
- {primecli-0.5.6 → primecli-0.5.8}/PKG-INFO +1 -1
- {primecli-0.5.6 → primecli-0.5.8}/primecli/degenprime.py +58 -5
- {primecli-0.5.6 → primecli-0.5.8}/primecli/health_monitor.py +97 -64
- {primecli-0.5.6 → primecli-0.5.8}/primecli.egg-info/PKG-INFO +1 -1
- {primecli-0.5.6 → primecli-0.5.8}/pyproject.toml +1 -1
- {primecli-0.5.6 → primecli-0.5.8}/LICENSE +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/README.md +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli/__init__.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli/arbprime.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli/deltaprime.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli.egg-info/SOURCES.txt +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli.egg-info/dependency_links.txt +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli.egg-info/entry_points.txt +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli.egg-info/requires.txt +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/primecli.egg-info/top_level.txt +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/setup.cfg +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/tests/test_cross_file_identity.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/tests/test_gas_pricing.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/tests/test_health_monitor.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/tests/test_paraswap_validator.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/tests/test_redstone_encoding.py +0 -0
- {primecli-0.5.6 → primecli-0.5.8}/tests/test_to_wei_units.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: primecli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: Agent-friendly CLI tools for the DeltaPrime (Avalanche + Arbitrum) and DegenPrime (Base) lending and leverage protocols. Preview-by-default; no Etherscan key required.
|
|
5
5
|
Author: Mnemosyne-quest contributors
|
|
6
6
|
License: MIT
|
|
@@ -137,6 +137,42 @@ ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
|
|
|
137
137
|
# read lazily so read-only commands that don't sign never need a key at all.
|
|
138
138
|
_CLI_KEY = None # set by the --key CLI flag in main()
|
|
139
139
|
|
|
140
|
+
# Named-wallet table shared with deltaprime/arbprime. Allows running via
|
|
141
|
+
# DEGENPRIME_AGENT=parakletos (or the fallback DELTAPRIME_AGENT) which is
|
|
142
|
+
# cleaner than passing raw keys through environment variables.
|
|
143
|
+
# Agent resolution also supports --as <agent> CLI flag.
|
|
144
|
+
AGENTS = {
|
|
145
|
+
"parakletos": ("/root/.openclaw/.env", "PARAKLETOS_EVM_PRIVATE_KEY"),
|
|
146
|
+
"paraklaudios": ("/root/paraklaudios/.credentials.env", "PARAKLAUDIOS_EVM_PRIVATE_KEY"),
|
|
147
|
+
}
|
|
148
|
+
_SELECTED_AGENT = None # set by the --as CLI flag in main()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _read_env_var(path, var):
|
|
152
|
+
"""Return the value of `var` from a KEY=VALUE env file, or None if absent."""
|
|
153
|
+
try:
|
|
154
|
+
for line in Path(path).read_text().splitlines():
|
|
155
|
+
s = line.strip()
|
|
156
|
+
if s.startswith(var + "="):
|
|
157
|
+
return s.split("=", 1)[1].strip().strip('"').strip("'")
|
|
158
|
+
except FileNotFoundError:
|
|
159
|
+
return None
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _agent_key(agent):
|
|
164
|
+
if agent not in AGENTS:
|
|
165
|
+
raise RuntimeError(
|
|
166
|
+
f"Unknown agent '{agent}'. Known agents: {', '.join(AGENTS)}. "
|
|
167
|
+
f"Or set DEGENPRIME_PRIVATE_KEY, or DEGENPRIME_KEY_FILE."
|
|
168
|
+
)
|
|
169
|
+
path, var = AGENTS[agent]
|
|
170
|
+
key = _read_env_var(path, var)
|
|
171
|
+
if not key:
|
|
172
|
+
raise RuntimeError(f"{var} not found in {path} (agent '{agent}').")
|
|
173
|
+
return key
|
|
174
|
+
|
|
175
|
+
|
|
140
176
|
# Core protocol addresses (verified on Base 2026-05-29).
|
|
141
177
|
FACTORY_PROXY = "0x5A6a0e2702cF4603a098C3Df01f3F0DF56115456" # SmartLoansFactory TUP
|
|
142
178
|
# Diamond beacon. Every Degen Account is a per-user proxy that delegates here, so the
|
|
@@ -265,12 +301,17 @@ def _set_gas_price(w3, tx_dict):
|
|
|
265
301
|
def resolve_private_key():
|
|
266
302
|
"""Resolve the signing key per the documented precedence:
|
|
267
303
|
1. --key <0xhex> CLI flag
|
|
268
|
-
2.
|
|
269
|
-
3.
|
|
270
|
-
4.
|
|
271
|
-
|
|
304
|
+
2. --as <agent> CLI flag
|
|
305
|
+
3. DEGENPRIME_PRIVATE_KEY env var
|
|
306
|
+
4. DEGENPRIME_KEY_FILE env var (path to a file containing the 0x key)
|
|
307
|
+
5. DELTAPRIME_PRIVATE_KEY / DELTAPRIME_KEY_FILE (same key, both chains)
|
|
308
|
+
6. DEGENPRIME_AGENT env var
|
|
309
|
+
7. DELTAPRIME_AGENT env var (fallback)
|
|
310
|
+
Raises with a clear message if none resolve."""
|
|
272
311
|
if _CLI_KEY:
|
|
273
312
|
return _CLI_KEY.strip()
|
|
313
|
+
if _SELECTED_AGENT:
|
|
314
|
+
return _agent_key(_SELECTED_AGENT)
|
|
274
315
|
for env_var in ("DEGENPRIME_PRIVATE_KEY", "DELTAPRIME_PRIVATE_KEY"):
|
|
275
316
|
raw = os.environ.get(env_var)
|
|
276
317
|
if raw:
|
|
@@ -282,6 +323,11 @@ def resolve_private_key():
|
|
|
282
323
|
return Path(key_file).read_text().strip()
|
|
283
324
|
except FileNotFoundError:
|
|
284
325
|
raise RuntimeError(f"{path_var} points at {key_file} but the file does not exist.")
|
|
326
|
+
# Named agent via env var
|
|
327
|
+
for ag in ("DEGENPRIME_AGENT", "DELTAPRIME_AGENT"):
|
|
328
|
+
agent = os.environ.get(ag)
|
|
329
|
+
if agent:
|
|
330
|
+
return _agent_key(agent)
|
|
285
331
|
raise RuntimeError(
|
|
286
332
|
"No signing key found. Set DEGENPRIME_PRIVATE_KEY (raw 0x... key) or "
|
|
287
333
|
"DEGENPRIME_KEY_FILE (path to a file with the key), or pass --key <0xhex>. "
|
|
@@ -2504,7 +2550,7 @@ def main():
|
|
|
2504
2550
|
def _dispatch():
|
|
2505
2551
|
args = sys.argv[1:] if len(sys.argv) > 1 else []
|
|
2506
2552
|
# Global signing-key override: --key <0xhex>, stripped before command dispatch.
|
|
2507
|
-
global _CLI_KEY
|
|
2553
|
+
global _SELECTED_AGENT, _CLI_KEY
|
|
2508
2554
|
if "--key" in args:
|
|
2509
2555
|
i = args.index("--key")
|
|
2510
2556
|
if i + 1 >= len(args):
|
|
@@ -2512,6 +2558,13 @@ def _dispatch():
|
|
|
2512
2558
|
return
|
|
2513
2559
|
_CLI_KEY = args[i + 1]
|
|
2514
2560
|
del args[i:i + 2]
|
|
2561
|
+
if "--as" in args:
|
|
2562
|
+
i = args.index("--as")
|
|
2563
|
+
if i + 1 >= len(args):
|
|
2564
|
+
print("--as requires an agent name. Example: --as parakletos")
|
|
2565
|
+
return
|
|
2566
|
+
_SELECTED_AGENT = args[i + 1]
|
|
2567
|
+
del args[i:i + 2]
|
|
2515
2568
|
if not args or args[0] in ("-h", "--help"):
|
|
2516
2569
|
print(__doc__)
|
|
2517
2570
|
return
|
|
@@ -37,22 +37,21 @@ TIER_MAX = {"basic": 5, "premium": 10}
|
|
|
37
37
|
# ════════════════════════════════════════════════════════════════════
|
|
38
38
|
|
|
39
39
|
def compute_health(defi_data: dict, max_mult: int = 10) -> dict:
|
|
40
|
-
"""Compute
|
|
40
|
+
"""Compute health (0-100%) using the frontend formula from DeltaPrime docs.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
Uses the cross-margin health formula (all assets assumed same borrowing power):
|
|
43
|
+
equity = total_supplied_usd - total_debt_usd
|
|
44
|
+
health_pct = 100 * (1 - debt / (max_mult * equity))
|
|
45
|
+
(0% = liquidation, 100% = no debt)
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
Background:
|
|
48
|
+
The frontend uses Pr = tier / (tier + 1) and computes:
|
|
49
|
+
health_pct = (Pr * supplied - debt) / (Pr * equity) * 100
|
|
50
|
+
which simplifies to: 100 * (1 - debt / (max_mult * equity)).
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
(1.0=liquidation
|
|
53
|
-
measurement (0%=liquidation, 50%=half borrowing power used, 100%=no debt).
|
|
54
|
-
|
|
55
|
-
Returns dict with health metrics or error.
|
|
52
|
+
DIFFERENT from the equity-based "health_pct" in defi --json / prime-summary
|
|
53
|
+
(which uses max_debt = equity * (tier - 1)).
|
|
54
|
+
The on-chain health_ratio (1.0=liquidation) is NOT used here.
|
|
56
55
|
"""
|
|
57
56
|
# Parse groups (DeltaPrime format) or flat format (DegenPrime)
|
|
58
57
|
groups = defi_data.get("groups", [])
|
|
@@ -64,22 +63,25 @@ def compute_health(defi_data: dict, max_mult: int = 10) -> dict:
|
|
|
64
63
|
# Use precomputed health_pct from defi --json if available (primecli >= 0.5.4)
|
|
65
64
|
precomputed = g.get("health_pct")
|
|
66
65
|
if precomputed is not None:
|
|
67
|
-
#
|
|
66
|
+
# Override health_pct with frontend formula (ignores precomputed value)
|
|
68
67
|
supplied_usd = sum(s.get("usd", 0) or 0 for s in supplied)
|
|
69
68
|
debt_usd = sum(b.get("usd", 0) or 0 for b in borrowed)
|
|
70
|
-
equity = supplied_usd - debt_usd
|
|
69
|
+
equity = max(supplied_usd - debt_usd, 0.01)
|
|
71
70
|
raw_usdc = sum(s.get("usd", 0) for s in supplied if s.get("symbol") == "USDC")
|
|
72
71
|
symbols = [s.get("symbol", "") for s in supplied]
|
|
73
|
-
has_gmx =
|
|
72
|
+
has_gmx = sum(s.get("usd", 0) for s in supplied if "GM_" in s.get("symbol", "")) > 1.0
|
|
74
73
|
has_lb = any(sym in ("LB_AVAX_USDC", "LB_WAVAX_USDC", "JOE") or "TRADERJOE" in sym.upper() for sym in symbols)
|
|
75
74
|
has_aero = any("AERO" in sym.upper() or "CL_POSITION" in sym.upper() for sym in symbols)
|
|
75
|
+
# Frontend formula: health_pct = 100 * (1 - debt / (max_mult * equity))
|
|
76
|
+
fe_health = max(0.0, 100.0 * (1.0 - round(debt_usd, 2) / (max_mult * equity)))
|
|
77
|
+
fe_max_debt = round(max_mult * equity, 2)
|
|
76
78
|
return {
|
|
77
|
-
"health_pct":
|
|
79
|
+
"health_pct": round(fe_health, 1),
|
|
78
80
|
"health_ratio": round(health_ratio, 4),
|
|
79
81
|
"supplied_usd": round(supplied_usd, 2),
|
|
80
82
|
"debt_usd": round(debt_usd, 2),
|
|
81
83
|
"equity": round(equity, 2),
|
|
82
|
-
"max_debt": round(max(0,
|
|
84
|
+
"max_debt": round(max(0, max_mult * equity), 2),
|
|
83
85
|
"raw_usdc": round(raw_usdc, 2),
|
|
84
86
|
"has_gmx": has_gmx,
|
|
85
87
|
"has_lb": has_lb,
|
|
@@ -105,14 +107,14 @@ def compute_health(defi_data: dict, max_mult: int = 10) -> dict:
|
|
|
105
107
|
"error": "equity near zero",
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
max_debt =
|
|
110
|
+
max_debt = round(max_mult * equity, 2) # frontend formula: max debt before liquidation
|
|
109
111
|
|
|
110
112
|
# Raw USDC in account
|
|
111
113
|
raw_usdc = sum(s.get("usd", 0) for s in supplied if s.get("symbol") == "USDC")
|
|
112
114
|
|
|
113
115
|
# Position type detection
|
|
114
116
|
symbols = [s.get("symbol", "") for s in supplied]
|
|
115
|
-
has_gmx =
|
|
117
|
+
has_gmx = sum(s.get("usd", 0) for s in supplied if "GM_" in s.get("symbol", "")) > 1.0
|
|
116
118
|
has_lb = any(
|
|
117
119
|
sym in ("LB_AVAX_USDC", "LB_WAVAX_USDC", "JOE")
|
|
118
120
|
or "TRADERJOE" in sym.upper()
|
|
@@ -120,13 +122,13 @@ def compute_health(defi_data: dict, max_mult: int = 10) -> dict:
|
|
|
120
122
|
)
|
|
121
123
|
has_aero = any("AERO" in sym.upper() or "CL_POSITION" in sym.upper() for sym in symbols)
|
|
122
124
|
|
|
123
|
-
if max_debt > 0 and debt_usd >= 0:
|
|
124
|
-
health_pct = (
|
|
125
|
-
health_pct = max(0.0, min(100.0, health_pct))
|
|
125
|
+
if max_debt > 0.01 and debt_usd >= 0:
|
|
126
|
+
health_pct = max(0.0, 100.0 * (1.0 - round(debt_usd, 2) / max_debt))
|
|
126
127
|
else:
|
|
127
128
|
health_pct = 100.0
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
# Center target (50% health): target_debt = max_debt * 0.5
|
|
131
|
+
delta_debt = (max_debt * 0.5) - debt_usd
|
|
130
132
|
|
|
131
133
|
return {
|
|
132
134
|
"health_pct": round(health_pct, 1),
|
|
@@ -306,28 +308,32 @@ def run_tick(
|
|
|
306
308
|
max_mult = TIER_MAX.get("basic", 5)
|
|
307
309
|
tier = "basic"
|
|
308
310
|
else:
|
|
309
|
-
max_mult = TIER_MAX.get("
|
|
310
|
-
tier = "
|
|
311
|
+
max_mult = TIER_MAX.get("basic", 5)
|
|
312
|
+
tier = "basic"
|
|
311
313
|
except Exception:
|
|
312
|
-
max_mult =
|
|
313
|
-
tier = "
|
|
314
|
+
max_mult = 5
|
|
315
|
+
tier = "basic"
|
|
314
316
|
|
|
315
317
|
# 3. Compute health
|
|
316
318
|
health = compute_health(defi_data, max_mult)
|
|
317
319
|
health["tier"] = tier
|
|
318
320
|
if health.get("error") == "equity near zero":
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
321
|
+
# Only escalate if there's actual debt — an empty unfunded wallet is not an emergency
|
|
322
|
+
if health.get("debt_usd", 0) and health["debt_usd"] > 0.5:
|
|
323
|
+
write_escalation(state_dir, "equity-near-zero", {
|
|
324
|
+
"reason": "equity_near_zero",
|
|
325
|
+
"equity": health["equity"],
|
|
326
|
+
"debt": health["debt_usd"],
|
|
327
|
+
"health_pct": health["health_pct"],
|
|
328
|
+
"label": label,
|
|
329
|
+
})
|
|
330
|
+
result["mode"] = "escalated"
|
|
331
|
+
else:
|
|
332
|
+
result["action"] = "none (unfunded account)"
|
|
326
333
|
result.update(health)
|
|
327
|
-
result["mode"] = "escalated"
|
|
328
334
|
return result
|
|
329
335
|
|
|
330
|
-
# 4. Load strategy
|
|
336
|
+
# 4. Load strategy (position/market/side are optional hints now — auto-detected from defi_data)
|
|
331
337
|
strategy = load_strategy(strategy_path)
|
|
332
338
|
mode = strategy.get("mode", "observer")
|
|
333
339
|
health["mode"] = mode
|
|
@@ -390,7 +396,7 @@ def run_tick(
|
|
|
390
396
|
pct = health["health_pct"]
|
|
391
397
|
equity = health["equity"]
|
|
392
398
|
debt = health["debt_usd"]
|
|
393
|
-
raw_usdc = health
|
|
399
|
+
raw_usdc = health.get("raw_usdc", 0)
|
|
394
400
|
|
|
395
401
|
# ── Stop-loss: equity drawdown ──────────────────────────────
|
|
396
402
|
if stop_loss_drawdown > 0:
|
|
@@ -513,32 +519,59 @@ def run_tick(
|
|
|
513
519
|
result["error"] = f"borrow error: {e}"
|
|
514
520
|
return result
|
|
515
521
|
|
|
516
|
-
# Deploy into
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
# Partial state: borrowed but deposit failed
|
|
530
|
-
result["warning"] = f"borrow ok but deposit failed: {r.stderr[:200]}"
|
|
531
|
-
result["action"] = "partial (borrowed, deposit failed)"
|
|
532
|
-
except Exception as e:
|
|
533
|
-
result["error"] = f"gmx deposit error: {e}"
|
|
522
|
+
# Deploy into whatever positions are open (detected dynamically from defi_data)
|
|
523
|
+
has_gmx = health.get("has_gmx", False)
|
|
524
|
+
has_lb = health.get("has_lb", False)
|
|
525
|
+
has_aero = health.get("has_aero", False)
|
|
526
|
+
open_positions = []
|
|
527
|
+
if has_gmx: open_positions.append("gmx")
|
|
528
|
+
if has_lb: open_positions.append("lb")
|
|
529
|
+
if has_aero: open_positions.append("aero")
|
|
530
|
+
|
|
531
|
+
if not open_positions:
|
|
532
|
+
# No open positions — just borrow and leave as USDC (or deploy to default)
|
|
533
|
+
result["action"] = f"borrowed ${borrow_amt:.2f} (no positions to deploy into)"
|
|
534
|
+
cooldown_file.write_text(str(int(time.time())))
|
|
534
535
|
else:
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
536
|
+
# Split borrow amount proportionally across open positions
|
|
537
|
+
split_amt = borrow_amt / len(open_positions)
|
|
538
|
+
deployed_ok = 0
|
|
539
|
+
deployed_fail = 0
|
|
540
|
+
|
|
541
|
+
for pos_type in open_positions:
|
|
542
|
+
if pos_type == "gmx":
|
|
543
|
+
# Use market/side from strategy as hint, fall back to sensible defaults
|
|
544
|
+
mkt = strategy.get("market", "avax-usdc") if tool_path else "avax-usdc"
|
|
545
|
+
sd = strategy.get("side", "long") if tool_path else "long"
|
|
546
|
+
try:
|
|
547
|
+
r = subprocess.run(
|
|
548
|
+
[sys.executable, tool_path, "gmx-deposit",
|
|
549
|
+
"--market", mkt, "--amount", f"{split_amt:.2f}",
|
|
550
|
+
"--side", sd, "--fee-buffer", "1.5", "--execute"],
|
|
551
|
+
capture_output=True, text=True, timeout=120,
|
|
552
|
+
)
|
|
553
|
+
if r.returncode == 0:
|
|
554
|
+
deployed_ok += 1
|
|
555
|
+
else:
|
|
556
|
+
result["warning"] = f"gmx deposit failed: {r.stderr[:200]}"
|
|
557
|
+
deployed_fail += 1
|
|
558
|
+
except Exception as e:
|
|
559
|
+
result["error"] = f"gmx deposit error: {e}"
|
|
560
|
+
deployed_fail += 1
|
|
561
|
+
|
|
562
|
+
elif pos_type == "lb":
|
|
563
|
+
# LB deposits need pair + amount-x + amount-y (not a single amount),
|
|
564
|
+
# so just leave as USDC for now — manual deployment required.
|
|
565
|
+
result["action"] = f"lb-add needs pair + dual amounts — leaving ${split_amt:.2f} as USDC"
|
|
566
|
+
|
|
567
|
+
elif pos_type == "aero":
|
|
568
|
+
result["action"] = f"aero deposit not yet supported by tool — leaving ${split_amt:.2f} as USDC"
|
|
569
|
+
|
|
570
|
+
if deployed_ok > 0:
|
|
571
|
+
cooldown_file.write_text(str(int(time.time())))
|
|
572
|
+
result["action"] = f"borrowed ${borrow_amt:.2f}, deployed ${split_amt:.2f} to {deployed_ok} position(s)"
|
|
573
|
+
else:
|
|
574
|
+
result["warning"] = f"borrow ok but all deposits failed"
|
|
542
575
|
|
|
543
576
|
return result
|
|
544
577
|
|
|
@@ -573,7 +606,7 @@ def cli():
|
|
|
573
606
|
[sys.executable, tool_path, "defi", "--json"],
|
|
574
607
|
capture_output=True, text=True, timeout=90,
|
|
575
608
|
)
|
|
576
|
-
tier = "
|
|
609
|
+
tier = "basic" # default
|
|
577
610
|
try:
|
|
578
611
|
t = subprocess.run(
|
|
579
612
|
[sys.executable, tool_path, "prime-tier"],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: primecli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: Agent-friendly CLI tools for the DeltaPrime (Avalanche + Arbitrum) and DegenPrime (Base) lending and leverage protocols. Preview-by-default; no Etherscan key required.
|
|
5
5
|
Author: Mnemosyne-quest contributors
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "primecli"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.8"
|
|
8
8
|
description = "Agent-friendly CLI tools for the DeltaPrime (Avalanche + Arbitrum) and DegenPrime (Base) lending and leverage protocols. Preview-by-default; no Etherscan key required."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|