primecli 0.4.0__tar.gz → 0.5.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.4.0 → primecli-0.5.1}/PKG-INFO +25 -7
- {primecli-0.4.0 → primecli-0.5.1}/README.md +23 -5
- {primecli-0.4.0 → primecli-0.5.1}/primecli/arbprime.py +91 -42
- {primecli-0.4.0 → primecli-0.5.1}/primecli/degenprime.py +19 -12
- {primecli-0.4.0 → primecli-0.5.1}/primecli/deltaprime.py +91 -44
- {primecli-0.4.0 → primecli-0.5.1}/primecli/health_monitor.py +49 -0
- {primecli-0.4.0 → primecli-0.5.1}/primecli.egg-info/PKG-INFO +25 -7
- {primecli-0.4.0 → primecli-0.5.1}/primecli.egg-info/SOURCES.txt +6 -2
- {primecli-0.4.0 → primecli-0.5.1}/primecli.egg-info/requires.txt +1 -1
- {primecli-0.4.0 → primecli-0.5.1}/pyproject.toml +2 -2
- primecli-0.5.1/tests/test_cross_file_identity.py +183 -0
- primecli-0.5.1/tests/test_gas_pricing.py +105 -0
- primecli-0.5.1/tests/test_health_monitor.py +340 -0
- primecli-0.5.1/tests/test_paraswap_validator.py +160 -0
- primecli-0.5.1/tests/test_redstone_encoding.py +71 -0
- primecli-0.5.1/tests/test_to_wei_units.py +40 -0
- primecli-0.4.0/primecli/prime-bridge.py +0 -299
- primecli-0.4.0/tests/test_redstone_encoding.py +0 -110
- {primecli-0.4.0 → primecli-0.5.1}/LICENSE +0 -0
- {primecli-0.4.0 → primecli-0.5.1}/primecli/__init__.py +0 -0
- {primecli-0.4.0 → primecli-0.5.1}/primecli.egg-info/dependency_links.txt +0 -0
- {primecli-0.4.0 → primecli-0.5.1}/primecli.egg-info/entry_points.txt +0 -0
- {primecli-0.4.0 → primecli-0.5.1}/primecli.egg-info/top_level.txt +0 -0
- {primecli-0.4.0 → primecli-0.5.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: primecli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.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
|
|
@@ -26,7 +26,7 @@ License-File: LICENSE
|
|
|
26
26
|
Requires-Dist: web3<8,>=7.0
|
|
27
27
|
Requires-Dist: eth-account>=0.13
|
|
28
28
|
Requires-Dist: eth-keys>=0.5
|
|
29
|
-
Requires-Dist: eth-abi
|
|
29
|
+
Requires-Dist: eth-abi<7,>=5.0
|
|
30
30
|
Requires-Dist: requests>=2.31
|
|
31
31
|
Dynamic: license-file
|
|
32
32
|
|
|
@@ -48,13 +48,15 @@ Built for agent use:
|
|
|
48
48
|
- RedStone-signed solvency math handled internally, with a regression test pinning the half-boundary `toFixed(8)` encoding.
|
|
49
49
|
- ParaSwap calldata validated client-side against the on-chain executor allowlist before broadcast.
|
|
50
50
|
|
|
51
|
-
**Current version:** 0.
|
|
51
|
+
**Current version:** 0.5.1 The 0.x line is pre-1.0, so breaking changes are possible. See [Releases](https://github.com/Mnemosyne-quest/primecli/releases).
|
|
52
|
+
|
|
53
|
+
> **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)).
|
|
52
54
|
|
|
53
55
|
## Security and trust
|
|
54
56
|
|
|
55
57
|
**This tool moves real on-chain funds.** Read before using.
|
|
56
58
|
|
|
57
|
-
- You manage your own private key. The tool reads it from `
|
|
59
|
+
- You manage your own private key. The tool reads it from `<TOOL>_PRIVATE_KEY` (e.g. `DELTAPRIME_PRIVATE_KEY`), or a file path you point at via `<TOOL>_KEY_FILE`, or a one-shot `--key` flag. It never writes the key anywhere. There is no default key: with nothing configured, commands fail closed.
|
|
58
60
|
- Every state-changing command **previews by default**. You must pass `--execute` to broadcast. Don't pass `--execute` until you have read the preview and understand what it is about to do.
|
|
59
61
|
- The RedStone payload, ParaSwap executor allowlist, and facet ABIs are pinned to specific on-chain state at the dates noted in the source. If DeltaPrime or DegenPrime upgrade their diamonds, the tool may need updating. Open an issue.
|
|
60
62
|
- The DeltaPrimeLabs team is not affiliated with this project. This is community-maintained tooling.
|
|
@@ -123,7 +125,7 @@ State-changing commands preview by default. Add `--execute` to broadcast.
|
|
|
123
125
|
|-------|----------|
|
|
124
126
|
| Lending core | `pool-info [--json]`, `my-positions`, `deposit`, `withdraw` (24h delayed lender flow, step 1), `withdrawal-requests`, `execute-withdrawal-request --pool X [--index N]`, `cancel-withdrawal-request --pool X --index N`, `borrow`, `repay`, `fund` |
|
|
125
127
|
| Prime Account | `create-prime-account` (alias `create-account`), `prime-summary`, `defi --json`, `withdraw-collateral`, `withdrawal-intents`, `execute-withdrawal` |
|
|
126
|
-
| Swaps | `swap --from S --to S --amount N [--via yak\|paraswap] [--slippage P]` (
|
|
128
|
+
| Swaps | `swap --from S --to S --amount N [--via yak\|paraswap] [--slippage P]` (`--via yak` default; `--via paraswap` validates the API calldata and patches a non-whitelisted executor to a known-good one before broadcast), `swap-debt --from S --to S --amount N [--slippage P]` (same ParaSwap executor handling) |
|
|
127
129
|
| GMX V2 LP (async, keeper-executed) | `gmx-positions`, `gmx-deposit --market M --amount N [--side long\|short]`, `gmx-withdraw --market M --amount N` |
|
|
128
130
|
| TraderJoe V2 LB | `lb-positions`, `lb-add --pair P --amount-x N --amount-y N [--shape spot\|curve\|bidask] [--range R]`, `lb-remove --pair P` |
|
|
129
131
|
| sJOE staking | `sjoe-position`, `sjoe-stake --amount N`, `sjoe-unstake --amount N`, `sjoe-claim` |
|
|
@@ -181,11 +183,14 @@ Note: DeltaPrime has TWO deployments on Arbitrum; `arbprime` targets the live on
|
|
|
181
183
|
| `DEGENPRIME_KEY_FILE` | falls back to `DELTAPRIME_KEY_FILE` | Path to key file for Base. |
|
|
182
184
|
| `DEGENPRIME_RPC` | `https://base.publicnode.com` | Base RPC. |
|
|
183
185
|
| `ARBPRIME_PRIVATE_KEY` | falls back to `DELTAPRIME_PRIVATE_KEY` | Your Arbitrum signing key. Same EVM key works on all three chains. |
|
|
186
|
+
| `ARBPRIME_KEY_FILE` | falls back to `DELTAPRIME_KEY_FILE` | Path to key file for Arbitrum. |
|
|
184
187
|
| `ARBPRIME_AGENT` | falls back to `DELTAPRIME_AGENT` | Named-agent key selection (multi-wallet setups). |
|
|
185
188
|
| `ARBPRIME_RPC` | `https://arb1.arbitrum.io/rpc` | Arbitrum One RPC. |
|
|
186
189
|
|
|
187
190
|
The CLI also accepts a per-command `--key <0xhex>` override that takes precedence over all env vars. Handy for one-off operations from a shell where you don't want to persist the key.
|
|
188
191
|
|
|
192
|
+
**Key resolution.** `deltaprime` and `arbprime` resolve the signing key in this order (first hit wins): `--key` > `--as <agent>` > `<TOOL>_PRIVATE_KEY` > `<TOOL>_KEY_FILE` > `<TOOL>_ENV_FILE` + `<TOOL>_KEY_VAR` > `<TOOL>_AGENT` env > error. `arbprime`'s `ARBPRIME_*` vars each fall back to the `DELTAPRIME_*` equivalent. `degenprime` is simpler — `--key` > `DEGENPRIME_PRIVATE_KEY` > `DEGENPRIME_KEY_FILE`, with `DELTAPRIME_PRIVATE_KEY` / `DELTAPRIME_KEY_FILE` as fallbacks (it has no `--as` / agent-table mechanism). If none resolve, the command exits 1 with `No signing key found...`.
|
|
193
|
+
|
|
189
194
|
A copy-paste template is at [examples/env.example](examples/env.example).
|
|
190
195
|
|
|
191
196
|
## What's covered
|
|
@@ -239,6 +244,19 @@ A copy-paste template is at [examples/env.example](examples/env.example).
|
|
|
239
244
|
| Leveraged-long zap macro | full (GM-terminal) |
|
|
240
245
|
| Penpie / Beefy / Sushi facets | not yet (live on-chain; deferred by scope) |
|
|
241
246
|
|
|
247
|
+
### PRIME bridge (`deltaprime` and `arbprime`)
|
|
248
|
+
|
|
249
|
+
Both tools expose a `prime-bridge` subcommand that moves the PRIME token between Avalanche and Arbitrum over LayerZero's OFT:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
deltaprime prime-bridge --from arb --amount 100 [--execute] # Arbitrum -> Avalanche
|
|
253
|
+
arbprime prime-bridge --from avax --amount 100 [--execute] # Avalanche -> Arbitrum
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`--from` takes `avax` or `arb` (the source chain; destination is the other one). The default `--from` differs per tool — `arb` for `deltaprime`, `avax` for `arbprime` — so always pass it explicitly. Without `--execute` it previews the LayerZero native fee, balance, and the two steps (ERC-20 approve, then `sendFrom()`); with `--execute` it broadcasts both. Gas price and `chainId` are set per the source chain.
|
|
257
|
+
|
|
258
|
+
The standalone `prime-bridge.py` script that shipped earlier was removed in 0.5.0 — the subcommand is the only supported entry point.
|
|
259
|
+
|
|
242
260
|
## Documentation
|
|
243
261
|
|
|
244
262
|
- [DeltaPrime reference](docs/deltaprime-reference.md): protocol model, addresses, facet map, RedStone integration, full command table, GMX / LB / PRIME flows.
|
|
@@ -253,7 +271,7 @@ A copy-paste template is at [examples/env.example](examples/env.example).
|
|
|
253
271
|
|
|
254
272
|
1. **Preview by default.** Every state-changing command prints a structured preview and stops unless `--execute` is passed. An agent can call any command speculatively, parse the preview, decide whether to broadcast, then re-run with `--execute`.
|
|
255
273
|
2. **Predictable, parseable stdout.** Read-only commands (`pool-info` (also `--json`), `my-positions`, `prime-summary`, `summary`, `withdrawal-intents`, `lb-positions`, `gmx-positions`, `aerodrome-positions`, `sjoe-position`, `prime-tier`, `defi --json`) emit fixed-format tables or JSON. `defi --json` is a one-shot full positions snapshot.
|
|
256
|
-
3. **Clean failure modes.** Configuration errors do not print stack traces. A missing key prints `deltaprime: No signing key found.
|
|
274
|
+
3. **Clean failure modes.** Configuration errors do not print stack traces. A missing key prints `deltaprime: No signing key found. Pass --key <0xhex> or --as <agent>, or set DELTAPRIME_PRIVATE_KEY ...` to stderr and exits 1.
|
|
257
275
|
|
|
258
276
|
Full agent integration guide (Claude Code skill template, MCP notes, recommended guardrails): [docs/agent-integration.md](docs/agent-integration.md).
|
|
259
277
|
|
|
@@ -280,7 +298,7 @@ Common failure modes and their fixes:
|
|
|
280
298
|
- **`RedStone gateway unreachable` on a read.** `prime-summary` / `summary` fall back to balances-only when the RedStone gateway is down. On `--execute` of a solvency-gated write, the call cannot proceed without a payload; wait and retry, or try the alternate gateway via the env override.
|
|
281
299
|
- **Swap fails on-chain with `InvalidExecutor`.** ParaSwap rotated an executor that is not in the tool's mirror of the on-chain allowlist. The tool patches to a known-good fallback automatically; if reverts persist, the on-chain allowlist itself has likely rotated. Open an issue.
|
|
282
300
|
- **GMX deposit reverts `InsufficientNumberOfUniqueSigners(0,3)`.** A required RedStone feed was missing from the appended payload. This was the load-bearing fix on the GMX path (24-05-2026). If you hit it on a current build, capture the tx hash and open an issue.
|
|
283
|
-
- **GMX deposit accepted but no GM minted.** The execution fee was below the keeper's threshold and the request expired (refund without mint). Re-run; the tool floors gas at
|
|
301
|
+
- **GMX deposit accepted but no GM minted.** The execution fee was below the keeper's threshold and the request expired (refund without mint). Re-run; the tool floors gas at 1 gwei (and pads 2×) in the fee estimator to clear the keeper's bar.
|
|
284
302
|
- **`createLoan` succeeded but `getLoansForOwner` returns empty.** The factory's owner→loans map lags a beat behind the receipt. The tool polls for up to 12s; rerun `my-positions` shortly after if it timed out.
|
|
285
303
|
|
|
286
304
|
If your failure is not on this list and the on-chain revert reason is opaque, capture the tx hash, the exact CLI invocation, and the preview output, and file an issue.
|
|
@@ -16,13 +16,15 @@ 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.
|
|
19
|
+
**Current version:** 0.5.1 The 0.x line is pre-1.0, so breaking changes are possible. See [Releases](https://github.com/Mnemosyne-quest/primecli/releases).
|
|
20
|
+
|
|
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)).
|
|
20
22
|
|
|
21
23
|
## Security and trust
|
|
22
24
|
|
|
23
25
|
**This tool moves real on-chain funds.** Read before using.
|
|
24
26
|
|
|
25
|
-
- You manage your own private key. The tool reads it from `
|
|
27
|
+
- You manage your own private key. The tool reads it from `<TOOL>_PRIVATE_KEY` (e.g. `DELTAPRIME_PRIVATE_KEY`), or a file path you point at via `<TOOL>_KEY_FILE`, or a one-shot `--key` flag. It never writes the key anywhere. There is no default key: with nothing configured, commands fail closed.
|
|
26
28
|
- Every state-changing command **previews by default**. You must pass `--execute` to broadcast. Don't pass `--execute` until you have read the preview and understand what it is about to do.
|
|
27
29
|
- The RedStone payload, ParaSwap executor allowlist, and facet ABIs are pinned to specific on-chain state at the dates noted in the source. If DeltaPrime or DegenPrime upgrade their diamonds, the tool may need updating. Open an issue.
|
|
28
30
|
- The DeltaPrimeLabs team is not affiliated with this project. This is community-maintained tooling.
|
|
@@ -91,7 +93,7 @@ State-changing commands preview by default. Add `--execute` to broadcast.
|
|
|
91
93
|
|-------|----------|
|
|
92
94
|
| Lending core | `pool-info [--json]`, `my-positions`, `deposit`, `withdraw` (24h delayed lender flow, step 1), `withdrawal-requests`, `execute-withdrawal-request --pool X [--index N]`, `cancel-withdrawal-request --pool X --index N`, `borrow`, `repay`, `fund` |
|
|
93
95
|
| Prime Account | `create-prime-account` (alias `create-account`), `prime-summary`, `defi --json`, `withdraw-collateral`, `withdrawal-intents`, `execute-withdrawal` |
|
|
94
|
-
| Swaps | `swap --from S --to S --amount N [--via yak\|paraswap] [--slippage P]` (
|
|
96
|
+
| Swaps | `swap --from S --to S --amount N [--via yak\|paraswap] [--slippage P]` (`--via yak` default; `--via paraswap` validates the API calldata and patches a non-whitelisted executor to a known-good one before broadcast), `swap-debt --from S --to S --amount N [--slippage P]` (same ParaSwap executor handling) |
|
|
95
97
|
| GMX V2 LP (async, keeper-executed) | `gmx-positions`, `gmx-deposit --market M --amount N [--side long\|short]`, `gmx-withdraw --market M --amount N` |
|
|
96
98
|
| TraderJoe V2 LB | `lb-positions`, `lb-add --pair P --amount-x N --amount-y N [--shape spot\|curve\|bidask] [--range R]`, `lb-remove --pair P` |
|
|
97
99
|
| sJOE staking | `sjoe-position`, `sjoe-stake --amount N`, `sjoe-unstake --amount N`, `sjoe-claim` |
|
|
@@ -149,11 +151,14 @@ Note: DeltaPrime has TWO deployments on Arbitrum; `arbprime` targets the live on
|
|
|
149
151
|
| `DEGENPRIME_KEY_FILE` | falls back to `DELTAPRIME_KEY_FILE` | Path to key file for Base. |
|
|
150
152
|
| `DEGENPRIME_RPC` | `https://base.publicnode.com` | Base RPC. |
|
|
151
153
|
| `ARBPRIME_PRIVATE_KEY` | falls back to `DELTAPRIME_PRIVATE_KEY` | Your Arbitrum signing key. Same EVM key works on all three chains. |
|
|
154
|
+
| `ARBPRIME_KEY_FILE` | falls back to `DELTAPRIME_KEY_FILE` | Path to key file for Arbitrum. |
|
|
152
155
|
| `ARBPRIME_AGENT` | falls back to `DELTAPRIME_AGENT` | Named-agent key selection (multi-wallet setups). |
|
|
153
156
|
| `ARBPRIME_RPC` | `https://arb1.arbitrum.io/rpc` | Arbitrum One RPC. |
|
|
154
157
|
|
|
155
158
|
The CLI also accepts a per-command `--key <0xhex>` override that takes precedence over all env vars. Handy for one-off operations from a shell where you don't want to persist the key.
|
|
156
159
|
|
|
160
|
+
**Key resolution.** `deltaprime` and `arbprime` resolve the signing key in this order (first hit wins): `--key` > `--as <agent>` > `<TOOL>_PRIVATE_KEY` > `<TOOL>_KEY_FILE` > `<TOOL>_ENV_FILE` + `<TOOL>_KEY_VAR` > `<TOOL>_AGENT` env > error. `arbprime`'s `ARBPRIME_*` vars each fall back to the `DELTAPRIME_*` equivalent. `degenprime` is simpler — `--key` > `DEGENPRIME_PRIVATE_KEY` > `DEGENPRIME_KEY_FILE`, with `DELTAPRIME_PRIVATE_KEY` / `DELTAPRIME_KEY_FILE` as fallbacks (it has no `--as` / agent-table mechanism). If none resolve, the command exits 1 with `No signing key found...`.
|
|
161
|
+
|
|
157
162
|
A copy-paste template is at [examples/env.example](examples/env.example).
|
|
158
163
|
|
|
159
164
|
## What's covered
|
|
@@ -207,6 +212,19 @@ A copy-paste template is at [examples/env.example](examples/env.example).
|
|
|
207
212
|
| Leveraged-long zap macro | full (GM-terminal) |
|
|
208
213
|
| Penpie / Beefy / Sushi facets | not yet (live on-chain; deferred by scope) |
|
|
209
214
|
|
|
215
|
+
### PRIME bridge (`deltaprime` and `arbprime`)
|
|
216
|
+
|
|
217
|
+
Both tools expose a `prime-bridge` subcommand that moves the PRIME token between Avalanche and Arbitrum over LayerZero's OFT:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
deltaprime prime-bridge --from arb --amount 100 [--execute] # Arbitrum -> Avalanche
|
|
221
|
+
arbprime prime-bridge --from avax --amount 100 [--execute] # Avalanche -> Arbitrum
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`--from` takes `avax` or `arb` (the source chain; destination is the other one). The default `--from` differs per tool — `arb` for `deltaprime`, `avax` for `arbprime` — so always pass it explicitly. Without `--execute` it previews the LayerZero native fee, balance, and the two steps (ERC-20 approve, then `sendFrom()`); with `--execute` it broadcasts both. Gas price and `chainId` are set per the source chain.
|
|
225
|
+
|
|
226
|
+
The standalone `prime-bridge.py` script that shipped earlier was removed in 0.5.0 — the subcommand is the only supported entry point.
|
|
227
|
+
|
|
210
228
|
## Documentation
|
|
211
229
|
|
|
212
230
|
- [DeltaPrime reference](docs/deltaprime-reference.md): protocol model, addresses, facet map, RedStone integration, full command table, GMX / LB / PRIME flows.
|
|
@@ -221,7 +239,7 @@ A copy-paste template is at [examples/env.example](examples/env.example).
|
|
|
221
239
|
|
|
222
240
|
1. **Preview by default.** Every state-changing command prints a structured preview and stops unless `--execute` is passed. An agent can call any command speculatively, parse the preview, decide whether to broadcast, then re-run with `--execute`.
|
|
223
241
|
2. **Predictable, parseable stdout.** Read-only commands (`pool-info` (also `--json`), `my-positions`, `prime-summary`, `summary`, `withdrawal-intents`, `lb-positions`, `gmx-positions`, `aerodrome-positions`, `sjoe-position`, `prime-tier`, `defi --json`) emit fixed-format tables or JSON. `defi --json` is a one-shot full positions snapshot.
|
|
224
|
-
3. **Clean failure modes.** Configuration errors do not print stack traces. A missing key prints `deltaprime: No signing key found.
|
|
242
|
+
3. **Clean failure modes.** Configuration errors do not print stack traces. A missing key prints `deltaprime: No signing key found. Pass --key <0xhex> or --as <agent>, or set DELTAPRIME_PRIVATE_KEY ...` to stderr and exits 1.
|
|
225
243
|
|
|
226
244
|
Full agent integration guide (Claude Code skill template, MCP notes, recommended guardrails): [docs/agent-integration.md](docs/agent-integration.md).
|
|
227
245
|
|
|
@@ -248,7 +266,7 @@ Common failure modes and their fixes:
|
|
|
248
266
|
- **`RedStone gateway unreachable` on a read.** `prime-summary` / `summary` fall back to balances-only when the RedStone gateway is down. On `--execute` of a solvency-gated write, the call cannot proceed without a payload; wait and retry, or try the alternate gateway via the env override.
|
|
249
267
|
- **Swap fails on-chain with `InvalidExecutor`.** ParaSwap rotated an executor that is not in the tool's mirror of the on-chain allowlist. The tool patches to a known-good fallback automatically; if reverts persist, the on-chain allowlist itself has likely rotated. Open an issue.
|
|
250
268
|
- **GMX deposit reverts `InsufficientNumberOfUniqueSigners(0,3)`.** A required RedStone feed was missing from the appended payload. This was the load-bearing fix on the GMX path (24-05-2026). If you hit it on a current build, capture the tx hash and open an issue.
|
|
251
|
-
- **GMX deposit accepted but no GM minted.** The execution fee was below the keeper's threshold and the request expired (refund without mint). Re-run; the tool floors gas at
|
|
269
|
+
- **GMX deposit accepted but no GM minted.** The execution fee was below the keeper's threshold and the request expired (refund without mint). Re-run; the tool floors gas at 1 gwei (and pads 2×) in the fee estimator to clear the keeper's bar.
|
|
252
270
|
- **`createLoan` succeeded but `getLoansForOwner` returns empty.** The factory's owner→loans map lags a beat behind the receipt. The tool polls for up to 12s; rerun `my-positions` shortly after if it timed out.
|
|
253
271
|
|
|
254
272
|
If your failure is not on this list and the on-chain revert reason is opaque, capture the tx hash, the exact CLI invocation, and the preview output, and file an issue.
|
|
@@ -234,19 +234,21 @@ ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
|
|
|
234
234
|
# every chain, so the ARBPRIME_ env vars fall back to the DELTAPRIME_ equivalents.
|
|
235
235
|
#
|
|
236
236
|
# Key resolution order (first hit wins; see resolve_private_key):
|
|
237
|
-
# 1. --
|
|
238
|
-
# 2.
|
|
239
|
-
# 3.
|
|
240
|
-
# 4.
|
|
241
|
-
# 5.
|
|
237
|
+
# 1. --key <0xhex> CLI flag -> raw 0x… key (one-off)
|
|
238
|
+
# 2. --as <agent> CLI flag -> AGENTS[<agent>]
|
|
239
|
+
# 3. ARBPRIME_PRIVATE_KEY / DELTAPRIME_PRIVATE_KEY env var -> raw 0x… key
|
|
240
|
+
# 4. ARBPRIME_KEY_FILE / DELTAPRIME_KEY_FILE env var -> path to a file with the 0x key
|
|
241
|
+
# 5. ARBPRIME_ENV_FILE+ARBPRIME_KEY_VAR / DELTAPRIME_* equivalent -> read <var> from <file>
|
|
242
|
+
# 6. ARBPRIME_AGENT / DELTAPRIME_AGENT env var -> AGENTS[<agent>]
|
|
243
|
+
# If none resolve, fail closed (no silent default key).
|
|
242
244
|
#
|
|
243
|
-
# To add another wallet: add a row to AGENTS, or
|
|
245
|
+
# To add another wallet: add a row to AGENTS, export ARBPRIME_PRIVATE_KEY, or pass --key.
|
|
244
246
|
AGENTS = {
|
|
245
247
|
"parakletos": ("/root/.openclaw/.env", "PARAKLETOS_EVM_PRIVATE_KEY"),
|
|
246
248
|
"paraklaudios": ("/root/paraklaudios/.credentials.env", "PARAKLAUDIOS_EVM_PRIVATE_KEY"),
|
|
247
249
|
}
|
|
248
|
-
DEFAULT_AGENT = "parakletos" # preserves original behavior when nothing else is set
|
|
249
250
|
_SELECTED_AGENT = None # set by the --as CLI flag in main()
|
|
251
|
+
_CLI_KEY = None # set by the --key CLI flag in main()
|
|
250
252
|
# Core protocol addresses — the LIVE Arbitrum deployment (DeploymentConstants.sol),
|
|
251
253
|
# on-chain verified 2026-06-03. The stale *TUP.json deployment (factory 0x97f4C81…)
|
|
252
254
|
# has only ETH+USDC pools — NOT used here.
|
|
@@ -658,7 +660,10 @@ def _set_gas_price(w3, tx_dict):
|
|
|
658
660
|
"""Set appropriate gas price fields for the chain, replacing the legacy gasPrice approach.
|
|
659
661
|
On EIP-1559 chains (Arbitrum, Base): sets maxFeePerGas + maxPriorityFeePerGas with a 2x
|
|
660
662
|
base-fee hedge (base + prio + 1 gwei buffer). On Avalanche (legacy): sets gasPrice at
|
|
661
|
-
2x base fee with a
|
|
663
|
+
2x base fee with a 1 gwei floor. (25 gwei was the pre-Etna C-chain minimum;
|
|
664
|
+
ACP-125 (Dec 2024) lowered the min base fee to 1 nAVAX — base now sits at ~0.01
|
|
665
|
+
nAVAX, so a 25 gwei floor overpaid ~2500x and inflated the upfront balance
|
|
666
|
+
requirement past small EOAs.)"""
|
|
662
667
|
tx_dict.pop("gasPrice", None)
|
|
663
668
|
if CHAIN_ID in (42161, 8453): # Arbitrum, Base — EIP-1559
|
|
664
669
|
base = w3.eth.gas_price
|
|
@@ -666,7 +671,22 @@ def _set_gas_price(w3, tx_dict):
|
|
|
666
671
|
tx_dict["maxFeePerGas"] = max(int(base * 2), base + prio + 10**9)
|
|
667
672
|
tx_dict["maxPriorityFeePerGas"] = prio
|
|
668
673
|
else: # Avalanche (43114) — legacy gasPrice
|
|
669
|
-
tx_dict["gasPrice"] = max(int(w3.eth.gas_price * 2),
|
|
674
|
+
tx_dict["gasPrice"] = max(int(w3.eth.gas_price * 2), 1 * 10**9)
|
|
675
|
+
|
|
676
|
+
def _set_gas_price_for(chain_id, w3, tx_dict):
|
|
677
|
+
"""Set gas fields for an EXPLICIT chain_id rather than the module CHAIN_ID. Needed by
|
|
678
|
+
cross-chain flows (prime-bridge) where a tx may target Avalanche or Arbitrum regardless
|
|
679
|
+
of which tool built it. Arbitrum/Base (EIP-1559): maxFeePerGas + maxPriorityFeePerGas;
|
|
680
|
+
Avalanche (legacy): gasPrice with a 1 gwei floor (post-Etna; see _set_gas_price)."""
|
|
681
|
+
tx_dict.pop("gasPrice", None)
|
|
682
|
+
if chain_id in (42161, 8453): # Arbitrum, Base — EIP-1559
|
|
683
|
+
base = w3.eth.gas_price
|
|
684
|
+
prio = w3.eth.max_priority_fee
|
|
685
|
+
tx_dict["maxFeePerGas"] = max(int(base * 2), base + prio + 10**9)
|
|
686
|
+
tx_dict["maxPriorityFeePerGas"] = prio
|
|
687
|
+
else: # Avalanche (43114) — legacy gasPrice
|
|
688
|
+
tx_dict["gasPrice"] = max(int(w3.eth.gas_price * 2), 1 * 10**9)
|
|
689
|
+
|
|
670
690
|
def _read_env_var(path, var):
|
|
671
691
|
"""Return the value of `var` from a KEY=VALUE env file, or None if absent."""
|
|
672
692
|
try:
|
|
@@ -693,15 +713,26 @@ def _agent_key(agent):
|
|
|
693
713
|
def resolve_private_key():
|
|
694
714
|
# The same EVM key works on every chain, so each ARBPRIME_ var falls back to its
|
|
695
715
|
# DELTAPRIME_ equivalent (exactly how degenprime falls back to DELTAPRIME_*).
|
|
696
|
-
# 1. --
|
|
716
|
+
# 1. --key <0xhex> CLI flag (set in main)
|
|
717
|
+
if _CLI_KEY:
|
|
718
|
+
return _CLI_KEY.strip()
|
|
719
|
+
# 2. --as <agent> CLI flag (set in main)
|
|
697
720
|
if _SELECTED_AGENT:
|
|
698
721
|
return _agent_key(_SELECTED_AGENT)
|
|
699
|
-
#
|
|
722
|
+
# 3. raw key directly in the environment
|
|
700
723
|
for env_var in ("ARBPRIME_PRIVATE_KEY", "DELTAPRIME_PRIVATE_KEY"):
|
|
701
724
|
raw = os.environ.get(env_var)
|
|
702
725
|
if raw:
|
|
703
726
|
return raw.strip()
|
|
704
|
-
#
|
|
727
|
+
# 4. path to a file containing the 0x key
|
|
728
|
+
for path_var in ("ARBPRIME_KEY_FILE", "DELTAPRIME_KEY_FILE"):
|
|
729
|
+
key_file = os.environ.get(path_var)
|
|
730
|
+
if key_file:
|
|
731
|
+
try:
|
|
732
|
+
return Path(key_file).read_text().strip()
|
|
733
|
+
except FileNotFoundError:
|
|
734
|
+
raise RuntimeError(f"{path_var} points at {key_file} but the file does not exist.")
|
|
735
|
+
# 5. explicit env-file + var-name
|
|
705
736
|
env_file = os.environ.get("ARBPRIME_ENV_FILE") or os.environ.get("DELTAPRIME_ENV_FILE")
|
|
706
737
|
key_var = os.environ.get("ARBPRIME_KEY_VAR") or os.environ.get("DELTAPRIME_KEY_VAR")
|
|
707
738
|
if env_file and key_var:
|
|
@@ -709,16 +740,25 @@ def resolve_private_key():
|
|
|
709
740
|
if not key:
|
|
710
741
|
raise RuntimeError(f"{key_var} not found in {env_file}.")
|
|
711
742
|
return key
|
|
712
|
-
#
|
|
743
|
+
# 6. named agent in the environment
|
|
713
744
|
agent = os.environ.get("ARBPRIME_AGENT") or os.environ.get("DELTAPRIME_AGENT")
|
|
714
745
|
if agent:
|
|
715
746
|
return _agent_key(agent)
|
|
716
|
-
#
|
|
717
|
-
|
|
747
|
+
# No silent default — fail closed.
|
|
748
|
+
raise RuntimeError(
|
|
749
|
+
"No signing key found. Pass --key <0xhex> or --as <agent>, or set "
|
|
750
|
+
"ARBPRIME_PRIVATE_KEY (raw 0x... key), ARBPRIME_KEY_FILE (path to a file with "
|
|
751
|
+
"the key), or ARBPRIME_ENV_FILE + ARBPRIME_KEY_VAR. DELTAPRIME_* equivalents "
|
|
752
|
+
"also work (same key, all chains)."
|
|
753
|
+
)
|
|
718
754
|
|
|
719
755
|
def get_account() -> Account:
|
|
720
756
|
return Account.from_key(resolve_private_key())
|
|
721
757
|
|
|
758
|
+
def to_wei_units(amount, decimals):
|
|
759
|
+
"""Convert a human amount to integer base units without float drift."""
|
|
760
|
+
return int(Decimal(str(amount)) * (10 ** int(decimals)))
|
|
761
|
+
|
|
722
762
|
def get_pool_contract(pool_name: str):
|
|
723
763
|
"""Pool proxy contract bound directly to the hand-curated POOL_ABI (no block-explorer
|
|
724
764
|
ABI fetch — Arbiscan is display-only here; the hand-curated subset covers every
|
|
@@ -1376,7 +1416,7 @@ def cmd_my_positions():
|
|
|
1376
1416
|
def cmd_deposit(pool_name: str, amount: float, execute: bool = False):
|
|
1377
1417
|
contract, cfg, w3 = get_pool_contract(pool_name)
|
|
1378
1418
|
acct = get_account()
|
|
1379
|
-
amount_wei =
|
|
1419
|
+
amount_wei = to_wei_units(amount, cfg["decimals"])
|
|
1380
1420
|
|
|
1381
1421
|
if not execute:
|
|
1382
1422
|
print(f"Preview: Deposit {amount} {cfg['symbol']} into {pool_name.upper()} pool")
|
|
@@ -1433,7 +1473,7 @@ def cmd_withdraw(pool_name: str, amount: float, execute: bool = False):
|
|
|
1433
1473
|
"""
|
|
1434
1474
|
contract, cfg, w3 = get_pool_contract(pool_name)
|
|
1435
1475
|
acct = get_account()
|
|
1436
|
-
amount_wei =
|
|
1476
|
+
amount_wei = to_wei_units(amount, cfg["decimals"])
|
|
1437
1477
|
|
|
1438
1478
|
# getBalanceOf is the lender's current deposit balance — sane upper bound for
|
|
1439
1479
|
# the intent amount. The pool reverts "Amount must be greater than zero" on 0,
|
|
@@ -1670,7 +1710,7 @@ def cmd_create_prime_account(execute: bool = False, fund_pool: str = None, fund_
|
|
|
1670
1710
|
print(f"Preview: Create a new Prime Account for {acct.address}")
|
|
1671
1711
|
if funding:
|
|
1672
1712
|
symbol = cfg["symbol"]
|
|
1673
|
-
amount_wei =
|
|
1713
|
+
amount_wei = to_wei_units(fund_amount, cfg["decimals"])
|
|
1674
1714
|
print(f" Factory: {FACTORY_PROXY} (SmartLoansFactory.createAndFundLoan())")
|
|
1675
1715
|
print(f" Approves the factory to spend {fund_amount} {symbol}, then")
|
|
1676
1716
|
print(f" calls createAndFundLoan(bytes32 '{symbol}', {amount_wei}) — creates + funds in one go.")
|
|
@@ -1683,7 +1723,7 @@ def cmd_create_prime_account(execute: bool = False, fund_pool: str = None, fund_
|
|
|
1683
1723
|
|
|
1684
1724
|
if funding:
|
|
1685
1725
|
symbol = cfg["symbol"]
|
|
1686
|
-
amount_wei =
|
|
1726
|
+
amount_wei = to_wei_units(fund_amount, cfg["decimals"])
|
|
1687
1727
|
# createAndFundLoan does token.transferFrom(msg.sender, factory, amount),
|
|
1688
1728
|
# so approve the factory first.
|
|
1689
1729
|
token = w3.eth.contract(address=Web3.to_checksum_address(cfg["token"]),
|
|
@@ -1746,7 +1786,7 @@ def cmd_fund(pool_name: str, amount: float, execute: bool = False):
|
|
|
1746
1786
|
return
|
|
1747
1787
|
|
|
1748
1788
|
symbol = pool_to_asset_symbol(pool_name)
|
|
1749
|
-
amount_wei =
|
|
1789
|
+
amount_wei = to_wei_units(amount, cfg["decimals"])
|
|
1750
1790
|
pa_cs = Web3.to_checksum_address(pa)
|
|
1751
1791
|
|
|
1752
1792
|
if not execute:
|
|
@@ -1980,7 +2020,7 @@ def cmd_borrow(pool_name: str, amount: float, execute: bool = False):
|
|
|
1980
2020
|
return
|
|
1981
2021
|
|
|
1982
2022
|
symbol = pool_to_asset_symbol(pool_name)
|
|
1983
|
-
amount_wei =
|
|
2023
|
+
amount_wei = to_wei_units(amount, cfg["decimals"])
|
|
1984
2024
|
if not execute:
|
|
1985
2025
|
print(f"Preview: Borrow {amount} {symbol} into Prime Account {pa}")
|
|
1986
2026
|
print(f" Calls borrow(bytes32 '{symbol}', {amount_wei}) on the Prime Account")
|
|
@@ -2027,7 +2067,7 @@ def cmd_repay(pool_name: str, amount: float, execute: bool = False):
|
|
|
2027
2067
|
# The facet's repay reverts if amount > debt OR amount > in-account balance.
|
|
2028
2068
|
# Cap to min(requested, debt, in_account) so callers don't need to know either
|
|
2029
2069
|
# exact figure — pass an overshoot like 9999 and it clips cleanly.
|
|
2030
|
-
requested_wei =
|
|
2070
|
+
requested_wei = to_wei_units(amount, cfg["decimals"])
|
|
2031
2071
|
debt_wei = pool.functions.getBorrowed(pa_cs).call()
|
|
2032
2072
|
in_acct_wei = account.functions.getBalance(asset_b32(symbol)).call()
|
|
2033
2073
|
if debt_wei == 0:
|
|
@@ -2297,7 +2337,7 @@ def cmd_swap(from_sym: str, to_sym: str, amount: float, slippage_pct: float = 1.
|
|
|
2297
2337
|
account = w3.eth.contract(address=pa_cs, abi=PRIME_ACCOUNT_ABI)
|
|
2298
2338
|
|
|
2299
2339
|
from_cfg, to_cfg = SWAP_ASSETS[from_sym], SWAP_ASSETS[to_sym]
|
|
2300
|
-
amount_in =
|
|
2340
|
+
amount_in = to_wei_units(amount, from_cfg["decimals"])
|
|
2301
2341
|
|
|
2302
2342
|
# In-account balance check (oracle-free view).
|
|
2303
2343
|
in_balance = account.functions.getBalance(asset_b32(from_sym)).call()
|
|
@@ -2395,7 +2435,7 @@ def _calc_swap_debt_amounts(w3, account, from_sym, to_sym, amount):
|
|
|
2395
2435
|
borrowed = from_pool.functions.getBorrowed(pa_cs).call()
|
|
2396
2436
|
if borrowed == 0:
|
|
2397
2437
|
raise ValueError("zero_old_debt")
|
|
2398
|
-
repay_amount = min(
|
|
2438
|
+
repay_amount = min(to_wei_units(amount, from_cfg["decimals"]), borrowed)
|
|
2399
2439
|
|
|
2400
2440
|
# Value-match the new borrow to the repay using the facet's own RedStone prices.
|
|
2401
2441
|
feeds = prime_account_price_feeds(account)
|
|
@@ -2749,7 +2789,7 @@ def cmd_withdraw_collateral(pool_name: str, amount: float, execute: bool = False
|
|
|
2749
2789
|
return
|
|
2750
2790
|
|
|
2751
2791
|
symbol = pool_to_asset_symbol(pool_name)
|
|
2752
|
-
amount_wei =
|
|
2792
|
+
amount_wei = to_wei_units(amount, cfg["decimals"])
|
|
2753
2793
|
pa_cs = Web3.to_checksum_address(pa)
|
|
2754
2794
|
account = w3.eth.contract(address=pa_cs, abi=PRIME_ACCOUNT_ABI)
|
|
2755
2795
|
|
|
@@ -3244,7 +3284,7 @@ def cmd_gmx_deposit(market: str, amount: float, is_long: bool | None = None,
|
|
|
3244
3284
|
pa_cs = Web3.to_checksum_address(pa)
|
|
3245
3285
|
account = w3.eth.contract(address=pa_cs, abi=PRIME_ACCOUNT_ABI)
|
|
3246
3286
|
|
|
3247
|
-
amount_wei =
|
|
3287
|
+
amount_wei = to_wei_units(amount, dep_cfg["decimals"])
|
|
3248
3288
|
in_balance = account.functions.getBalance(asset_b32(dep_sym)).call()
|
|
3249
3289
|
if amount_wei > in_balance:
|
|
3250
3290
|
print(f"Prime Account holds only {in_balance / 10**dep_cfg['decimals']:.6f} {dep_sym} "
|
|
@@ -3354,7 +3394,7 @@ def cmd_gmx_withdraw(market: str, amount: float, slippage_pct: float = 1.0,
|
|
|
3354
3394
|
gm_cs = Web3.to_checksum_address(mkt["gm_token"])
|
|
3355
3395
|
erc = json.loads('[{"inputs":[{"name":"a","type":"address"}],"name":"balanceOf","outputs":[{"type":"uint256"}],"stateMutability":"view","type":"function"}]')
|
|
3356
3396
|
gm_bal = w3.eth.contract(address=gm_cs, abi=erc).functions.balanceOf(pa_cs).call()
|
|
3357
|
-
gm_amount =
|
|
3397
|
+
gm_amount = to_wei_units(amount, GM_TOKEN_DECIMALS)
|
|
3358
3398
|
if gm_bal == 0:
|
|
3359
3399
|
print(f"Prime Account holds no {mkt['gm_feed']} GM tokens — nothing to withdraw.")
|
|
3360
3400
|
return
|
|
@@ -3600,7 +3640,7 @@ def cmd_glv_deposit(vault_key: str, amount: float, is_long: bool | None = None,
|
|
|
3600
3640
|
dep_meta = long_meta if is_long_eff else short_meta
|
|
3601
3641
|
dep_sym = dep_meta["symbol"]
|
|
3602
3642
|
|
|
3603
|
-
amount_wei =
|
|
3643
|
+
amount_wei = to_wei_units(amount, dep_meta["decimals"])
|
|
3604
3644
|
in_balance = account.functions.getBalance(asset_b32(dep_sym)).call()
|
|
3605
3645
|
if amount_wei > in_balance:
|
|
3606
3646
|
print(f"Prime Account holds only {in_balance / 10**dep_meta['decimals']:.6f} {dep_sym} "
|
|
@@ -3717,7 +3757,7 @@ def cmd_glv_withdraw(vault_key: str, amount: float, target_market: str = None,
|
|
|
3717
3757
|
glv_cs = Web3.to_checksum_address(vault["glv_token"])
|
|
3718
3758
|
erc = json.loads('[{"inputs":[{"name":"a","type":"address"}],"name":"balanceOf","outputs":[{"type":"uint256"}],"stateMutability":"view","type":"function"}]')
|
|
3719
3759
|
glv_bal = w3.eth.contract(address=glv_cs, abi=erc).functions.balanceOf(pa_cs).call()
|
|
3720
|
-
glv_amount =
|
|
3760
|
+
glv_amount = to_wei_units(amount, GLV_TOKEN_DECIMALS)
|
|
3721
3761
|
if glv_bal == 0:
|
|
3722
3762
|
print(f"Prime Account holds no [{vault_key}] GLV tokens — nothing to withdraw.")
|
|
3723
3763
|
return
|
|
@@ -4055,8 +4095,8 @@ def cmd_lb_add(pair_key: str, amount_x: float, amount_y: float, shape: str = "sp
|
|
|
4055
4095
|
pa_cs = Web3.to_checksum_address(pa)
|
|
4056
4096
|
account = w3.eth.contract(address=pa_cs, abi=PRIME_ACCOUNT_ABI)
|
|
4057
4097
|
|
|
4058
|
-
amount_x_wei =
|
|
4059
|
-
amount_y_wei =
|
|
4098
|
+
amount_x_wei = to_wei_units(amount_x, x_cfg["decimals"]) if has_x else 0
|
|
4099
|
+
amount_y_wei = to_wei_units(amount_y, y_cfg["decimals"]) if has_y else 0
|
|
4060
4100
|
|
|
4061
4101
|
# In-account balances (oracle-free), keyed by the TokenManager symbol the facet uses.
|
|
4062
4102
|
bal_x = account.functions.getBalance(asset_b32(x_cfg["symbol"])).call()
|
|
@@ -4382,7 +4422,7 @@ def cmd_prime_activate(amount: float = None, execute: bool = False):
|
|
|
4382
4422
|
print(f"Prime Account {pa} is already in PREMIUM tier — nothing to do.")
|
|
4383
4423
|
return
|
|
4384
4424
|
|
|
4385
|
-
deposit_wei =
|
|
4425
|
+
deposit_wei = to_wei_units(amount, PRIME_TOKEN["decimals"]) if amount else 0
|
|
4386
4426
|
eoa_prime = prime.functions.balanceOf(acct.address).call()
|
|
4387
4427
|
in_acct_prime = account.functions.getBalance(asset_b32(PRIME_TOKEN["symbol"])).call()
|
|
4388
4428
|
# depositPrime caps to the EOA balance on-chain; mirror that for an honest preview.
|
|
@@ -4490,7 +4530,7 @@ def cmd_prime_deposit(amount: float, execute: bool = False):
|
|
|
4490
4530
|
|
|
4491
4531
|
eoa_prime = prime.functions.balanceOf(acct.address).call()
|
|
4492
4532
|
in_acct_prime = account.functions.getBalance(asset_b32(PRIME_TOKEN["symbol"])).call()
|
|
4493
|
-
deposit_wei =
|
|
4533
|
+
deposit_wei = to_wei_units(amount, PRIME_TOKEN["decimals"])
|
|
4494
4534
|
deposit_wei = min(deposit_wei, eoa_prime) # depositPrime caps to the EOA balance on-chain
|
|
4495
4535
|
|
|
4496
4536
|
print(f"PRIME deposit into Prime Account {pa}")
|
|
@@ -4602,7 +4642,7 @@ def cmd_prime_unstake(amount: float, execute: bool = False):
|
|
|
4602
4642
|
if staked == 0:
|
|
4603
4643
|
print(f"Prime Account {pa} has no staked PRIME — nothing to unstake.")
|
|
4604
4644
|
return
|
|
4605
|
-
amount_wei =
|
|
4645
|
+
amount_wei = to_wei_units(amount, PRIME_TOKEN["decimals"])
|
|
4606
4646
|
if amount_wei > staked:
|
|
4607
4647
|
print(f"Staked PRIME is {staked / 10**PRIME_TOKEN['decimals']:,.6f}; clamping unstake to that.")
|
|
4608
4648
|
amount_wei = staked
|
|
@@ -4649,7 +4689,7 @@ def cmd_prime_repay(amount: float, execute: bool = False):
|
|
|
4649
4689
|
|
|
4650
4690
|
_tier, _staked, recorded_debt = account.functions.getLeverageTierFullInfo().call()
|
|
4651
4691
|
in_acct_prime = account.functions.getBalance(asset_b32(PRIME_TOKEN["symbol"])).call()
|
|
4652
|
-
amount_wei =
|
|
4692
|
+
amount_wei = to_wei_units(amount, PRIME_TOKEN["decimals"])
|
|
4653
4693
|
|
|
4654
4694
|
print(f"PRIME repay debt: {amount} PRIME on Prime Account {pa}")
|
|
4655
4695
|
print(f" Recorded PRIME debt: {recorded_debt / 10**PRIME_TOKEN['decimals']:,.6f} "
|
|
@@ -5141,7 +5181,7 @@ def _bridge_estimate_lz_fee(w3, src_cfg: dict, dst_lz_chain_id: int, amount_wei:
|
|
|
5141
5181
|
"stateMutability": "view", "type": "function"}])))
|
|
5142
5182
|
native, zro = ep.functions.estimateFees(
|
|
5143
5183
|
dst_lz_chain_id, Web3.to_checksum_address(src_cfg["bridge_target"]),
|
|
5144
|
-
_bridge_lz_payload(
|
|
5184
|
+
_bridge_lz_payload(get_account().address, amount_wei),
|
|
5145
5185
|
False, BRIDGE_ADAPTER_PARAMS).call()
|
|
5146
5186
|
return native, zro
|
|
5147
5187
|
|
|
@@ -5164,7 +5204,8 @@ def cmd_prime_bridge(from_chain: str = "avax", amount: float = None, execute: bo
|
|
|
5164
5204
|
dst_key = "arb" if src_key == "avax" else "avax"
|
|
5165
5205
|
src_cfg = BRIDGE_CHAIN[src_key]
|
|
5166
5206
|
dst_cfg = BRIDGE_CHAIN[dst_key]
|
|
5167
|
-
|
|
5207
|
+
src_chain_id = src_cfg["chain_id"]
|
|
5208
|
+
amount_wei = to_wei_units(amount, 18)
|
|
5168
5209
|
|
|
5169
5210
|
w3 = _bridge_w3(src_key)
|
|
5170
5211
|
acct = get_account()
|
|
@@ -5218,8 +5259,8 @@ def cmd_prime_bridge(from_chain: str = "avax", amount: float = None, execute: bo
|
|
|
5218
5259
|
"name": "approve", "outputs": [{"name": "", "type": "bool"}], "type": "function"}])))
|
|
5219
5260
|
atx = app_c.functions.approve(bridge_target, amount_wei).build_transaction(
|
|
5220
5261
|
{"from": wallet, "nonce": w3.eth.get_transaction_count(wallet),
|
|
5221
|
-
"gas": 100000, "chainId":
|
|
5222
|
-
|
|
5262
|
+
"gas": 100000, "chainId": src_chain_id})
|
|
5263
|
+
_set_gas_price_for(src_chain_id, w3, atx)
|
|
5223
5264
|
signed = acct.sign_transaction(atx)
|
|
5224
5265
|
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
|
|
5225
5266
|
_ = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
|
|
@@ -5240,8 +5281,8 @@ def cmd_prime_bridge(from_chain: str = "avax", amount: float = None, execute: bo
|
|
|
5240
5281
|
print(f" sendFrom() via LayerZero (LZ {src_cfg['lz_chain_id']} → {dst_cfg['lz_chain_id']})...")
|
|
5241
5282
|
tx = {"from": wallet, "to": bridge_target, "data": bytes.fromhex(calldata_hex),
|
|
5242
5283
|
"nonce": w3.eth.get_transaction_count(wallet), "gas": 500000,
|
|
5243
|
-
"value": native_fee, "chainId":
|
|
5244
|
-
|
|
5284
|
+
"value": native_fee, "chainId": src_chain_id}
|
|
5285
|
+
_set_gas_price_for(src_chain_id, w3, tx)
|
|
5245
5286
|
signed = acct.sign_transaction(tx)
|
|
5246
5287
|
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
|
|
5247
5288
|
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=300)
|
|
@@ -5252,7 +5293,7 @@ def cmd_prime_bridge(from_chain: str = "avax", amount: float = None, execute: bo
|
|
|
5252
5293
|
def main():
|
|
5253
5294
|
args = sys.argv[1:] if len(sys.argv) > 1 else []
|
|
5254
5295
|
# Global wallet selector: --as <agent>, stripped before command dispatch.
|
|
5255
|
-
global _SELECTED_AGENT
|
|
5296
|
+
global _SELECTED_AGENT, _CLI_KEY
|
|
5256
5297
|
if "--as" in args:
|
|
5257
5298
|
i = args.index("--as")
|
|
5258
5299
|
if i + 1 >= len(args):
|
|
@@ -5260,6 +5301,14 @@ def main():
|
|
|
5260
5301
|
return
|
|
5261
5302
|
_SELECTED_AGENT = args[i + 1]
|
|
5262
5303
|
del args[i:i + 2]
|
|
5304
|
+
# Global signing-key override: --key <0xhex>, stripped before command dispatch.
|
|
5305
|
+
if "--key" in args:
|
|
5306
|
+
i = args.index("--key")
|
|
5307
|
+
if i + 1 >= len(args):
|
|
5308
|
+
print("--key requires a hex key. Example: --key 0xabc...")
|
|
5309
|
+
return
|
|
5310
|
+
_CLI_KEY = args[i + 1]
|
|
5311
|
+
del args[i:i + 2]
|
|
5263
5312
|
if not args or args[0] in ("-h", "--help"):
|
|
5264
5313
|
print(__doc__)
|
|
5265
5314
|
return
|