primecli 0.8.0__tar.gz → 0.8.1__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.8.0 → primecli-0.8.1}/PKG-INFO +2 -2
- {primecli-0.8.0 → primecli-0.8.1}/README.md +1 -1
- {primecli-0.8.0 → primecli-0.8.1}/primecli/degenprime.py +104 -82
- {primecli-0.8.0 → primecli-0.8.1}/primecli.egg-info/PKG-INFO +2 -2
- {primecli-0.8.0 → primecli-0.8.1}/pyproject.toml +1 -1
- {primecli-0.8.0 → primecli-0.8.1}/LICENSE +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli/__init__.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli/arbprime.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli/deltaprime.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli/health_monitor.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli.egg-info/SOURCES.txt +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli.egg-info/dependency_links.txt +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli.egg-info/entry_points.txt +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli.egg-info/requires.txt +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/primecli.egg-info/top_level.txt +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/setup.cfg +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_cross_file_identity.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_gas_limit.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_gas_pricing.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_health_meter.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_health_monitor.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_paraswap_validator.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/tests/test_redstone_encoding.py +0 -0
- {primecli-0.8.0 → primecli-0.8.1}/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.8.
|
|
3
|
+
Version: 0.8.1
|
|
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
|
|
@@ -47,7 +47,7 @@ Built for agent use:
|
|
|
47
47
|
- RedStone-signed solvency math handled internally, with a regression test pinning the half-boundary `toFixed(8)` encoding.
|
|
48
48
|
- ParaSwap calldata validated client-side against the on-chain executor allowlist before broadcast.
|
|
49
49
|
|
|
50
|
-
**Current version:** 0.8.
|
|
50
|
+
**Current version:** 0.8.1 The 0.x line is pre-1.0, so breaking changes are possible. See [Releases](https://github.com/Mnemosyne-quest/primecli/releases).
|
|
51
51
|
|
|
52
52
|
> **Breaking change in 0.5.0:** there is no longer a default signing key. Earlier versions silently fell back to a baked-in agent when no key was configured; that fallback has been removed. With no key configured, every command now fails closed with `No signing key found...`. Set a key explicitly (see [Configuration](#configuration)).
|
|
53
53
|
|
|
@@ -16,7 +16,7 @@ Built for agent use:
|
|
|
16
16
|
- RedStone-signed solvency math handled internally, with a regression test pinning the half-boundary `toFixed(8)` encoding.
|
|
17
17
|
- ParaSwap calldata validated client-side against the on-chain executor allowlist before broadcast.
|
|
18
18
|
|
|
19
|
-
**Current version:** 0.8.
|
|
19
|
+
**Current version:** 0.8.1 The 0.x line is pre-1.0, so breaking changes are possible. See [Releases](https://github.com/Mnemosyne-quest/primecli/releases).
|
|
20
20
|
|
|
21
21
|
> **Breaking change in 0.5.0:** there is no longer a default signing key. Earlier versions silently fell back to a baked-in agent when no key was configured; that fallback has been removed. With no key configured, every command now fails closed with `No signing key found...`. Set a key explicitly (see [Configuration](#configuration)).
|
|
22
22
|
|
|
@@ -27,7 +27,7 @@ Usage:
|
|
|
27
27
|
degenprime cancel-withdrawal --pool usdc --index N [--execute]
|
|
28
28
|
degenprime aerodrome-positions
|
|
29
29
|
degenprime aero-add-liquidity --pool weth-usdc-100 --amount-weth 0.05 --amount-usdc 100 [--slippage 1] [--execute]
|
|
30
|
-
degenprime aero-remove-liquidity --token-id N [--
|
|
30
|
+
degenprime aero-remove-liquidity --token-id N [--token-id M ...] [--execute] (full close only)
|
|
31
31
|
degenprime aero-collect-fees --token-id N [--execute]
|
|
32
32
|
|
|
33
33
|
Configuration (env vars):
|
|
@@ -85,6 +85,13 @@ the Aerodrome Slipstream NonfungiblePositionManager through the Degen Account's
|
|
|
85
85
|
AerodromeFacet wrapper functions. The facet selectors were determined via on-chain
|
|
86
86
|
probing (Diamond Loupe) of the smart-loan diamond; function names are inferred from
|
|
87
87
|
their parameter layouts and revert signatures.
|
|
88
|
+
|
|
89
|
+
aero-remove-liquidity fully closes one or more staked positions in a single call via
|
|
90
|
+
batchRemoveStakedLiquidityAerodrome(uint256[]) (selector 0x27bed82e): per tokenId it
|
|
91
|
+
unstakes from the gauge, removes all liquidity, collects fees, and burns the NFT. There
|
|
92
|
+
is no partial/percentage decrease on this path — it always closes 100%. The call is
|
|
93
|
+
solvency-gated, so the calldata carries a RedStone payload (verified byte-exact against
|
|
94
|
+
the manual close 0x0d65...0a50).
|
|
88
95
|
"""
|
|
89
96
|
|
|
90
97
|
import json, os, sys, time, base64
|
|
@@ -208,14 +215,13 @@ AERODROME_NPM = "0x827922686190790b37229fd06084350E74485b72"
|
|
|
208
215
|
# 6f2845cd getOwnedStakedAerodromeTokenIds()
|
|
209
216
|
# b6626971 getPositionCompositionSimplified(uint256) -> (address,address,uint256,uint256)
|
|
210
217
|
# 121350b3 (view, takes uint256 — detailed position info, unknown return)
|
|
211
|
-
# 27bed82e (
|
|
218
|
+
# 27bed82e batchRemoveStakedLiquidityAerodrome(uint256[]) — full close per id
|
|
219
|
+
# (verified byte-exact vs manual close 0x0d65...0a50, 2026-06-14)
|
|
212
220
|
# 2c710777 (write, onlyOwner, takes IncreaseLiquidityParams-like tuple — inferred increase)
|
|
213
|
-
# ca15558b (write, takes DecreaseLiquidityParams tuple 5-field — matches decreaseLiquidity)
|
|
214
221
|
# 92b5a47e (write, takes uint256 tokenId, checks position exists — burn/collect)
|
|
215
222
|
# 46daca2c (write, onlyOwnerOrLiquidator — emergency withdrawal)
|
|
216
223
|
AERODROME_SEL_MINT = bytes.fromhex("f32f1e56") # mintAndStakeLiquidityAerodrome
|
|
217
224
|
AERODROME_SEL_INCREASE = bytes.fromhex("2c710777") # inferred: increaseLiquidity
|
|
218
|
-
AERODROME_SEL_DECREASE = bytes.fromhex("cb16b6c6") # decreaseAerodromeLiquidity
|
|
219
225
|
AERODROME_SEL_BURN = bytes.fromhex("27bed82e") # batchRemoveStakedLiquidityAerodrome
|
|
220
226
|
AERODROME_SEL_COLLECT = bytes.fromhex("887e4b7e") # collectAerodromeFees
|
|
221
227
|
|
|
@@ -801,19 +807,6 @@ PRIME_ACCOUNT_ABI = [
|
|
|
801
807
|
]}],
|
|
802
808
|
"name": "mintAerodrome", "outputs": [],
|
|
803
809
|
"stateMutability": "nonpayable", "type": "function"},
|
|
804
|
-
# decreaseAerodromeLiquidity: wraps NPM.decreaseLiquidity(DecreaseLiquidityParams).
|
|
805
|
-
# DecreaseLiquidityParams = (uint256 tokenId, uint128 liquidity,
|
|
806
|
-
# uint256 amount0Min, uint256 amount1Min, uint256 deadline).
|
|
807
|
-
# Selector: 0xca15558b (probed — accepts 5-field tuple matching decrease layout).
|
|
808
|
-
{"inputs": [{"name": "params", "type": "tuple", "components": [
|
|
809
|
-
{"name": "tokenId", "type": "uint256"},
|
|
810
|
-
{"name": "liquidity", "type": "uint128"},
|
|
811
|
-
{"name": "amount0Min", "type": "uint256"},
|
|
812
|
-
{"name": "amount1Min", "type": "uint256"},
|
|
813
|
-
{"name": "deadline", "type": "uint256"}
|
|
814
|
-
]}],
|
|
815
|
-
"name": "decreaseAerodromeLiquidity", "outputs": [],
|
|
816
|
-
"stateMutability": "nonpayable", "type": "function"},
|
|
817
810
|
# burnAerodromePosition: wraps NPM.burn(uint256). tokenId must have 0 liquidity
|
|
818
811
|
# and all fees collected.
|
|
819
812
|
# Selector: 0x92b5a47e (probed — takes uint256, checks position exists via NPM.positions).
|
|
@@ -3133,10 +3126,17 @@ def cmd_aerodrome_positions():
|
|
|
3133
3126
|
token0, token1, tick_lower, tick_upper, liq = pos
|
|
3134
3127
|
sym0 = _resolve_token_symbol(w3, token0)
|
|
3135
3128
|
sym1 = _resolve_token_symbol(w3, token1)
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3129
|
+
# Human price = token1 per token0 = 1.0001**tick * 10**(dec0 - dec1).
|
|
3130
|
+
dec0 = _resolve_token_decimals(w3, token0)
|
|
3131
|
+
dec1 = _resolve_token_decimals(w3, token1)
|
|
3132
|
+
if dec0 is not None and dec1 is not None:
|
|
3133
|
+
scale = 10 ** (dec0 - dec1)
|
|
3134
|
+
price_lower = 1.0001 ** tick_lower * scale
|
|
3135
|
+
price_upper = 1.0001 ** tick_upper * scale
|
|
3136
|
+
print(f" [{tid}] {sym0}/{sym1} ticks=[{tick_lower}, {tick_upper}]"
|
|
3137
|
+
f" liq={liq} price_range=[{price_lower:.6g}, {price_upper:.6g}] ({sym1}/{sym0})")
|
|
3138
|
+
else:
|
|
3139
|
+
print(f" [{tid}] {sym0}/{sym1} ticks=[{tick_lower}, {tick_upper}] liq={liq}")
|
|
3140
3140
|
print(" Manage on Aerodrome UI: https://aerodrome.finance/positions")
|
|
3141
3141
|
|
|
3142
3142
|
def _aero_read_position(w3, token_id: int):
|
|
@@ -3197,6 +3197,25 @@ def _resolve_token_symbol(w3, addr: str) -> str:
|
|
|
3197
3197
|
pass
|
|
3198
3198
|
return addr[:10] + "..."
|
|
3199
3199
|
|
|
3200
|
+
_ERC20_DECIMALS_ABI = json.dumps([{"inputs": [], "name": "decimals",
|
|
3201
|
+
"outputs": [{"type": "uint8"}], "stateMutability": "view", "type": "function"}])
|
|
3202
|
+
|
|
3203
|
+
def _resolve_token_decimals(w3, addr: str):
|
|
3204
|
+
"""Token decimals from the static pool maps, falling back to an on-chain
|
|
3205
|
+
decimals() read. Returns the int decimals or None if it can't be determined."""
|
|
3206
|
+
addr_lower = addr.lower()
|
|
3207
|
+
for cfg in AERODROME_POOLS.values():
|
|
3208
|
+
if cfg["token0"].lower() == addr_lower:
|
|
3209
|
+
return cfg["decimals0"]
|
|
3210
|
+
if cfg["token1"].lower() == addr_lower:
|
|
3211
|
+
return cfg["decimals1"]
|
|
3212
|
+
try:
|
|
3213
|
+
c = w3.eth.contract(address=Web3.to_checksum_address(addr),
|
|
3214
|
+
abi=json.loads(_ERC20_DECIMALS_ABI))
|
|
3215
|
+
return c.functions.decimals().call()
|
|
3216
|
+
except Exception:
|
|
3217
|
+
return None
|
|
3218
|
+
|
|
3200
3219
|
# ─── Aerodrome Write Commands ────────────────────────────────────────────────
|
|
3201
3220
|
|
|
3202
3221
|
# Helper: get Aerodrome CL pool address from the factory's getPool (authoritative).
|
|
@@ -3307,12 +3326,6 @@ def _aero_mint_params(pool_cfg: dict, amount0_wei: int, amount1_wei: int,
|
|
|
3307
3326
|
0, 0, 0, # word11-13: zero (sqrtPriceX96=0 / bools false)
|
|
3308
3327
|
)
|
|
3309
3328
|
|
|
3310
|
-
# Helper: build DecreaseLiquidityParams tuple (5 fields).
|
|
3311
|
-
def _aero_decrease_params(token_id: int, liquidity: int,
|
|
3312
|
-
amount0_min: int, amount1_min: int) -> tuple:
|
|
3313
|
-
deadline = int(time.time()) + 1800
|
|
3314
|
-
return (token_id, liquidity, amount0_min, amount1_min, deadline)
|
|
3315
|
-
|
|
3316
3329
|
# Helper: compute tick range around a desired centre price.
|
|
3317
3330
|
def _aero_tick_range(tick_spacing: int, centre_price: float = None,
|
|
3318
3331
|
width_pct: float = 2.0, pool_tick: int = None) -> tuple:
|
|
@@ -3468,15 +3481,31 @@ def cmd_aero_add_liquidity(pool_key: str, amount0: float = None,
|
|
|
3468
3481
|
ok = receipt["status"] == 1
|
|
3469
3482
|
|
|
3470
3483
|
|
|
3471
|
-
def cmd_aero_remove_liquidity(
|
|
3484
|
+
def cmd_aero_remove_liquidity(token_ids, percentage: float = 100.0,
|
|
3472
3485
|
execute: bool = False):
|
|
3473
|
-
"""
|
|
3474
|
-
Degen Account
|
|
3475
|
-
|
|
3476
|
-
|
|
3486
|
+
"""Fully close one or more staked Aerodrome Slipstream positions owned by the
|
|
3487
|
+
Degen Account, via batchRemoveStakedLiquidityAerodrome(uint256[]) on the
|
|
3488
|
+
AerodromeFacet (selector 0x27bed82e). This single call does the FULL unwind per
|
|
3489
|
+
tokenId: unstake from the gauge + remove all liquidity + collect fees + burn the
|
|
3490
|
+
NFT (the manual reference close 0x0d65... emitted 41 logs doing exactly this).
|
|
3491
|
+
|
|
3492
|
+
There is NO partial/percentage decrease on this path — it always closes 100%.
|
|
3493
|
+
The call is remainsSolvent-gated, so the calldata carries a RedStone signed-price
|
|
3494
|
+
payload (same construction as the mint+stake path)."""
|
|
3495
|
+
if percentage < 100:
|
|
3496
|
+
print(f" Partial removal ({percentage}%) is not supported on this path — "
|
|
3497
|
+
f"batchRemoveStakedLiquidityAerodrome fully closes each position "
|
|
3498
|
+
f"(unstake + remove + collect + burn). Re-run without --percentage "
|
|
3499
|
+
f"(or with --percentage 100) to fully close.")
|
|
3500
|
+
return
|
|
3501
|
+
|
|
3502
|
+
if isinstance(token_ids, int):
|
|
3503
|
+
token_ids = [token_ids]
|
|
3504
|
+
token_ids = [int(t) for t in token_ids]
|
|
3505
|
+
if not token_ids:
|
|
3506
|
+
print(" No tokenIds supplied.")
|
|
3507
|
+
return
|
|
3477
3508
|
|
|
3478
|
-
The facet wraps NPM.decreaseLiquidity. No RedStone payload needed
|
|
3479
|
-
(the decrease path is NOT remainsSolvent — same as TJ lb-remove)."""
|
|
3480
3509
|
w3 = get_w3()
|
|
3481
3510
|
acct = get_account()
|
|
3482
3511
|
print(f"Wallet: {acct.address}")
|
|
@@ -3487,41 +3516,33 @@ def cmd_aero_remove_liquidity(token_id: int, percentage: float = 100.0,
|
|
|
3487
3516
|
account = w3.eth.contract(address=Web3.to_checksum_address(pa), abi=PRIME_ACCOUNT_ABI)
|
|
3488
3517
|
print(f"Degen Account: {pa}")
|
|
3489
3518
|
|
|
3490
|
-
#
|
|
3491
|
-
# staked
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
sym0 = _resolve_token_symbol(w3, token0)
|
|
3503
|
-
sym1 = _resolve_token_symbol(w3, token1)
|
|
3504
|
-
|
|
3505
|
-
remove_liq = int(Decimal(str(current_liq)) * Decimal(str(percentage)) / Decimal(100))
|
|
3506
|
-
if remove_liq <= 0:
|
|
3507
|
-
print(f" Removal percentage {percentage}% yields 0 liquidity.")
|
|
3508
|
-
return
|
|
3509
|
-
|
|
3510
|
-
print(f"Position {token_id}: {sym0}/{sym1} ticks=[{tick_lower},{tick_upper}]")
|
|
3511
|
-
print(f" Current liquidity: {current_liq}")
|
|
3512
|
-
print(f" Removing: {remove_liq} ({percentage}%)")
|
|
3519
|
+
# Show what each position holds before closing (NPM.positions() is correct for
|
|
3520
|
+
# staked NFTs, which the simplified facet view reports as 0 liquidity).
|
|
3521
|
+
for tid in token_ids:
|
|
3522
|
+
pos = _aero_read_position(w3, tid)
|
|
3523
|
+
if pos is None:
|
|
3524
|
+
print(f" Position {tid}: cannot read (may not exist).")
|
|
3525
|
+
continue
|
|
3526
|
+
token0, token1, tick_lower, tick_upper, current_liq = pos
|
|
3527
|
+
sym0 = _resolve_token_symbol(w3, token0)
|
|
3528
|
+
sym1 = _resolve_token_symbol(w3, token1)
|
|
3529
|
+
print(f"Position {tid}: {sym0}/{sym1} ticks=[{tick_lower},{tick_upper}] "
|
|
3530
|
+
f"liquidity={current_liq}")
|
|
3513
3531
|
|
|
3514
|
-
|
|
3515
|
-
#
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3532
|
+
# Encode batchRemoveStakedLiquidityAerodrome(uint256[] tokenIds) and append the
|
|
3533
|
+
# RedStone payload raw. Byte-for-byte layout (selector + uint256[] head + payload)
|
|
3534
|
+
# verified against the manual close 0x0d65...0a50.
|
|
3535
|
+
from eth_abi import encode as abi_encode
|
|
3536
|
+
encoded_ids = abi_encode(['uint256[]'], [token_ids])
|
|
3537
|
+
feeds = sorted(REDSTONE_AVAILABLE_FEEDS)
|
|
3538
|
+
payload = build_redstone_payload(feeds)
|
|
3539
|
+
close_calldata = AERODROME_SEL_BURN + encoded_ids + payload
|
|
3519
3540
|
|
|
3520
|
-
# Pre-flight eth_call simulation — refuse to broadcast on revert. The
|
|
3521
|
-
#
|
|
3541
|
+
# Pre-flight eth_call simulation — refuse to broadcast on revert. The close path
|
|
3542
|
+
# IS RedStone-gated, so the simulated calldata already carries the payload.
|
|
3522
3543
|
try:
|
|
3523
3544
|
w3.eth.call({"from": acct.address, "to": account.address,
|
|
3524
|
-
"data": "0x" +
|
|
3545
|
+
"data": "0x" + close_calldata.hex()})
|
|
3525
3546
|
except Exception as e:
|
|
3526
3547
|
print(f" Simulation reverted — aborting before broadcast: {type(e).__name__}: {str(e)[:200]}")
|
|
3527
3548
|
return
|
|
@@ -3535,15 +3556,15 @@ def cmd_aero_remove_liquidity(token_id: int, percentage: float = 100.0,
|
|
|
3535
3556
|
"from": acct.address,
|
|
3536
3557
|
"to": account.address,
|
|
3537
3558
|
"nonce": w3.eth.get_transaction_count(acct.address),
|
|
3538
|
-
"gas":
|
|
3559
|
+
"gas": 5000000,
|
|
3539
3560
|
"chainId": CHAIN_ID,
|
|
3540
|
-
"data": "0x" +
|
|
3561
|
+
"data": "0x" + close_calldata.hex(),
|
|
3541
3562
|
}
|
|
3542
|
-
receipt = _sign_and_send(w3, acct, tx, "
|
|
3563
|
+
receipt = _sign_and_send(w3, acct, tx, "Close Aerodrome position(s)", timeout=300, fallback_gas=5000000)
|
|
3543
3564
|
ok = receipt["status"] == 1
|
|
3544
|
-
if ok
|
|
3545
|
-
|
|
3546
|
-
print(f"
|
|
3565
|
+
if ok:
|
|
3566
|
+
ids_str = ", ".join(str(t) for t in token_ids)
|
|
3567
|
+
print(f" Fully closed (unstaked + removed + collected + burned): {ids_str}")
|
|
3547
3568
|
|
|
3548
3569
|
|
|
3549
3570
|
def cmd_aero_collect_fees(token_id: int, execute: bool = False):
|
|
@@ -3563,13 +3584,13 @@ def cmd_aero_collect_fees(token_id: int, execute: bool = False):
|
|
|
3563
3584
|
account = w3.eth.contract(address=Web3.to_checksum_address(pa), abi=PRIME_ACCOUNT_ABI)
|
|
3564
3585
|
print(f"Degen Account: {pa}")
|
|
3565
3586
|
|
|
3566
|
-
# Read position
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
print(f" Cannot read position {token_id}
|
|
3587
|
+
# Read position for display via NPM.positions() — correct for staked NFTs (the
|
|
3588
|
+
# simplified facet view reports liquidity=0 once the gauge owns the NFT).
|
|
3589
|
+
pos = _aero_read_position(w3, token_id)
|
|
3590
|
+
if pos is None:
|
|
3591
|
+
print(f" Cannot read position {token_id}.")
|
|
3571
3592
|
return
|
|
3572
|
-
token0, token1,
|
|
3593
|
+
token0, token1, tick_lower, tick_upper, liq = pos
|
|
3573
3594
|
sym0 = _resolve_token_symbol(w3, token0)
|
|
3574
3595
|
sym1 = _resolve_token_symbol(w3, token1)
|
|
3575
3596
|
print(f"Position {token_id}: {sym0}/{sym1} liquidity={liq}")
|
|
@@ -3830,16 +3851,17 @@ def _dispatch():
|
|
|
3830
3851
|
return
|
|
3831
3852
|
cmd_aero_add_liquidity(pool_key, amt0, amt1, slippage, execute, width)
|
|
3832
3853
|
elif cmd == "aero-remove-liquidity":
|
|
3833
|
-
|
|
3854
|
+
token_ids = []
|
|
3834
3855
|
percentage = 100.0
|
|
3835
3856
|
execute = "--execute" in args
|
|
3836
3857
|
for i, a in enumerate(args):
|
|
3837
|
-
if a == "--token-id" and i + 1 < len(args):
|
|
3858
|
+
if a == "--token-id" and i + 1 < len(args): token_ids.append(int(args[i + 1]))
|
|
3838
3859
|
if a == "--percentage" and i + 1 < len(args): percentage = float(args[i + 1])
|
|
3839
|
-
if
|
|
3840
|
-
print("Usage: degenprime aero-remove-liquidity --token-id N [--
|
|
3860
|
+
if not token_ids:
|
|
3861
|
+
print("Usage: degenprime aero-remove-liquidity --token-id N [--token-id M ...] [--execute]")
|
|
3862
|
+
print(" Fully closes (unstake + remove + collect + burn) each staked position. Full close only.")
|
|
3841
3863
|
return
|
|
3842
|
-
cmd_aero_remove_liquidity(
|
|
3864
|
+
cmd_aero_remove_liquidity(token_ids, percentage, execute)
|
|
3843
3865
|
elif cmd == "aero-collect-fees":
|
|
3844
3866
|
token_id = None
|
|
3845
3867
|
execute = "--execute" in args
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: primecli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
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
|
|
@@ -47,7 +47,7 @@ Built for agent use:
|
|
|
47
47
|
- RedStone-signed solvency math handled internally, with a regression test pinning the half-boundary `toFixed(8)` encoding.
|
|
48
48
|
- ParaSwap calldata validated client-side against the on-chain executor allowlist before broadcast.
|
|
49
49
|
|
|
50
|
-
**Current version:** 0.8.
|
|
50
|
+
**Current version:** 0.8.1 The 0.x line is pre-1.0, so breaking changes are possible. See [Releases](https://github.com/Mnemosyne-quest/primecli/releases).
|
|
51
51
|
|
|
52
52
|
> **Breaking change in 0.5.0:** there is no longer a default signing key. Earlier versions silently fell back to a baked-in agent when no key was configured; that fallback has been removed. With no key configured, every command now fails closed with `No signing key found...`. Set a key explicitly (see [Configuration](#configuration)).
|
|
53
53
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "primecli"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.1"
|
|
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
|
|
File without changes
|
|
File without changes
|