Skip to content

Commit 51ec0f0

Browse files
committed
docs(rpc): clarify paid RPC modes
1 parent b41000a commit 51ec0f0

3 files changed

Lines changed: 274 additions & 122 deletions

File tree

‎src/commands/agent/context.md‎

Lines changed: 116 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -145,86 +145,66 @@ Top-level nouns (plurals like `endpoints`/`streams` and `ls` are accepted aliase
145145
available keys. Custom endpoint: `--endpoint-url <URL>` (or `[rpc] endpoint_url`
146146
in config) sends the call to a fully-formed HTTP URL that authenticates itself
147147
(no token minted); it's mutually exclusive with `--network`.
148-
**Paid lane**: `--x402` (EVM/Solana stablecoin) or `--mpp` (Tempo) pays for
149-
the call per request with a crypto micropayment instead of an API key — no
150-
login, no Tooling Access. Requires `--network` as the payment gateway's path
151-
slug (e.g. `base-sepolia`; NOT validated by `list-networks`). Parameters:
152-
`--payment-network <NETWORK>` (the chain the payment settles on — independent of
153-
`--network`; a network name like `base-sepolia`/`solana-devnet`/`tempo-testnet`,
154-
or a raw CAIP-2 id like `eip155:84532`, which always passes through
155-
verbatim), `--payment-asset <ADDRESS>` (a token contract/mint, or the symbol
156-
`USDC`, resolved to that network's address), `--max-amount <BASE_UNITS>` (spend ceiling
157-
per call, integer base units, no default), and the private key via
158-
`--payment-key-file <PATH|->` > `--payment-wallet <NAME>` > `key_file` >
159-
`wallet` under `[rpc.payment]` in config. The key always comes from a file
160-
or a stored wallet — never an env var and never a raw key on the command
161-
line. All parameters fall back to `[rpc.payment]`, but config never
162-
activates payment by itself: the scheme flag is always required. `--receipt`
163-
wraps stdout as `{"result": ..., "payment_receipt": ...}` (on MPP an object
164-
whose `reference` is the settlement tx hash; `null` on x402); without it the
165-
paid output shape is identical to an unpaid call.
166-
Mutually exclusive with `--endpoint-url`.
167-
**Wallets**: stored payment wallets are managed by the top-level `qn wallet`
168-
noun (see below); reference one on a paid call with `--payment-wallet <NAME>`.
169-
**Discovery** (per gateway, no API key): `qn rpc {x402,mpp}
170-
supported-networks` (alias `networks`) lists the networks you can make paid
171-
calls to — each slug is a valid `--network`. `qn rpc {x402,mpp}
172-
supported-payments` (alias `payments`) lists the payment options the gateway
173-
accepts — each row's network/address pair is a ready
174-
`--payment-network`/`--payment-asset`.
175-
**x402 drawdown**: `qn rpc x402 {buy-credits, balance, drip}` manages prepaid
176-
gateway credits instead of paying per request. EVM payment networks use SIWE;
177-
Solana payment networks use SIWS with Base58 Ed25519 signatures. `qn rpc call
178-
--x402-drawdown` spends them (no per-call signing, 1 credit per successful
179-
response). `buy-credits` selects the largest regular x402 offer for the credit
180-
block. `GatewayWalletBatched` is the separate Circle Gateway nanopayment
181-
option, not the credit offer; it requires USDC deposited in the Circle Gateway
182-
wallet contract and is not used by `buy-credits`. `--x402` pays per request.
183-
`buy-credits` signs a payment, so it takes the full paid-lane
184-
stack (`--payment-wallet`/`-key-file`, `--payment-network`, `--payment-asset`,
185-
`--max-amount`, `--svm-rpc-url`); `balance` and `drip` only present a Bearer
186-
session JWT and sign nothing, so they take just the wallet +
187-
`--payment-network` (+ `--svm-rpc-url` for Solana) and do NOT accept
188-
`--payment-asset`/`--max-amount`. All fall back to `[rpc.payment]`.
189-
`--x402-drawdown` requires `--network` (the query chain) and a wallet only —
190-
it signs nothing per call, so `--payment-asset`/`--max-amount` aren't needed
191-
and the pay network defaults to `--network`; mutually exclusive with
192-
`--x402`/`--mpp`/`--endpoint-url`. `buy-credits` takes `--network` (the
193-
gateway path chain the purchase settles on), SIWX-authenticates, then pays the
194-
gateway's credit offer (gated Mild — `--yes`, or exit 5 in scripts — and names
195-
the spend ceiling); `balance` (alias
196-
`credits`) prints the current credit count (bare number, or the full envelope
197-
with `--format json`); `drip` funds the wallet from the testnet faucet
198-
(Base Sepolia only, returns the funding tx, not credits; once per account).
199-
Solana wallets have no x402 faucet and must be funded out of band. The
200-
session JWT is authenticated once and cached under
201-
`<config-dir>/qn/sessions.toml` (0600, keyed by wallet address); a
202-
missing/expired session re-authenticates transparently (free, no
203-
confirmation), including one automatic re-auth if a drawdown call's token
204-
expired mid-use. Out of credits surfaces an actionable error pointing at
205-
`qn rpc x402 buy-credits`; nothing auto-retries a credit-drawing call.
206-
**MPP session**: `qn rpc mpp {open, top-up, close, status}` manages an
207-
on-chain escrow payment channel (Tempo), and `qn rpc call --mpp-session` pays
208-
from it with a cumulative EIP-712 voucher (no on-chain tx per call). All take
209-
the same payment param stack (a Tempo wallet). The four lifecycle verbs take
210-
no `--network`: they act on the channel, which `--payment-network` and
211-
`--payment-asset` identify on their own. Only `--mpp-session` names
212-
`--network`, because only it queries a chain. `open --deposit <BASE_UNITS>` and
213-
`top-up --deposit <BASE_UNITS>` move real funds on-chain (gated Mild); `close`
214-
cooperatively settles + refunds (gated Mild; its prompt warns further
215-
`--mpp-session` calls fail until re-open); `status` shows the deposit and
216-
remaining balance from the local record with no network call, and `status
217-
--verify` asks the gateway instead and re-syncs the accepted spend. `--verify`
218-
spends one request unit from the deposit: the gateway prices every session
219-
POST as a chargeable request, so there is no free way to ask it. Channel state is cached
220-
under `<config-dir>/qn/channels.toml` (0600, keyed by wallet address + pay
221-
network + pay asset); every channel verb needs that record — a lost one means
222-
opening a new channel. The key is the pay scope: a channel funds paid calls to
223-
any supported `--network`, so you can pay on a testnet to query a mainnet.
224-
Two pay assets on one pay chain are separate
225-
channels. `--mpp-session` requires an open channel, is mutually exclusive with
226-
`--x402`/`--mpp`/`--x402-drawdown`/`--endpoint-url`, and points at
227-
`qn rpc mpp top-up` when the channel deposit is exhausted.
148+
**Paid lane**: use a gateway micropayment instead of an API key, login, or
149+
Tooling Access. Choose one mode before building the command:
150+
151+
| Mode | Use it when | Call flag | What pays |
152+
|------|-------------|-----------|-----------|
153+
| x402 per request | You make a small number of calls. | `--x402` | A signed payment on each call. |
154+
| MPP per request | You make a small number of calls through Tempo. | `--mpp` | A signed Tempo payment on each call. |
155+
| x402 drawdown | You want prepaid credits and no per-call signing. | `--x402-drawdown` | One credit per successful response. |
156+
| MPP session | You want repeated calls from a funded Tempo channel. | `--mpp-session` | A cumulative voucher from the channel. |
157+
158+
Start with discovery. These commands need no API key:
159+
160+
```sh
161+
qn rpc x402 supported-networks
162+
qn rpc x402 supported-payments
163+
qn rpc mpp supported-networks
164+
qn rpc mpp supported-payments
165+
```
166+
167+
Use a supported gateway slug for `--network`. It selects the chain the
168+
gateway call queries. Use `--payment-network` for the chain that settles the
169+
payment. They can differ. For example, `--network ethereum-mainnet` can query
170+
Ethereum while `--payment-network base-sepolia` settles an x402 payment.
171+
172+
`--payment-asset` accepts a token symbol, EVM contract address, or Solana
173+
mint. `--max-amount` sets the per-call or per-action ceiling in integer base
174+
units. An offer above that ceiling is refused before signing. The CLI has no
175+
default ceiling.
176+
177+
The key source precedence is `--payment-key-file` > `--payment-wallet` >
178+
`key_file` > `wallet` in `[rpc.payment]`. Keys come from a file or a stored
179+
wallet. The CLI does not read payment keys from environment variables,
180+
command-line values, or inline config. Config supplies values but never
181+
activates a mode; the call still needs `--x402`, `--mpp`,
182+
`--x402-drawdown`, or `--mpp-session`.
183+
184+
`--receipt` changes paid-call stdout to
185+
`{"result": ..., "payment_receipt": ...}`. MPP includes the settlement
186+
reference. x402 returns `null`. Without `--receipt`, paid calls use the same
187+
result shape as unpaid calls. Paid calls cannot use `--endpoint-url`.
188+
189+
**x402 drawdown** uses a cached gateway session. `qn rpc x402 buy-credits`
190+
signs the credit purchase and requires the full payment flags. `balance` and
191+
`drip` authenticate the wallet but do not sign a payment, so they need only
192+
the wallet and payment network. `drip` works on Base Sepolia only. Fund
193+
Solana wallets out of band. `buy-credits` is gated and needs `--yes` in a
194+
script. `qn rpc call --x402-drawdown` needs the query network and wallet; it
195+
uses one credit after a successful response and does not need an asset or
196+
spend ceiling. The pay network defaults to the query network. Credits can pay
197+
for calls to any supported query network.
198+
199+
**MPP session** uses a cached Tempo escrow channel. `open --deposit` funds
200+
the channel, `top-up --deposit` adds funds, `status` reads the local record,
201+
and `close` settles and refunds the unused balance. These lifecycle commands
202+
identify the channel with `--payment-network` and `--payment-asset`; they do
203+
not take a query `--network`. `status --verify` contacts the gateway and
204+
spends one request unit. `--mpp-session` needs an open channel and adds the
205+
query `--network`. The channel can fund calls to any supported query network.
206+
`open`, `top-up`, and `close` are gated. A lost channel record under
207+
`<config-dir>/qn/channels.toml` requires opening a new channel.
228208
- `wallet` — the local store of payment wallets for the paid RPC lane; no API
229209
key or login required. `qn wallet generate --vm <evm|svm> --name <NAME>`
230210
creates and stores a dedicated payment wallet (raw key at 0600 under
@@ -304,57 +284,71 @@ qn rpc call eth_blockNumber --endpoint-url https://my-endpoint.example/rpc
304284
is enabling Tooling Access (or pass `--yes` to enable on first use). A custom
305285
`--endpoint-url` (or `[rpc] endpoint_url` in config) bypasses that entirely.
306286

307-
**Pay per call with a crypto micropayment (no API key, no login):**
287+
**Choose a paid RPC mode:**
308288

309-
`--payment-asset`/`--max-amount` must match a real offer for the network (see
310-
`qn rpc x402 supported-payments` / `qn rpc mpp supported-payments`); an
311-
unfunded wallet or a mismatched asset/amount is refused with HTTP 400/402
312-
before anything settles.
289+
Discovery and wallet setup come first. Fund the address printed by
290+
`qn wallet generate` before you run a paid command.
313291

314292
```sh
315-
qn rpc x402 supported-networks # networks you can call (mpp: qn rpc mpp supported-networks)
316-
qn rpc x402 supported-payments # payment options: network, token, address (mpp: qn rpc mpp supported-payments)
317-
qn wallet generate --vm evm --name payer # dedicated wallet; prints its address + a QR to fund
318-
# → fund THAT address, then pick a lane:
293+
qn rpc x402 supported-networks
294+
qn rpc x402 supported-payments
295+
qn rpc mpp supported-networks
296+
qn rpc mpp supported-payments
297+
qn wallet generate --vm evm --name payer
298+
```
299+
300+
**x402 per request:** sign one payment for each call. Use this for occasional
301+
calls. The query network and settlement network can differ.
319302

320-
# x402 on EVM (pays Base Sepolia USDC; --network, the chain you query, is
321-
# independent of the chain you pay on):
303+
```sh
322304
qn rpc call eth_blockNumber --network ethereum-mainnet --x402 \
323-
--payment-wallet payer --payment-network base-sepolia \
324-
--payment-asset USDC --max-amount 1000
305+
--payment-wallet payer --payment-network base-sepolia \
306+
--payment-asset USDC --max-amount 1000
307+
```
325308

326-
# MPP (pays Tempo testnet USDC); same EVM wallet, --receipt adds the settlement ref:
309+
**MPP per request:** pay each call on Tempo. Use the same EVM wallet and add
310+
`--receipt` when you need the settlement reference.
311+
312+
```sh
327313
qn rpc call eth_blockNumber --network ethereum-mainnet --mpp --receipt \
328-
--payment-wallet payer --payment-network tempo-testnet \
329-
--payment-asset USDC --max-amount 1000
330-
331-
# x402 on Solana (devnet); needs an SVM wallet:
332-
qn wallet generate --vm svm --name sol-payer
333-
qn rpc call getSlot --network solana-devnet --x402 \
334-
--payment-wallet sol-payer --payment-network solana-devnet \
335-
--payment-asset USDC --max-amount 1000000
336-
337-
# Solana payment builds read the mint and a recent blockhash from a Solana RPC.
338-
# The public default rate-limits; point --svm-rpc-url at your own endpoint:
339-
qn rpc call getSlot --network solana-devnet --x402 \
340-
--payment-wallet sol-payer --payment-network solana-devnet \
341-
--payment-asset USDC --max-amount 1000000 \
342-
--svm-rpc-url https://my-solana-endpoint.example
343-
344-
# Store the parameters in config to keep calls short (never the raw key):
345-
cat >> ~/.config/qn/config.toml <<'EOF'
346-
[rpc.payment]
347-
wallet = "payer" # a stored wallet, or key_file = "<path>" (chmod 600)
348-
max_amount = "1000" # spend ceiling per call, base units
349-
payment_network = "base-sepolia" # settlement chain: network name or CAIP-2 id
350-
payment_asset = "USDC" # symbol (resolved per network), or a raw address/mint
351-
EOF
352-
qn rpc call eth_blockNumber --network ethereum-mainnet --x402 # params now come from config
314+
--payment-wallet payer --payment-network tempo-testnet \
315+
--payment-asset USDC --max-amount 1000
353316
```
354317

355-
This moves real funds (even testnet tokens are real transfers) — use a
356-
dedicated, minimally funded wallet. The spend ceiling bounds each call; there
357-
is no built-in default.
318+
**x402 drawdown:** buy credits once, then spend one credit per successful call.
319+
Use this when you want to avoid signing each call.
320+
321+
```sh
322+
qn rpc x402 buy-credits --network ethereum-mainnet --yes \
323+
--payment-wallet payer --payment-network base-sepolia \
324+
--payment-asset USDC --max-amount 10000000
325+
qn rpc x402 balance --payment-wallet payer --payment-network base-sepolia
326+
qn rpc call eth_blockNumber --network ethereum-mainnet --x402-drawdown \
327+
--payment-wallet payer
328+
```
329+
330+
**MPP session:** deposit into a Tempo channel, then pay with cumulative
331+
vouchers. Use this for repeated calls. The channel's payment network and asset
332+
identify the channel; the call's `--network` identifies the query chain.
333+
334+
```sh
335+
qn rpc mpp open --deposit 1000000 --yes \
336+
--payment-wallet payer --payment-network tempo-testnet \
337+
--payment-asset USDC --max-amount 1000000
338+
qn rpc call eth_blockNumber --network ethereum-mainnet --mpp-session \
339+
--payment-wallet payer --payment-network tempo-testnet \
340+
--payment-asset USDC --max-amount 1000000
341+
qn rpc mpp status --payment-wallet payer \
342+
--payment-network tempo-testnet --payment-asset USDC --max-amount 1000000
343+
```
344+
345+
Use `qn rpc mpp top-up` after the channel runs low. Use `qn rpc mpp close` to
346+
settle the channel and refund its unused balance. Both commands need the same
347+
channel flags and `--yes` in a script.
348+
349+
For Solana x402, generate an SVM wallet and set both networks to
350+
`solana-devnet`. Set `--svm-rpc-url` when the public Solana RPC rate-limits the
351+
payment build.
358352

359353
## 8. Gotchas & safety rails
360354

‎src/confirm.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub fn prompt_yes_no(message: &str) -> Result<bool, CliError> {
8484
Confirm::new()
8585
.with_prompt(message)
8686
.default(false)
87+
.report(false)
8788
.interact()
8889
.map_err(|e| CliError::Io(std::io::Error::other(e)))
8990
}

0 commit comments

Comments
 (0)