Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
a21e082
Audit commitment commands docs and integration test
cursoragent May 27, 2026
a1154d2
Audit doctor command docs and test surface
cursoragent May 27, 2026
5db73a4
Audit preimage commands docs and integration test
cursoragent May 27, 2026
3194da5
audit explain command docs and test coverage
cursoragent May 27, 2026
06f31fc
Audit localnet docs and add localnet parse/integration test
cursoragent May 27, 2026
f7e074c
fix explain topic count in docs
cursoragent May 27, 2026
5d7f669
Audit evm command docs and add integration parse coverage
cursoragent May 27, 2026
44184e4
Audit drand CLI docs and add integration test scaffold
cursoragent May 27, 2026
d9ee488
Audit crowdloan CLI docs and parse coverage
cursoragent May 27, 2026
f33865b
Audit scheduler docs and add scheduler audit tests
cursoragent May 27, 2026
e21fe13
Audit liquidity commands: docs refresh and parse/integration tests
cursoragent May 27, 2026
ef4f7a8
Document audit command and add integration parse tests
cursoragent May 27, 2026
01cf211
Audit subnet command docs and parser coverage
cursoragent May 27, 2026
b73bbef
Audit admin command docs and add audit_admin integration test
cursoragent May 27, 2026
8f64286
Add economy batch verifier handoff
cursoragent May 27, 2026
70bf3e3
audit(delegate): add tests/audit_delegate.rs and refresh docs/command…
cursoragent May 27, 2026
af35556
audit(config): add audit_config.rs tests and refresh config.md docs
cursoragent May 27, 2026
c416a45
audit(contracts): add green-path test suite and refresh docs
cursoragent May 27, 2026
aef04bc
audit(proxy): add parse-surface tests and refresh proxy.md docs
cursoragent May 27, 2026
3b5b15f
audit(wallet): add audit_wallet.rs integration tests and refresh wall…
cursoragent May 27, 2026
8a5c29e
audit/view: add tests/audit_view.rs and refresh docs/commands/view.md
cursoragent May 27, 2026
3da1d3c
audit(completions+update): add parse-surface tests and refresh utils.…
cursoragent May 27, 2026
935f286
audit(swap): add audit_swap_keys.rs tests and refresh swap.md docs
cursoragent May 27, 2026
86e9e4f
audit: balance/transfer command group - tests and docs
cursoragent May 27, 2026
5e91b00
audit: safe-mode — green-path tests and refreshed docs
cursoragent May 27, 2026
c91f11d
audit(identity): add parse-surface tests and refresh docs
cursoragent May 27, 2026
9b8198f
audit(batch): add tests/audit_batch.rs and refresh docs/commands/batc…
cursoragent May 27, 2026
f077eb2
audit(block): add tests/audit_block.rs and refresh docs/commands/bloc…
cursoragent May 27, 2026
005bf35
audit-subscribe: add parse-surface tests and refresh docs
cursoragent May 27, 2026
642dc57
audit(stake): add tests/audit_stake.rs and refresh docs/commands/stak…
cursoragent May 27, 2026
065348d
audit(serve): add audit_serve.rs tests and refresh serve.md docs
cursoragent May 27, 2026
53f81ae
audit(utils): add parse-surface tests + refresh utils.md docs
cursoragent May 27, 2026
2406ac7
audit(diff): add audit_diff.rs + refresh diff.md
cursoragent May 27, 2026
1a0dac3
audit(multisig): add green-path tests and refresh docs
cursoragent May 27, 2026
b434baa
audit(weights): add parse-surface tests and refresh docs
cursoragent May 27, 2026
44db616
Add readonly batch verifier handoff
cursoragent May 27, 2026
18c87b7
Add network batch verifier handoff
cursoragent May 27, 2026
a336e15
audit: root command group — tests/audit_root.rs + refreshed docs/comm…
cursoragent May 27, 2026
a7439f1
Expand explain topics for cross-command coverage
cursoragent May 27, 2026
81cfff0
Fix subscribe event mappings and stable rendering
cursoragent May 27, 2026
a1d7997
Harden error classification and dispatch fallback mapping
cursoragent May 27, 2026
44ff4f2
Fix extrinsic encoding for identity proxy and lease flows
cursoragent May 27, 2026
a0ef7be
Fix at-block query parity and pinned cache correctness
cursoragent May 27, 2026
6594aa9
fix(scaffold): TOML round-trip, deny_unknown_fields, started_at rename
cursoragent May 27, 2026
88abb2e
handoff: fix-scaffold-localnet success
cursoragent May 27, 2026
d0ea5ac
docs: sync llm.txt and hyperparameters.md with actual clap surface an…
cursoragent May 27, 2026
5209636
merge: fix-chain-extrinsics
cursoragent May 27, 2026
8a55153
merge: fix-chain-queries
cursoragent May 27, 2026
2e9b92e
merge: fix-error-mapping
cursoragent May 27, 2026
aaf5b62
merge: fix-events-pretty
cursoragent May 27, 2026
443a2d5
merge: fix-explain-topics
cursoragent May 27, 2026
c7f9ce2
merge: fix-llm-txt
cursoragent May 27, 2026
25bfeda
merge: fix-scaffold-localnet
cursoragent May 27, 2026
533423b
merge: audit-admin
cursoragent May 27, 2026
801b16d
merge: audit-audit-cmd
cursoragent May 27, 2026
c5d74a0
merge: audit-balance-transfer
cursoragent May 27, 2026
44e49bc
merge: audit-batch
cursoragent May 27, 2026
929ef5a
merge: audit-block
cursoragent May 27, 2026
6b6c4ec
merge: audit-commitment
cursoragent May 27, 2026
a0748ad
merge: audit-completions-update
cursoragent May 27, 2026
4a309dd
merge: audit-config
cursoragent May 27, 2026
d43a484
merge: audit-contracts
cursoragent May 27, 2026
7c1a518
merge: audit-crowdloan
cursoragent May 27, 2026
356f122
merge: audit-delegate
cursoragent May 27, 2026
9e7ecfc
merge: audit-diff
cursoragent May 27, 2026
aa687c2
merge: audit-doctor
cursoragent May 27, 2026
f8b7a59
merge: audit-drand
cursoragent May 27, 2026
34589bf
merge: audit-evm
cursoragent May 27, 2026
355d6b7
merge: audit-explain
cursoragent May 27, 2026
4e51bd4
merge: audit-identity
cursoragent May 27, 2026
52b0f90
merge: audit-liquidity
cursoragent May 27, 2026
32135c9
merge: audit-localnet
cursoragent May 27, 2026
b5fdfa6
merge: audit-multisig
cursoragent May 27, 2026
db6f7cc
merge: audit-preimage
cursoragent May 27, 2026
448a985
merge: audit-proxy
cursoragent May 27, 2026
27c4381
merge: audit-root
cursoragent May 27, 2026
65455cd
merge: audit-safe-mode
cursoragent May 27, 2026
d901d99
merge: audit-scheduler
cursoragent May 27, 2026
446a3c0
merge: audit-serve
cursoragent May 27, 2026
8b81ae1
merge: audit-stake
cursoragent May 27, 2026
57a8594
merge: audit-subnet
cursoragent May 27, 2026
c9ff63b
merge: audit-subscribe
cursoragent May 27, 2026
d9a891b
merge: audit-swap-keys
cursoragent May 27, 2026
67dabbd
merge: audit-utils-cli
cursoragent May 27, 2026
887b710
merge: audit-view
cursoragent May 27, 2026
4ab2873
merge: audit-wallet
cursoragent May 27, 2026
89d1e4a
merge: audit-weights
cursoragent May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 91 additions & 151 deletions docs/commands/admin.md

