unchecked-calls
Skill36 starsChanged 5 months agoMITView on GitHub
Detect ignored external-call return values — silent failures from low-level call/delegatecall/staticcall, ignored ERC20 transfer return values, return-data length issues. Activate on `.call`, `.delegatecall`, `.staticcall`, `.send`, `transfer`/`transferFrom` (without SafeERC20), and any function returning `bool` whose return is discarded.
In this repository44 other files it gives its agents.
- access-controlSkill
- approval-issuesSkill
- caching-and-incrementalSkill
- centralization-riskSkill
- confidence-scoringSkill
- cosmwasmSkill
- cross-chain-messagingSkill
- cross-contract-stateSkill
- delegatecall-risksSkill
- diamond-eip2535Skill
- dos-vectorsSkill
- erc1271-contract-signaturesSkill
- erc4337-account-abstractionSkill
- erc4626-inflationSkill
- false-positive-feedback-loopSkill
- fee-on-transferSkill
- flash-loan-attacksSkill
- initializationSkill
- inline-assemblySkill
- integer-issuesSkill
- intents-erc7683Skill
- known-good-comparisonSkill
- liquidation-cascadeSkill
- mev-frontrunningSkill
- mev-pbsSkill
- multi-pass-self-critiqueSkill
- oracle-manipulationSkill
- oracle-redundancySkill
- permit2-patternsSkill
- pragma-and-addressesSkill
- progress-and-streamingSkill
- reentrancySkill
- restaking-eigenlayerSkill
- selfdestruct-eip6780Skill
- signature-malleabilitySkill
- signature-replaySkill
- solana-anchorSkill
- storage-layoutSkill
- stylus-rustSkill
- token-compatibilitySkill
- tx-context-misuseSkill
- ve-lock-governanceSkill
- vyper-specificSkill
- zk-verifier-bugsSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 24
Always require(ok, "call failed").
- Very specific: line 31
Use OZ SafeERC20's safeTransfer which handles missing return values.
- Very specific: line 54
If permit reverts (because it was already used), the consuming transferFrom continues with a stale allowance.
- Very specific: line 76
Always check (bool ok, bytes memory ret) = target.call(...) and require(ok, ...).
- Very specific: line 78
After .call to dynamic addresses, check target.code.length > 0 before relying on return.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Unchecked external calls detection
When this applies
- Low-level
call,delegatecall,staticcall,send - ERC-20
transfer/transferFrom/approve(non-SafeERC20) - Calls to user-provided addresses
- Multi-call patterns that don't propagate failures
- Try-catch swallowing all errors
Detection patterns
Ignored .call return (HIGH)
(bool ok,) = target.call(data); // ← ok unused
// or worse:
target.call(data); // ← Solidity ≥0.5 still allows this with warningAlways require(ok, "call failed"); unless an intentional best-effort.
ERC-20 without SafeERC20 (HIGH)
USDT and other non-conformant tokens don't return bool. Naive call:
IERC20(usdt).transfer(to, amt); // ← reverts on USDT due to ABI mismatchUse OZ SafeERC20's safeTransfer which handles missing return values.
Return-data check missing (HIGH)
Even compliant ERC20 returning false instead of reverting is silently passed:
bool ok = token.transfer(to, amt); // ← ok unused, returns false on failuretry/catch swallows everything (MEDIUM-HIGH)
try external.call() { /* … */ }
catch { /* silently ignored */ }Without inspecting catch (bytes memory reason), you lose all info; transitioning a critical revert into a silent success is a bug.
Address with no code (HIGH on call)
(bool ok,) = target.call(data);
require(ok);ok = true even if target is an EOA with no contract — call returns true. Add target.code.length > 0 check.
Permit followed by transferFrom — permit silently revertable (MEDIUM)
If permit reverts (because it was already used), the consuming transferFrom continues with a stale allowance. Use try/catch only to skip the permit reuse case.
Multicall fail-skip (HIGH)
Some routers continue on per-call failure. If a treasury sweeps via multicall, a single failed call could drop revenue.
selfdestruct / transfer no longer guaranteed on L2s with reduced gas
Forwarding 2300 gas is brittle on Berachain/Arbitrum/etc. — see [[dos-vectors]].
Severity rubric
| Pattern | Severity |
.call ignored, leads to silent fund loss | Critical |
| Non-SafeERC20 with USDT/non-conformant token | High |
target.call without code-length check | High |
| Try-catch swallows revert without inspection | High |
| Multicall fail-skip on revenue path | High |
.transfer (2300 gas) on L2 / to smart-wallet receivers | Medium |
| Best-effort fire-and-forget event hook | Low (document intent) |
Remediation patterns
- Always check
(bool ok, bytes memory ret) = target.call(...)andrequire(ok, ...). - For ERC-20: use OZ
SafeERC20everywhere. - After
.callto dynamic addresses, checktarget.code.length > 0before relying on return. - Replace
transfer/sendwith(bool ok,) = to.call{value: amt}("")+ check. - For best-effort hooks (event-style), document with a comment and consider returning a status code rather than silently succeeding.
False-positive notes
- A
.callwhose only side-effect-on-failure is a UX message can be best-effort — Info. - Solady / Solmate sometimes use bare
callwith custom assembly checks — verify the surrounding bytes are inspected.
Related
- [[token-compatibility]] — non-conformant ERC20s
- [[dos-vectors]]
- [[reentrancy]]
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

