04 / Security

Two modes.
Sharply different
blast radius.

Read-only is the default and has no key material in the process. Write mode holds a hot key. Everything below exists to keep that mode deliberate, bounded, and inspectable.

read-only

No key in the process

The server can only query public chain state. Write tools are not registered. Worst case is wrong data, not lost funds.

write

A dedicated hot wallet

PONS_PRIVATE_KEY can spend everything that wallet holds. Use a wallet funded only with what you intend to spend. Never reuse one that stores anything else.

Key

One env var.
Never logged.

The key comes only from PONS_PRIVATE_KEY (32-byte hex, 0x prefix optional). There is no key file, no prompt, no RPC parameter, no tool input that can carry a key.

Only the derived address is logged, to stderr, at startup. The env var is deleted from process.env right after loading. There is no runtime path to enable write mode — it requires a process restart with the variable set.

Gating

Dry-run is the
only default.

Every write tool needs two independent booleans to broadcast: dryRun=false and confirm=true. Both are strict zod booleans. A string "false" does not parse. Anything else returns a dry-run.

A dry-run simulates every step with eth_call (state-diff overrides so unfunded wallets still exercise contract logic), estimates gas, and returns exact calldata. Nothing is broadcast. Nothing is signed.

The Permit2 permit on a V4 sell is signed only when broadcasting. Dry-run simulates with an allowance override instead, so no live, replayable signature ever appears in a preview.

On broadcast: re-simulate → refuse if a step reverts → sign → send sequentially, waiting for each receipt. A status-0 receipt is a structured REVERTED. Later steps never send after a failed earlier one.

pons_set_creator_fee_recipient takes effect immediately — there is no 72 h delay. The timelocked propose/execute flow is the owner override, via pons_admin_call.

Caps

Fail closed at
startup, not later.

PONS_MAX_DEV_BUY_ETHDefault "0.05". Hard cap on a launch’s opening buy.
PONS_MAX_LAUNCHES_PER_DAYDefault 5. Hard cap on launch broadcasts per rolling 24 h (in-memory).
Curve registrationpons_buy / pons_sell only accept the factory-registered curve for a token. A contract that merely implements the curve ABI is NOT_A_LAUNCH.
Contract driftLive launchForwarder and memeHook are compared to pinned values. Drift blocks broadcast unless acceptContractDrift is set.
Tx hashThe hash from eth_sendRawTransaction must equal the locally computed keccak-256 of the signed payload.
Hot wallet. The key in PONS_PRIVATE_KEY can spend everything that wallet holds. Fund it with what you intend to spend, and nothing else.