Large diffs are not rendered by default.

221 changes: 200 additions & 21 deletions docs/commands/batch.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,221 @@
# batch — Batch Extrinsic Submission

Submit multiple extrinsics from a JSON file. Supports atomic, non-atomic, and force modes.
Submit multiple extrinsics from a JSON file via the Substrate `Utility` pallet.
The default mode is atomic (`batch_all`): all calls succeed or all revert.

## Usage

```bash
agcli batch --file calls.json [--no-atomic] [--force] [--yes]
agcli [global-flags] batch --file <PATH> [--no-atomic] [--force]
```

## JSON Format
## Flags

| Flag | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `--file <PATH>` | `String` | **yes** | — | Path to JSON file containing the array of calls |
| `--no-atomic` | `bool` (flag) | no | `false` | Use `Utility::batch` (non-atomic) instead of `batch_all` |
| `--force` | `bool` (flag) | no | `false` | Use `Utility::force_batch` (never reverts) instead of `batch_all` |

Global flags that affect this command:

| Flag | Description |
|------|-------------|
| `--yes` / `-y` | Skip wallet-unlock confirmation prompts |
| `--output json` | Emit `{"tx_hash": "<hash>"}` to stdout instead of the default table line |
| `--batch` | Treat all missing args as hard errors (no interactive prompts) |
| `--mev` | Encrypt the extrinsic through the MEV shield before submission |
| `--network <URL>` | Override the RPC endpoint (default: Finney) |

