Token Approval Scam Warning System Development

We develop an approval scam warning system that protects your assets before a transaction is signed. Token approval is one of the most dangerous operations in Web3 — a user gives a contract the right to spend their tokens without their future involvement. Approval scams are the leading cause of asse

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1449
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    717
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1008

We develop an approval scam warning system that protects your assets before a transaction is signed. Token approval is one of the most dangerous operations in Web3 — a user gives a contract the right to spend their tokens without their future involvement. Approval scams are the leading cause of asset theft: according to Revoke.cash, losses have exceeded $2.8 billion. Our warning system detects suspicious approves 10 times faster than manual checks, analyzing pending requests and monitoring issued approvals using simulation and address databases. With over 5 years of experience in Web3 security, we build protection that prevents theft before it happens.

Why Approval Scams Are the Biggest Threat to Your Wallet

ERC-20 approve: token.approve(spender, amount) allows the spender to transfer up to amount tokens. ERC-721/ERC-1155 setApprovalForAll grants rights to all NFTs — the most dangerous form. Permit (EIP-2612) enables gasless approval signatures without on-chain transactions; an attacker can send permit() later, covertly. Our approval scam warning system analyzes transactions in 1-2 seconds with detection accuracy above 99%.

Which Types of Approvals Require Special Attention?

Type Rights Risk Example Protection
ERC-20 approve Up to amount tokens Medium Simulation + limit
setApprovalForAll All NFTs in collection High Mandatory review
Permit2 signature Unlimited via off-chain Critical Signature transaction monitoring
Infinite approval MaxUint256 High Notification of pending approve

How the Suspicious Approval Warning System Works

The system uses two layers: pre-transaction screening (analysis of pending transactions before signing) and post-approval monitoring (tracking issued approvals). The risk score is calculated by an algorithm considering the approval type, spender data, and contract age. If the score exceeds 70, the system blocks signing.

Analysis of Pending Transactions — Developing the Warning System

Simulation via Tenderly or Alchemy

Before signing, we simulate the transaction and analyze state changes. Code function:

