Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

eth-allowance-checker

Audit ERC-20 token approvals and allowances for any Ethereum wallet.

Overview

When you interact with DeFi protocols, NFT marketplaces, or DEXes, they request token approvals — permission to spend your tokens. These approvals persist on-chain and can be exploited if the spender contract is compromised or if you no longer use the protocol.

This tool scans all Approval events for a wallet, reads current on-chain allowances, assesses risk levels, and helps you identify dangerous or stale approvals.

Install

# Clone or copy the project
cd eth-allowance-checker

# Install dependencies
pip install -r requirements.txt

Requirements

  • Python 3.8+
  • click — CLI framework
  • requests — HTTP client
  • rich — terminal formatting

Configuration

Env Var Default Description
ETHERSCAN_API_KEY (empty) Etherscan API key. Optional but recommended (free tier: 5 req/sec).
ETH_RPC_URL https://rpc.ankr.com/eth Ethereum JSON-RPC endpoint for eth_call.

Set them:

export ETHERSCAN_API_KEY="YourApiKeyToken"
export ETH_RPC_URL="https://rpc.ankr.com/eth"   # or your own node

Usage

python allowance_checker.py <COMMAND> [OPTIONS]

check — Audit all approvals

Scans Approval events + known spenders, reads current allowances, shows risk levels.

python allowance_checker.py check 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

Sample output:

Scanning approvals for 0xd8da6bf26964af9d7eed9e03e53415d37aa96045 ...
  Fetching Approval event logs from Etherscan ...
  Found 12 unique approval events in logs.
  Checking known spenders via token transfers ...
  Found 8 allowances to known spenders.
  Total unique (token, spender) pairs: 15
  Done. 11 active approvals found.

        Token Approvals (for 0xd8da6bf2…)
┌──────────────────┬─────────────────────┬──────────────┬──────────┐
│ Token            │ Spender             │    Allowance │     Risk │
├──────────────────┼─────────────────────┼──────────────┼──────────┤
│ USDT (0xdac17f9…) │ Uniswap V2 Router  │ UNLIMITED    │ CRITICAL │
│ WETH (0xc02aaa3…) │ Uniswap V3 Router  │ UNLIMITED    │ CRITICAL │
│ USDC (0xa0b8699…) │ Aave V3 Pool       │ 1,000,000    │ MEDIUM   │
│ DAI  (0x6b17547…) │ 1inch Router       │ 500.0        │ LOW      │
└──────────────────┴─────────────────────┴──────────────┴──────────┘

Export to JSON or CSV:

python allowance_checker.py check 0xWallet... --export approvals.json
python allowance_checker.py check 0xWallet... --export approvals.csv

Save a snapshot for later comparison:

python allowance_checker.py check 0xWallet... --snapshot snap_jan.json

unlimited — Show dangerous unlimited approvals

Filters for approvals where allowance ≥ 2^256 - 1 (max uint256).

python allowance_checker.py unlimited 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

Sample output:

No unlimited approvals found. ✓

Or if found:

    Unlimited Approvals (CRITICAL)
┌──────────┬───────────────────┬─────────────┬──────────┐
│ Token    │ Spender           │   Allowance │     Risk │
├──────────┼───────────────────┼─────────────┼──────────┤
│ USDT     │ Uniswap V2 Router │ UNLIMITED   │ CRITICAL │
│ WETH     │ Uniswap V3 Router │ UNLIMITED   │ CRITICAL │
└──────────┴───────────────────┴─────────────┴──────────┘

2 unlimited approval(s) found!
These protocols can spend any amount of your tokens at any time.
Consider revoking them if no longer needed.

stale — Show old unused approvals

Checks last interaction with each spender via transaction history.

python allowance_checker.py stale 0xWallet... --days 90

Sample output:

  Stale Approvals (>90 days)