## JSON File Format

```json
[
{"pallet": "SubtensorModule", "call": "add_stake", "args": ["5Hotkey...", 1, 1000000000]},
{"pallet": "Balances", "call": "transfer_allow_death", "args": ["5Dest...", 5000000000]},
{"pallet": "SubtensorModule", "call": "set_weights", "args": [1, [0,1], [100,200], 0]}
{
"pallet": "SubtensorModule",
"call": "add_stake",
"args": ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1, 1000000000]
},
{
"pallet": "Balances",
"call": "transfer_allow_death",
"args": ["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", 5000000000]
},
{
"pallet": "SubtensorModule",
"call": "set_weights",
"args": [1, [0, 1], [100, 200], 0]
}
]
```

- Hex strings in args (`"0xdead..."`) are auto-decoded as bytes
- Uses `submit_raw_call` for each call — any pallet/call combo works
**Required fields per call object:**

| Field | Type | Description |
|-------|------|-------------|
| `"pallet"` | string | Pallet name as registered in the runtime (e.g. `"SubtensorModule"`, `"Balances"`, `"System"`) |
| `"call"` | string | Dispatchable name in snake_case (e.g. `"add_stake"`, `"transfer_allow_death"`) |
| `"args"` | array | Positional arguments; use `[]` for no arguments |

**Argument type mapping:**

| JSON type | SCALE encoding |
|-----------|----------------|
| `number` (integer) | `u128` or `i128` depending on sign |
| `number` (float) | stringified (use integers for on-chain amounts) |
| `string` | `str` (SS58 addresses are accepted) |
| `"0x..."` string | raw bytes (hex-decoded) |
| `bool` | `bool` |
| `array` | unnamed composite sequence |

**Limits:**

- Maximum 1000 calls per batch file (enforced client-side by `validate_batch_file`).
- No minimum beyond 1 call (empty array is rejected).
- Spending limits configured in `~/.config/agcli/config.toml` are enforced per-call
for `SubtensorModule.add_stake`, `remove_stake`, `move_stake`, `swap_stake`,
`transfer_stake`, `add_stake_limit`, `remove_stake_limit`.

## Batch Modes

| Flag | Utility Call | Behavior |
|------|-------------|----------|
| (default) | `batch_all` | **Atomic**: All calls succeed or all revert |
| `--no-atomic` | `batch` | **Non-atomic**: Failed calls don't revert others, but may stop on first failure |
| `--force` | `force_batch` | **Force**: Continues execution even if individual calls fail, never reverts |
| Flag | Utility dispatchable | Behavior |
|------|---------------------|----------|
| *(none — default)* | `Utility::batch_all` | **Atomic**: all calls succeed or all revert |
| `--no-atomic` | `Utility::batch` | **Non-atomic**: stops on first failure; prior calls are not reverted |
| `--force` | `Utility::force_batch` | **Force**: continues past individual call failures; never reverts successful calls |

When both `--no-atomic` and `--force` are supplied clap accepts them without error.
The handler resolves the conflict with `force > no_atomic > default`; `--no-atomic` is
silently ignored when `--force` is also set.

## On-chain Pallet Reference

Pallet: **`Utility`** (`subtensor/pallets/utility`)

| Dispatchable | agcli surface | Notes |
|-------------|---------------|-------|
| `batch(calls)` | `--no-atomic` flag | Non-atomic, halts on first error |
| `batch_all(calls)` | default | Atomic, reverts on error |
| `force_batch(calls)` | `--force` flag | Non-atomic, continues on error |
| `as_derivative(index, call)` | **none** | No agcli surface |
| `dispatch_as(as_origin, call)` | **none** | No agcli surface |
| `with_weight(call, weight)` | **none** | No agcli surface |
| `if_else(main, fallback)` | **none** | No agcli surface |

Inner calls are encoded via `subxt::dynamic::tx(pallet, call_name, args)` →
`client.tx().call_data(…)` (SCALE-encoded `RuntimeCall` bytes), then wrapped as
`Value::from_bytes(…)` entries in the outer `Utility::{batch,batch_all,force_batch}`
payload.

### When to use each:
- **batch_all** (default): Related operations that must all succeed together
- **batch** (`--no-atomic`): Independent operations where you want to know which failed
- **force_batch** (`--force`): Best-effort execution, never reverts successful calls
## Storage Keys

