Suspicious Approval Warning System Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Suspicious Approval Warning System Development
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Suspicious Approval Warning System

Token approval—one of most dangerous Web3 operations. User gives smart contract right to spend tokens without participation. Approval scam—main asset theft method via phishing and malicious dApp. Revoke.cash recorded $2.8B+ losses via approval-based attacks. Warning system detects suspicious approve requests in real time—before transaction confirmation.

Anatomy of Approval Attack

ERC-20 approve: token.approve(spender, amount) allows spender to transfer up to amount tokens.

ERC-721/ERC-1155 setApprovalForAll: grants right to all NFTs in collection. Most dangerous—one tx grants rights to entire collection.

Permit (EIP-2612): gasless signature approval without on-chain tx. User signs message—attacker sends permit() tx. User doesn't see approval in wallet until theft.

System Architecture

Two-level system:

Pre-transaction screening: Analyze pending tx before signing. Integrates via simulation API.

Post-approval monitoring: Track approved tokens, alert on anomalous usage.

Pre-Transaction Analysis

Simulation via Tenderly or Alchemy

Before signing, simulate execution and analyze state changes:

interface ApprovalAnalysis {
    isSuspicious: boolean;
    riskScore: number;           // 0-100
    riskFactors: string[];
    simulatedStateChanges: StateChange[];
    spenderInfo: SpenderInfo;
}

async function analyzeApproval(txParams: TransactionParams): Promise<ApprovalAnalysis> {
    const riskFactors = [];
    let riskScore = 0;

    // 1. Simulate transaction
    const simulation = await simulateTransaction(txParams);

    // Extract approvals 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 NFTs");
            riskScore += 40;
        }

        if (approval.amount === MaxUint256) {
            riskFactors.push("UNLIMITED_APPROVAL—unlimited token access");
            riskScore += 20;
        }

        // 3. Analyze spender contract
        const spenderInfo = await analyzeSpender(approval.spender);

        if (spenderInfo.blacklisted) {
            riskFactors.push("KNOWN_SCAMMER—address in blacklist");
            riskScore += 60;
        }

        if (spenderInfo.isNewContract) {
            riskFactors.push("NEW_CONTRACT—deployed < 30 days ago");
            riskScore += 25;
        }

        if (!spenderInfo.hasSourceCode) {
            riskFactors.push("UNVERIFIED_CONTRACT—source code not verified");
            riskScore += 15;
        }
    }

    return {
        isSuspicious: riskScore >= 50,
        riskScore: Math.min(100, riskScore),
        riskFactors,
        simulatedStateChanges: simulation.stateChanges,
        spenderInfo: approvals[0]?.spender ? await analyzeSpender(approvals[0].spender) : null
    };
}

Known Spender Database

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
    ]),
};

const KNOWN_SCAM_SPENDERS: Record<number, Set<string>> = {
    1: new Set([
        // Updated from Forta, Chainabuse, Revoke.cash, MobyMask
    ])
};

async function analyzeSpender(spenderAddress: string): Promise<SpenderInfo> {
    const normalized = spenderAddress.toLowerCase();

    const isVerified = KNOWN_SAFE_SPENDERS[chainId]?.has(normalized) ?? false;
    const blacklisted = KNOWN_SCAM_SPENDERS[chainId]?.has(normalized) ?? false;

    const deployBlock = await getContractDeployBlock(spenderAddress);
    const blockAge = currentBlock - deployBlock;
    const isNewContract = blockAge < 200_000; // ~30 days on Ethereum

    const hasSourceCode = await checkEtherscanVerification(spenderAddress);

    return { address: spenderAddress, isVerified, blacklisted, isNewContract, hasSourceCode };
}

Post-Approval Monitoring

Approval Indexer

Listen to Approval and ApprovalForAll events:

async function indexApprovals(provider: ethers.Provider, userAddress: string) {
    const erc20ApprovalFilter = {
        topics: [
            ethers.id("Approval(address,address,uint256)"),
            ethers.zeroPadValue(userAddress, 32) // owner = userAddress
        ]
    };

    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

When approval is used—not always bad (legitimate dApp). Alert on anomalous usage:

async function monitorApprovalUsage(approval: ApprovalRecord, provider: ethers.Provider) {
    const transferFilter = {
        address: approval.tokenAddress,
        topics: [
            ethers.id("Transfer(address,address,uint256)"),
            ethers.zeroPadValue(approval.owner, 32)  // from = owner
        ]
    };

    provider.on(transferFilter, async (log) => {
        const tx = await provider.getTransaction(log.transactionHash);

        // Tx sent by spender (not owner)—approval usage
        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,
                message: `Your approval is being used! Contract ${approval.spender} transfers ${transferAmount} tokens.`
            });
        }
    });
}

Permit2 Specifics

Uniswap Permit2—new standard where user does one approve(permit2, unlimited) for Permit2 contract, then all protocols work via signature-based permissions. System must understand 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 decoded;
}

Integration into Wallet or dApp

Warning system integrates via MetaMask Snaps (pre-sign screening), browser extension (intercept dApp txs), or SDK in dApp.

Channel Use Case Latency
Wallet provider hook MetaMask Snaps pre-sign < 1 sec
Browser extension All dApp txs screening < 2 sec
dApp UI SDK Protocol-level integration < 1 sec
Email/Telegram Post-approval monitoring Real-time

MetaMask Snaps most promising path—Snap gets onTransaction hook, show warning to user before signing.