┌──────────┬───────────────┬───────────┬──────┬──────────────────┐
│ Token    │ Spender       │ Allowance │ Risk │ Last Interaction │
├──────────┼───────────────┼───────────┼──────┼──────────────────┤
│ USDT     │ SushiSwap     │ UNLIMITED │ HIGH │ 2024-03-15       │
│ LINK     │ 1inch Router  │ 1,000     │ LOW  │ never            │
└──────────┴───────────────┴───────────┴──────┴──────────────────┘

revoke — Generate revoke tx data

Generates the calldata for approve(spender, 0) without sending anything.

python allowance_checker.py revoke 0xdac17f958d2ee523a2206206994597c13d831ec7 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D

Output:

Revoke Transaction Data

  Token contract : 0xdac17f958d2ee523a2206206994597c13d831ec7
  Spender        : 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D (Uniswap V2 Router)
  Function       : approve(address,uint256)
  Selector       : 0x095ea7b3
  Calldata       : 0x095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d0000000000000000000000000000000000000000000000000000000000000000
  To             : 0xdac17f958d2ee523a2206206994597c13d831ec7
  Value          : 0 ETH

Recommended Gas Settings:
  Gas limit      : 50,000 – 100,000
  Gas price      : check current network gas (e.g. via eth_gasPrice)

⚠  This tool does NOT send transactions.
   Use a wallet or raw tx sender to broadcast.

Raw calldata to copy:
  0x095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d0000000000000000000000000000000000000000000000000000000000000000

summary — Overview with breakdowns

python allowance_checker.py summary 0xWallet...

Sample output:

═══ Approval Summary for 0xd8da6bf26964af9d7eed9e03e53415d37aa96045 ═══

  Total active approvals  : 11
  CRITICAL (unlimited)    : 2
  HIGH                    : 1
  MEDIUM                  : 3
  LOW                     : 5

Per-Token Breakdown:
  Token    Approvals  Max Risk
  USDT            3  CRITICAL
  WETH            2  CRITICAL
  USDC            3  MEDIUM
  DAI             3  LOW

Per-Spender Breakdown:
  Spender             Approvals  Max Risk
  Uniswap V2 Router          3  CRITICAL
  Uniswap V3 Router          2  CRITICAL
  Aave V3 Pool               2  MEDIUM
  1inch Router               2  LOW

compare — Diff two snapshots

Compare approvals between two points in time.

# Take snapshots on different dates
python allowance_checker.py check 0xWallet... --snapshot snap_jan.json
# ... time passes ...
python allowance_checker.py check 0xWallet... --snapshot snap_feb.json

# Compare
python allowance_checker.py compare snap_jan.json snap_feb.json

Output:

═══ Approval Comparison ═══

  Snapshot A : snap_jan.json (loaded 2025-01-15T10:00:00+00:00)
  Snapshot B : snap_feb.json (loaded 2025-02-15T10:00:00+00:00)
  Unchanged  : 8
  New        : 2
  Removed    : 1

New Approvals:
┌──────┬───────────────────┬──────────────┬──────┐
│ Token│ Spender           │    Allowance │ Risk │
├──────┼───────────────────┼──────────────┼──────┤
│ ARB  │ Uniswap V3 Router │ UNLIMITED    │ HIGH │
│ OP   │ CowSwap           │ 10,000       │ LOW  │
└──────┴───────────────────┴──────────────┴──────┘

Removed Approvals:
┌──────┬──────────────┐
│ Token│ Spender      │
├──────┼──────────────┤
│ LINK │ 1inch Router │
└──────┴──────────────┘

known-spenders — List known addresses

python allowance_checker.py known-spenders

Output:

     Known Spender Addresses
