Wrong-Address Debugging
The Hermes wallet mismatch case. How 'USDC balance: $0.00' lied. The Doppler key derived the wrong EOA. Detection: log derived address, compare to expected. Prevention: startup derivation check. Why 'balance = 0' is one of the most ambiguous signals in an EVM bot.
USDC balance: $0.00 is one of the most ambiguous messages an EVM bot can log. It is mechanically correct — the balance at the address being checked really is zero — and it is also the signal that launches every wrong-diagnosis debugging thread in the playbook.
The Hermes wallet mismatch case is canonical. The user funded the wallet. The bot reported zero. The first 40 minutes were burned assuming "the wallet must not be funded yet" — which was false. The wallet was fine. The bot was checking a different wallet entirely.
Why This Class Exists
The root cause is a subtle coupling between three systems:
- Secrets manager (Doppler, AWS Secrets Manager, Vault) holds the private key.
- Environment loads the key from the secrets manager at startup.
- Code derives the EOA from the key and queries on-chain state.
Any mismatch between (1) and the operator's mental model produces a derivation that lands somewhere unexpected. The operator thinks the key corresponds to wallet A. The secrets manager actually holds a key that corresponds to wallet B. The bot derives B and happily queries the balance at B — which is zero because nothing is funded there.
None of the three systems can see the others' state. The operator does not see the derived address unless the bot logs it. The secrets manager does not know what address the key maps to. The code does not know what address the operator expected.
The Diagnosis Order
When debugging any "balance = 0" complaint on an EVM bot, run these checks in this order:
- What address did the bot derive? Get this from a startup log, not by running a separate derivation.
- What address does the operator expect? Pull it from env var, config file, or user testimony.
- Do they match? If not, stop — this is the bug. No further debugging needed until the key or the expected value is corrected.
- If they match: query the on-chain balance at the derived address via a known-good RPC. Does it match the bot's report?
- If they match: query the exchange's reported balance. Does it match on-chain?
- If all four agree: then the wallet genuinely needs funding. This is the only point at which "it's not funded" is the correct diagnosis.
Most wrong-address cases fail at step 3 — which takes ten seconds to check if the bot logs its derived address at startup.
Inline Diagram — Diagnosis Ladder
The Prevention
The entire wrong-address debugging class is preventable with one startup check — covered in detail in Lesson 267. Here is the minimum viable version again, because it is worth repeating:
derived = Account.from_key(private_key).address
logger.info(f"bot_startup derived_wallet={derived}")
if derived.lower() != os.environ["EXPECTED_WALLET"].lower():
raise SystemExit(f"WALLET_MISMATCH derived={derived} expected={os.environ['EXPECTED_WALLET']}")
Five lines. Catches the entire class. The Hermes bot did not have this check. It does now, and so does every other EVM bot in the ecosystem.
The Rule
For every balance-zero complaint: verify the address before touching the fund question. Startup derivation check is mandatory. Post-startup, git log the derivation output to confirm it was logged. The entire wrong-address class should never consume more than 60 seconds of investigation once the preventive pattern is in place.