Skip to content
Security
Skill

/token-compatibility

Detect ERC-20 token compatibility issues — fee-on-transfer, rebasing, non-standard return values, missing decimals(), low-decimal tokens, blacklistable tokens (USDC), pausable tokens. Activate on any ERC-20 integration, `transfer`/`transferFrom` use, balance-based accounting,

From plugin
rugproof
1152 skills23 agents45 commands4 hooks

Claude Code

$ npx -y skills add omermaksutii/RugProof --skill token-compatibility --agent claude-code

SKILL.md

token-compatibility.SKILL.md
name: token-compatibility
description: Detect ERC-20 token compatibility issues — fee-on-transfer, rebasing, non-standard return values, missing decimals(), low-decimal tokens, blacklistable tokens (USDC), pausable tokens. Activate on any ERC-20 integration, `transfer`/`transferFrom` use, balance-based accounting, decimal scaling.

Token compatibility detection

When this applies

  • Any ERC-20 integration: lending, AMM, vault, staking, bridge
  • Balance-based accounting (`balanceOf(this) - prevBalance`)
  • Decimal scaling between tokens
  • Cross-chain bridges with various token implementations
  • Aggregators / routers handling user-supplied tokens

Detection patterns

Fee-on-transfer assumed away (HIGH)

uint256 before = token.balanceOf(address(this));
token.transferFrom(user, address(this), amount);
shares = amount * X / Y;        // ← uses `amount`, not actual received

Tokens like USDT (when fee enabled), SafeMoon, etc. take a fee. Use `balanceOf(this) - before` as the effective amount.

Rebasing token accounting (HIGH)

stETH, aUSDC, AMPL — balances change without `transfer`. Vaults assuming `balanceOf` ≡ deposit will mis-account. Either don't accept rebasing tokens, or use share-based accounting (wstETH-style wrappers).

Non-standard return values — USDT (HIGH)

USDT's `transfer` does NOT return bool (pre-`SafeERC20` use breaks):

bool ok = IERC20(usdt).transfer(to, amt);   // ← reverts: ABI mismatch

Use OZ `SafeERC20` which uses low-level call + return-data inspection.

Blacklistable tokens (HIGH)

USDC, USDT can blacklist addresses. If a user gets blacklisted after deposit, the protocol may be unable to return funds → other users' funds stuck if pooled.

Pausable tokens (HIGH)

USDC, USDT can pause transfers. Protocol functions that must succeed (liquidations) may revert.

Low-decimal tokens (MEDIUM-HIGH)

GUSD has 2 decimals. Math assuming 18 decimals causes huge rounding errors.

shares = assets * 1e18 / something;   // ← shares now astronomical or zero

Tokens with hooks (ERC-777) (HIGH)

Reentrancy surface (see [[reentrancy]]). Many protocols implicitly assume vanilla ERC-20.

Tokens with double-entry (HIGH)

TUSD historically had two valid addresses. `transferFrom` could be invoked from either. Approval to one didn't bind the other.

Missing return on approve / non-zero approve revert (HIGH)

Some tokens (early USDT) require `approve(spender, 0)` before `approve(spender, X)`. Use `safeApprove` or `forceApprove`. See [[approval-issues]].

Missing `decimals()` (LOW)

Non-standard tokens may lack `decimals()`. Guard with try/catch and default to 18.

Tokens that revert on zero-amount transfer (LOW-MEDIUM)

LEND, others. Cap-by-zero guards needed.

Severity rubric

| Pattern | Severity | |---|---| | Vault accepts fee-on-transfer with no balance-delta accounting | **High** | | Protocol accepts rebasing token without share-wrapper | **High** | | Naive ERC-20 transfer (no SafeERC20) | **High** | | Pooled funds with blacklistable token + no escape hatch | **High** | | Low-decimal token with 18-decimal-assumed math | **High** | | Pausable token in liquidation path | **High** | | Approve-non-zero revert ignored | **High** | | Zero-amount-revert in batch flow | **Medium** | | Missing `decimals()` graceful handling | **Low** |

Remediation patterns

  • **Allowlist tokens** — easier than supporting every token.
  • **Use SafeERC20** — covers most return-value quirks.
  • **Balance-delta accounting** — measure `balanceOf(this) - prev` after transferFrom.
  • **Disallow rebasing tokens** — or only accept their share-wrapped form (wstETH not stETH).
  • **Reset approval before set** — `forceApprove` from OZ ≥4.9, or `safeApprove(0)` then `safeApprove(amount)`.
  • **Escape hatches** — admin can swap a single user's blacklisted balance out of pooled state into a side mapping.

False-positive notes

  • Protocol explicitly lists supported tokens and tests against them → not a finding for unsupported.
  • Test/mock tokens in test/ → ignore.

Related

  • [[unchecked-calls]]
  • [[approval-issues]]
  • [[reentrancy]] — ERC-777 hooks
  • [[integer-issues]] — decimals math
Read more
@omermaksutii
Ships withrugproof

Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy

1152 skills23 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
11
Star history of omermaksutii/RugProof on GitHub, a chart by star-history.com

Other skills on rugproof.

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

@nvidia@nvidiaInstall Skill

Questions about token-compatibility.

Which coding agents can use token-compatibility?
token-compatibility installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.