┌────┬───────────────────────┬──────────────────────────────────────────────┐
│  # │ Name                  │ Address                                      │
├────┼───────────────────────┼──────────────────────────────────────────────┤
│  1 │ Uniswap V2 Router     │ 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D  │
│  2 │ Uniswap V3 Router     │ 0xE592427A0AEce92De3Edee1F18E0157C05861564  │
│  3 │ Uniswap Universal Rt  │ 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD  │
│  4 │ SushiSwap Router      │ 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F  │
│  5 │ 1inch Router          │ 0x1111111254fb6c44bAC0beD2854e76F90643097d  │
│  6 │ OpenSea (Wyvern)      │ 0x00000000006c3852cbEf3e08E8dF289169EdE581  │
│  7 │ Blur                  │ 0x39da41747a83aeE65833441429935E07D5843161  │
│  8 │ Seaport 1.5           │ 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC  │
│  9 │ Aave V3 Pool          │ 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2  │
│ 10 │ Compound cETH         │ 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5  │
│ 11 │ MetaMask Swap Router  │ 0x881D40237659C251811CEC9c364ef91dC08D300C  │
│ 12 │ 0x Exchange Proxy     │ 0xDef1C0ded9bec7F1a1670819833240f027b25EfF  │
│ 13 │ Paraswap              │ 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57  │
│ 14 │ CowSwap               │ 0xC92E8bdf79f0507F65a392b0ab4667716BFE0110  │
└────┴───────────────────────┴──────────────────────────────────────────────┘

14 known spenders listed.

Risk Levels

Level Condition Meaning
CRITICAL Allowance = 2^256 - 1 (max uint256) Unlimited approval. Protocol can spend your entire token balance at any time. Highest risk.
HIGH Allowance > 10^24 Very large allowance. Likely exceeds any realistic token supply.
MEDIUM Allowance > 10^18 Large allowance. May be intentional for large portfolios.
LOW Allowance ≤ 10^18 Small allowance. Likely safe, but still worth reviewing.

Known Spenders

The tool recognises these major protocols:

  • Uniswap (V2, V3, Universal Router)
  • SushiSwap Router
  • 1inch Router
  • OpenSea (Wyvern)
  • Blur
  • Seaport 1.5
  • Aave V3 Pool
  • Compound cETH
  • MetaMask Swap Router
  • 0x Exchange Proxy
  • Paraswap
  • CowSwap

Unknown spenders are displayed with a truncated address.

Caching

Token metadata (symbol, name, decimals) is cached for 1 hour at ~/.allowance-cache/.

Allowance values are cached for 5 minutes.

Delete the cache dir to force fresh lookups:

rm -rf ~/.allowance-cache/

Export Formats

All subcommands that show data support --export <path>:

  • .json extension → JSON export
  • .csv extension → CSV export
  • Other extensions default to JSON

Security Notes

  1. Unlimited approvals are dangerous. If a protocol contract is compromised or has an upgradeable proxy, unlimited approval means the attacker can drain your entire token balance.

  2. Revoke unused approvals. If you no longer use a protocol, revoke its approvals. This tool generates the revoke calldata — you still need to broadcast the transaction.

  3. Prefer exact-amount approvals. When interacting with protocols, approve only the exact amount needed rather than unlimited.

  4. This tool is read-only. It never sends transactions. The revoke command only generates calldata.

  5. Trust assumptions. This tool relies on Etherscan and a public RPC endpoint. For sensitive operations, verify results independently with your own node.

  6. Approval ≠ Transfer. An approval means the spender can transfer tokens — it doesn't mean they have. But revoked approvals immediately prevent future transfers.

How It Works

  1. Discovery: Fetches Approval event logs from Etherscan where topic1 = your wallet address. Also checks all tokens you've interacted with against known spender addresses.

  2. Allowance Reading: For each (token, spender) pair, calls allowance(owner, spender) on the token contract via eth_call through a public RPC.

  3. Metadata: Resolves token symbol, name, and decimals by calling the standard ERC-20 view functions on each token contract.

  4. Risk Assessment: Compares the raw uint256 allowance against the thresholds listed above.

License

MIT

About

CLI to audit ERC-20 token approvals — find unlimited approvals, stale approvals, risk assessment, revoke tx generation

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages