Summary
Sharing a small, optional pre-sign safety hook in case it is useful to AgentKit users, and to get the team's read on whether it belongs as a documented pattern. Feedback very welcome — including "this belongs in a wallet layer, not here."
Disclosure: I maintain chain-signer, the library referenced below. This is an optional integration suggestion, not a dependency ask.
The gap
AgentKit's wallet providers screen recipients (sanctions / known-bad addresses), which is great. What they don't do today is decode the calldata of the transaction the agent is about to sign. Most agent fund-loss in 2026 hasn't come from sending to a sanctioned address — it has come from an agent being talked into signing an unlimited approve(), a setApprovalForAll(true), a Permit2 allowance, or the same drain hidden inside a multicall / Safe / ERC-4337 execute. A recipient check doesn't see any of that, because the malicious party is the spender in the calldata, not the to of the tx. (Write-up with reproduced 2026 incident shapes: https://gist.github.com/Kevthetech143/f4b940b2b31d457bd593c3d6df9f65c4)
A small, dependency-light option
chain-signer is a pip-installable, offline, no-API-key, no-network static decoder. preflight(tx) decodes an unsigned EVM tx and returns HIGH/MED/LOW flags for the known drain patterns (unlimited/large approval, increaseAllowance, setApprovalForAll, ERC-20 transferFrom, ERC-721/1155 safeTransferFrom, ERC-2612/DAI/Permit2 permits, proxy upgradeTo, EIP-7702 delegation, and drains nested in multicall / Multicall3 / Safe multiSend / 4337 execute). It's a static complement to recipient screening and to simulation — not a replacement — and it runs in-process with no external call.
Proposed shape (opt-in wrapper, verified against coinbase-agentkit==0.7.4)
from chain_signer import preflight
from web3.types import TxParams
from coinbase_agentkit.wallet_providers import EthAccountWalletProvider # or CdpEvmWalletProvider
class PreflightBlocked(Exception): ...
def preflight_guard(tx: dict, *, on_block: str = "raise"):
report = preflight(tx) # offline, no key, no network
highs = [f for f in report.get("risk_flags", []) if f.get("severity") == "HIGH"]
if highs and on_block == "raise":
raise PreflightBlocked("blocked before signing: " + ", ".join(f["code"] for f in highs))
return None if highs else tx
class GuardedEthAccountWalletProvider(EthAccountWalletProvider):
def send_transaction(self, transaction: TxParams):
preflight_guard(dict(transaction), on_block="raise") # raises BEFORE sign + broadcast
return super().send_transaction(transaction)
Behavior (real provider instantiated, send_transaction called on a malicious unlimited approve() — raised before any broadcast):
BLOCKED pre-broadcast: chain-signer blocked a HIGH-risk tx before signing: unlimited_approval
Off by default; zero behavior change unless a user opts in.
Honest limits (stated up front)
This is static decoding, so it won't catch a novel/obfuscated drain it can't decode (those get a LOW "unknown" flag, not a block); it's EVM-only; and it does not stop a redirected legitimate transfer (moving real funds to an attacker) — that's a recipient-allowlist / value-cap concern, which AgentKit's policy layer already addresses and which chain-signer's separate check_action gate also covers. Best used alongside recipient screening + simulation for high-value actions.
Happy to open a PR adding this as a documented optional example if the team thinks it fits, or to just leave it here as a pattern for anyone who wants it.
Summary
Sharing a small, optional pre-sign safety hook in case it is useful to AgentKit users, and to get the team's read on whether it belongs as a documented pattern. Feedback very welcome — including "this belongs in a wallet layer, not here."
Disclosure: I maintain chain-signer, the library referenced below. This is an optional integration suggestion, not a dependency ask.
The gap
AgentKit's wallet providers screen recipients (sanctions / known-bad addresses), which is great. What they don't do today is decode the calldata of the transaction the agent is about to sign. Most agent fund-loss in 2026 hasn't come from sending to a sanctioned address — it has come from an agent being talked into signing an unlimited
approve(), asetApprovalForAll(true), a Permit2 allowance, or the same drain hidden inside amulticall/ Safe / ERC-4337execute. A recipient check doesn't see any of that, because the malicious party is the spender in the calldata, not thetoof the tx. (Write-up with reproduced 2026 incident shapes: https://gist.github.com/Kevthetech143/f4b940b2b31d457bd593c3d6df9f65c4)A small, dependency-light option
chain-signeris a pip-installable, offline, no-API-key, no-network static decoder.preflight(tx)decodes an unsigned EVM tx and returns HIGH/MED/LOW flags for the known drain patterns (unlimited/large approval,increaseAllowance,setApprovalForAll, ERC-20transferFrom, ERC-721/1155safeTransferFrom, ERC-2612/DAI/Permit2 permits, proxyupgradeTo, EIP-7702 delegation, and drains nested inmulticall/ Multicall3 / SafemultiSend/ 4337execute). It's a static complement to recipient screening and to simulation — not a replacement — and it runs in-process with no external call.Proposed shape (opt-in wrapper, verified against
coinbase-agentkit==0.7.4)Behavior (real provider instantiated,
send_transactioncalled on a malicious unlimitedapprove()— raised before any broadcast):Off by default; zero behavior change unless a user opts in.
Honest limits (stated up front)
This is static decoding, so it won't catch a novel/obfuscated drain it can't decode (those get a LOW "unknown" flag, not a block); it's EVM-only; and it does not stop a redirected legitimate transfer (moving real funds to an attacker) — that's a recipient-allowlist / value-cap concern, which AgentKit's policy layer already addresses and which chain-signer's separate
check_actiongate also covers. Best used alongside recipient screening + simulation for high-value actions.Happy to open a PR adding this as a documented optional example if the team thinks it fits, or to just leave it here as a pattern for anyone who wants it.