interface ApprovalAnalysis { isSuspicious: boolean; riskScore: number; // 0-100 riskFactors: string[]; simulatedStateChanges: StateChange[]; spenderInfo: SpenderInfo; } interface SpenderInfo { address: string; isVerified: boolean; // is in whitelist of known dApps isNewContract: boolean; // contract < 30 days old hasSourceCode: boolean; // verified on Etherscan blacklisted: boolean; // in known scammers list } async function analyzeApproval( txParams: TransactionParams, chainId: number ): Promise<ApprovalAnalysis> { const riskFactors: string[] = []; let riskScore = 0; // 1. Simulate transaction const simulation = await simulateTransaction(txParams, chainId); // Extract approve calls from simulation const approvals = extractApprovals(simulation.stateChanges); for (const approval of approvals) { // 2. Check approval type if (approval.type === "setApprovalForAll") { riskFactors.push("SET_APPROVAL_FOR_ALL — grants rights to all NFT collections"); riskScore += 40; } if (approval.amount === MaxUint256) { riskFactors.push("UNLIMITED_APPROVAL — unlimited token approval"); riskScore += 20; } // 3. Analyze spender contract const spenderInfo = await analyzeSpender(approval.spender, chainId); if (spenderInfo.blacklisted) { riskFactors.push("KNOWN_SCAMMER — address in blacklist"); riskScore += 60; } if (spenderInfo.isNewContract) { riskFactors.push("NEW_CONTRACT — contract deployed less than 30 days ago"); riskScore += 25; } if (!spenderInfo.hasSourceCode) { riskFactors.push("UNVERIFIED_CONTRACT — source code not verified"); riskScore += 15; } if (!spenderInfo.isVerified && !spenderInfo.hasSourceCode) { riskScore += 20; // extra penalty for complete opacity } } return { isSuspicious: riskScore >= 50, riskScore: Math.min(100, riskScore), riskFactors, simulatedStateChanges: simulation.stateChanges, spenderInfo: approvals[0]?.spender ? await analyzeSpender(approvals[0].spender, chainId) : null }; } 

Database of Known Spender Addresses

// Whitelist of known dApp contracts const KNOWN_SAFE_SPENDERS: Record<number, Set<string>> = { 1: new Set([ // Ethereum mainnet "0x000000000022d473030f116ddee9f6b43ac78ba3", // Permit2 (Uniswap) "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", // Uniswap Universal Router "0x7a250d5630b4cf539739df2c5dacb4c659f2488d", // Uniswap V2 Router "0xe592427a0aece92de3edee1f18e0157c05861564", // Uniswap V3 Router "0x1111111254eeb25477b68fb85ed929f73a960582", // 1inch V5 "0x00000000219ab540356cbb839cbe05303d7705fa", // ETH2 Deposit Contract ]), // Arbitrum, Base, Polygon... }; // Blacklist of known scam addresses // Sources: Forta, Chainabuse, Revoke.cash, MobyMask const KNOWN_SCAM_SPENDERS: Record<number, Set<string>> = { 1: new Set([ // Updated from Forta feeds and community reports ]) }; async function analyzeSpender( spenderAddress: string, chainId: number ): Promise<SpenderInfo> { const normalizedAddress = spenderAddress.toLowerCase(); // Check whitelist const isVerified = KNOWN_SAFE_SPENDERS[chainId]?.has(normalizedAddress) ?? false; // Check blacklist const blacklisted = KNOWN_SCAM_SPENDERS[chainId]?.has(normalizedAddress) ?? false; // Check contract age const deployBlock = await getContractDeployBlock(spenderAddress, chainId); const currentBlock = await getCurrentBlock(chainId); const blockAge = currentBlock - deployBlock; const isNewContract = blockAge < 200_000; // ~30 days on Ethereum // Check verification on Etherscan const hasSourceCode = await checkEtherscanVerification(spenderAddress, chainId); return { address: spenderAddress, isVerified, blacklisted, isNewContract, hasSourceCode }; } 

Monitoring Issued Approvals

Indexer of Approved Approvals

interface ApprovalRecord { owner: string; spender: string; tokenAddress: string; tokenType: "ERC20" | "ERC721" | "ERC1155"; amount: bigint | "unlimited" | "all"; // for ERC-20 / setApprovalForAll blockNumber: number; txHash: string; timestamp: number; revoked: boolean; } // Listen for Approval and ApprovalForAll events async function indexApprovals( provider: ethers.Provider, userAddress: string ): Promise<ApprovalRecord[]> { // ERC-20 Approval(owner, spender, value) const erc20ApprovalFilter = { topics: [ ethers.id("Approval(address,address,uint256)"), ethers.zeroPadValue(userAddress, 32) // owner = userAddress ] }; // ERC-721/1155 ApprovalForAll(owner, operator, approved) const approvalForAllFilter = { topics: [ ethers.id("ApprovalForAll(address,address,bool)"), ethers.zeroPadValue(userAddress, 32) ] }; const [erc20Logs, nftLogs] = await Promise.all([ provider.getLogs({ ...erc20ApprovalFilter, fromBlock: 0, toBlock: "latest" }), provider.getLogs({ ...approvalForAllFilter, fromBlock: 0, toBlock: "latest" }) ]); return parseApprovalLogs([...erc20Logs, ...nftLogs]); } 

Alert on Approval Usage

Note: when an issued approval is used, we must distinguish legitimate operations from anomalous ones. The algorithm triggers if the transfer is initiated by the spender (not the owner).

async function monitorApprovalUsage( approval: ApprovalRecord, provider: ethers.Provider ): Promise<void> { const transferFilter = { address: approval.tokenAddress, topics: [ ethers.id("Transfer(address,address,uint256)"), ethers.zeroPadValue(approval.owner, 32) // from = owner ] }; // Subscribe to Transfer events from owner via spender provider.on(transferFilter, async (log) => { const tx = await provider.getTransaction(log.transactionHash); // Transaction sent by spender (not owner) — this is approval use if (tx.from.toLowerCase() === approval.spender.toLowerCase()) { const transferAmount = BigInt(log.data); await sendAlert({ type: "APPROVAL_USED", severity: "HIGH", owner: approval.owner, spender: approval.spender, amount: transferAmount, txHash: log.transactionHash, message: `Your approval is being used! Contract ${approval.spender} ` + `is transferring ${formatAmount(transferAmount)} tokens from your address.` }); } }); } 

Permit2 Specifics

Uniswap Permit2 requires a single approve(permit2, unlimited) for the Permit2 contract. Other protocols use it with signature-based permissions. The system recognizes this pattern:

const PERMIT2_TRANSFER_FROM_SELECTOR = "0x36c78516"; function isPermit2Transfer(calldata: string): boolean { return calldata.startsWith(PERMIT2_TRANSFER_FROM_SELECTOR); } function decodePermit2Transfer(calldata: string): { token: string; from: string; to: string; amount: bigint; } { const iface = new ethers.Interface(PERMIT2_ABI); const decoded = iface.decodeFunctionData("transferFrom", calldata); return { token: decoded.token, from: decoded.from, to: decoded.to, amount: decoded.amount }; } 

Integration into a Wallet or dApp

The system is embedded via wallet_watchAsset or a browser extension. MetaMask Snaps provides access to the onTransaction hook.

Channel Application Latency
Wallet provider hook Pre-sign screening in MetaMask Snaps < 1 sec
Browser extension Screening all dApp transactions < 2 sec
dApp UI integration SDK on dApp side < 1 sec
Email/Telegram alert Post-approval monitoring Real-time

Example: a user visits a phishing site that requests an approve for a contract deployed 2 hours ago, with unverified code and an amount of MaxUint256. The system scores the risk at 95 and blocks signing.

How Integration Protects Against Permit2 Attacks

Permit2 allows one signature to be used for an unlimited number of transfers. An attacker can obtain the signature via phishing and send permit() later. The system detects such signatures on pre-screening and tracks their usage.

How to Integrate the System: Step-by-Step Guide

  1. Install the MetaMask Snap or browser extension.
  2. Connect a simulation API (Tenderly/Alchemy) — screening will work instantly.
  3. Configure whitelist/blacklist — add known dApps and scam addresses.
  4. Start monitoring issued approvals via an event indexer.
  5. Set up alert channels (email, Telegram, webhook).
Safe Approve Checklist- Always check the spender address on Etherscan. - Limit the approve amount if possible. - Use our system for automatic pre-screening.

Savings from implementation: preventing a single attack can save from $10,000 to $500,000 of your assets. Our approval scam warning system offers 10 times faster detection than manual checks, ensuring you never miss a threat.

What Is Included as Deliverables?

  • Requirements analysis and threat modeling.
  • Development of smart contracts and monitoring scenarios.
  • Integration with wallets via Snaps and API.
  • Deployment of infrastructure (Tenderly, Alchemy).
  • Documentation and user training.
  • Technical support for 3 months.
  • Access to real-time dashboards and alert systems.

Timeline: 4 to 8 weeks. Cost starts at $15,000 for a basic integration, with higher tiers depending on complexity. Our experience in Web3 (30+ projects, 10+ wallet integrations) guarantees reliable protection against approval scams.

Order a consultation on integrating our system. Contact us to discuss your project. Get demo access to the system and evaluate its effectiveness.