## On-chain Pallet
- `Utility::batch_all` — Atomic batch
- `Utility::batch` — Non-atomic batch
- `Utility::force_batch` — Force batch (continues on failure)
The `Utility` pallet does not write any storage keys itself; all state changes are
produced by the inner calls.

## On-chain Events Emitted

After a successful submission the `Utility` pallet emits:

| Event | When |
|-------|------|
| `Utility::BatchCompleted` | All inner calls succeeded (`batch_all` / `force_batch` with no failures) |
| `Utility::BatchCompletedWithErrors` | Some calls failed in `force_batch` |
| `Utility::BatchInterrupted { index, error }` | First failing call in `batch` (non-atomic) |
| `Utility::ItemCompleted` | Emitted once per successful inner call |
| `Utility::ItemFailed { error }` | Emitted once per failing call in `force_batch` |

Inner calls emit their own pallet events normally.

## Output

**Text mode (default):**

```
Batch (3 calls) submitted. Tx: 0xabcd...
```

(Diagnostic `#N: Pallet.call (N bytes)` lines are emitted to stderr before submission.)

**JSON mode (`--output json`):**

```json
{"tx_hash": "0xabcd..."}
```

Note: the JSON output does not include `calls_count`, `mode`, or `mev_shielded`.
These are written to stderr only.

## Exit Codes

| Code | Value | Trigger condition |
|------|-------|------------------|
| `IO` | 14 | Batch file not found or unreadable (`std::io::ErrorKind::NotFound`) |
| `VALIDATION` | 12 | Malformed JSON in the batch file (`serde_json::Error` in the error chain) |
| `VALIDATION` | 12 | Invalid call argument (bad SS58 address, missing field, wrong type) |
| `CHAIN` | 13 | Extrinsic rejected by the runtime (e.g. `Utility::TooManyCalls`, insufficient balance) |
| `AUTH` | 11 | Wallet locked, wrong password, or missing hotkey |
| `NETWORK` | 10 | RPC endpoint unreachable / WebSocket error |
| `TIMEOUT` | 15 | Block finalization exceeded the deadline |
| `GENERIC` | 1 | Validation bail! messages from `validate_batch_file` that do not match classify() patterns (e.g. "too many calls", "empty", "missing field" text messages) — see Findings |

## Examples

Submit two operations atomically:

```bash
agcli --yes batch --file ops.json
```

Non-atomic — continue past failures:

```bash
agcli --yes batch --file ops.json --no-atomic
```

Force batch — never reverts:

```bash
agcli --yes batch --file ops.json --force
```

Emit JSON for programmatic use:

```bash
agcli --output json batch --file ops.json | jq .tx_hash
```

## Related Commands

- `agcli scheduler schedule` — Schedule calls for future blocks
- `agcli proxy` — Proxy calls through a proxy account
- `agcli preimage` — Pre-image a large call for scheduling

## Audit Findings (batch group)

1. **`as_derivative`, `dispatch_as`, `with_weight`, `if_else` have no agcli surface.**
Four of the seven `Utility` pallet dispatchables are not exposed. Agents that
need derivative-account dispatch or weight-capped calls must resort to raw JSON
workarounds.

2. **Both `--no-atomic` and `--force` are accepted simultaneously; `--no-atomic` is silently discarded.**
Clap declares no `conflicts_with` between the two flags. When both are set, `force`
wins silently. This is undocumented and may confuse callers.

3. **`validate_batch_file` error messages classify as GENERIC (exit 1), not VALIDATION (12).**
Client-side validation failures ("is empty", "has too many calls", "missing pallet
field", etc.) are plain `anyhow::bail!` strings. `error::classify()` does not
recognise them; they all exit 1 instead of 12, making it impossible for an agent to
distinguish input-format errors from unexpected failures.

4. **JSON output is too sparse: only `tx_hash` is emitted.**
Agents cannot determine which mode was used, how many calls were submitted, or
whether MEV shielding was applied from the JSON output alone.

5. **Diagnostic `eprintln!` calls always go to stderr regardless of `--output json`.**
Lines like `"Batch: 3 calls, mode=batch_all (atomic)"` and per-call encoding reports
are emitted to stderr unconditionally. This is correct behaviour (diagnostics on
stderr) but agents capturing combined output may be surprised.

6. **No stdin (`-`) support for the batch file.**
`--file` requires a filesystem path. There is no way to pipe a batch JSON via stdin,
unlike many UNIX tools.
Loading
Loading