> ## Documentation Index
> Fetch the complete documentation index at: https://docs.webacy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Consumer Wallet Security

> Build secure consumer wallets with address poisoning detection, transaction preview, EIP-712 signature analysis, and phishing URL screening under 500ms.

Your user pasted an address from their clipboard. It looked right—but it wasn't. The first four characters matched. The last four matched. But in the middle, a scammer had swapped characters. \$68 million in WBTC, gone in one transaction. This guide shows you how to protect your users from these attacks before they happen.

## Why Wallets Need Security

<CardGroup cols={3}>
  <Card title="Send Protection" icon="paper-plane">
    Verify addresses before your users send funds to scammers
  </Card>

  <Card title="Transaction Preview" icon="eye">
    Show users what they're signing before they sign it
  </Card>

  <Card title="Phishing Defense" icon="shield-virus">
    Block malicious dApps before they drain wallets
  </Card>
</CardGroup>

**Why wallet developers choose Webacy:**

* **Address poisoning detection** — The attack that stole \$68M in one transaction
* **Transaction simulation** — Show users exactly what will happen before signing
* **EIP-712 signature analysis** — Catch permit phishing attacks
* **URL screening** — Block known phishing sites in your dApp browser
* **Sub-500ms response times** — Security without blocking the user experience

***

## Prerequisites

Before implementing wallet security, ensure you have:

* A Webacy API key ([sign up here](https://developers.webacy.co/billing))
* Basic familiarity with REST APIs or the [Webacy SDK](../sdk/installation)
* Your wallet's send flow and transaction signing identified for integration points

***

## Send Flow Protection

The send flow is where users are most vulnerable. A simple address check can save them from losing everything.

### Quick Profile Before Sending

Before showing the send confirmation, check the destination address.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.webacy.com/addresses/0xd9A1C3788D81257612E2581A6ea0aDa244853a91/quick-profile?chain=eth" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```typescript TypeScript theme={null}
  import { ThreatClient, Chain } from '@webacy-xyz/sdk';

  const client = new ThreatClient({ apiKey: process.env.WEBACY_API_KEY });

  const profile = await client.addresses.getQuickProfile(
    '0xd9A1C3788D81257612E2581A6ea0aDa244853a91',
    { chain: Chain.ETH }
  );

  console.log(`Risk score: ${profile.riskScore}`);
  console.log(`Risk level: ${profile.riskLevel}`);
  console.log(`Account age: ${profile.accountAge} days`);
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.webacy.com/addresses/0xd9A1C3788D81257612E2581A6ea0aDa244853a91/quick-profile",
      params={"chain": "eth"},
      headers={"x-api-key": "YOUR_API_KEY"}
  )
  profile = response.json()
  ```
</CodeGroup>

**Use the response to guide users:**

| Risk Level | Action                        |
| ---------- | ----------------------------- |
| `low`      | Proceed normally              |
| `medium`   | Show caution banner           |
| `high`     | Require explicit confirmation |
| `critical` | Block and explain why         |

### Address Poisoning Detection

Address poisoning attacks are devastating because they exploit user trust. Scammers create addresses that look nearly identical to legitimate ones.

<Warning>
  **Real Case**: In May 2024, a victim copied what they thought was their own address from transaction history. The attacker's address matched the first and last characters perfectly. \$68 million in WBTC, gone.
</Warning>

**Can you spot the difference?**

|              | Address                                      |
| ------------ | -------------------------------------------- |
| ✅ Legitimate | `0xd9A1b0B1e1aE382DbDc898Ea68012FfcB2853a91` |
| ❌ Attacker   | `0xd9A1C3788D81257612E2581A6ea0aDa244853a91` |

Both start with `0xd9A1`. Both end with `53a91`. The scammer generated a vanity address specifically to match the victim's transaction history.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.webacy.com/addresses/0xd9A1C3788D81257612E2581A6ea0aDa244853a91/poisoning?chain=eth" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```typescript TypeScript theme={null}
  const poisoning = await client.addresses.checkPoisoning(
    '0xd9A1C3788D81257612E2581A6ea0aDa244853a91',
    { chain: Chain.ETH }
  );

  if (poisoning.is_poisoned) {
    // Block the transaction and show warning
    showPoisoningWarning({
      message: 'This address appears to be part of an address poisoning attack.',
      similarAddresses: poisoning.similar_addresses,
      recommendation: 'Verify the full address character by character.'
    });
  }
  ```

  ```python Python theme={null}
  response = requests.get(
      "https://api.webacy.com/addresses/0xd9A1C3788D81257612E2581A6ea0aDa244853a91/poisoning",
      params={"chain": "eth"},
      headers={"x-api-key": "YOUR_API_KEY"}
  )
  poisoning = response.json()
  ```
</CodeGroup>

<Tip>
  **Integration tip**: Run this check whenever a user pastes an address. The 300ms latency is invisible to users—but catching a poisoning attack is priceless.
</Tip>

### Sanctions Screening

Prevent users from sending to sanctioned addresses and protect your platform from regulatory risk.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.webacy.com/addresses/sanctioned/0x098B716B8Aaf21512996dC57EB0615e2383E2f96?chain=eth" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```typescript TypeScript theme={null}
  const sanctions = await client.addresses.checkSanctioned(
    '0x098B716B8Aaf21512996dC57EB0615e2383E2f96',
    { chain: Chain.ETH }
  );

  if (sanctions.is_sanctioned) {
    // Block transaction to sanctioned address
    blockTransaction({
      reason: 'This address is on the OFAC sanctions list.',
      canOverride: false
    });
  }
  ```

  ```python Python theme={null}
  response = requests.get(
      "https://api.webacy.com/addresses/sanctioned/0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
      params={"chain": "eth"},
      headers={"x-api-key": "YOUR_API_KEY"}
  )
  ```
</CodeGroup>

***

## Transaction Preview

Show users exactly what they're about to sign. Transaction simulation catches drainers, malicious approvals, and unexpected asset transfers.

### Pre-Signing Simulation

Simulate the transaction before the user signs to reveal what will actually happen.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.webacy.com/scan/transaction" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "walletAddress": "0xUserAddress...",
      "tx": {
        "from": "0xUserAddress...",
        "to": "0xContractAddress...",
        "data": "0xTransactionData...",
        "value": "0x0"
      },
      "chain": 1,
      "domain": "app.example.com"
    }'
  ```

  ```typescript TypeScript theme={null}
  const simulation = await client.scan.scanTransaction(
    '0xUserAddress...',
    {
      tx: {
        from: '0xUserAddress...',
        to: '0xContractAddress...',
        data: '0xTransactionData...',
        value: '0x0',
      },
      chain: 1, // Ethereum mainnet
      domain: 'app.example.com',
    }
  );

  // Show asset changes to user
  for (const change of simulation.assetChanges ?? []) {
    if (change.type === 'transfer_out') {
      console.log(`You will send: ${change.amount} ${change.symbol}`);
    } else if (change.type === 'transfer_in') {
      console.log(`You will receive: ${change.amount} ${change.symbol}`);
    }
  }

  // Check for warnings
  if (simulation.warnings.length > 0) {
    console.warn('Warnings detected:', simulation.warnings);
  }
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.webacy.com/scan/transaction",
      headers={
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={
          "walletAddress": "0xUserAddress...",
          "tx": {
              "from": "0xUserAddress...",
              "to": "0xContractAddress...",
              "data": "0xTransactionData...",
              "value": "0x0"
          },
          "chain": 1,
          "domain": "app.example.com"
      }
  )
  simulation = response.json()
  ```
</CodeGroup>

**Key response fields:**

| Field            | Description                                       |
| ---------------- | ------------------------------------------------- |
| `assetChanges[]` | What tokens/NFTs will move and in which direction |
| `riskLevel`      | `low`, `medium`, `high`, or `critical`            |
| `warnings[]`     | Specific risks detected (drainer, phishing, etc.) |

### EIP-712 Signature Analysis

Permit signatures are the most dangerous attack vector. A user can lose everything without sending a single transaction—just by signing a message.

<Warning>
  **How Permit Phishing Works**: The user signs what looks like a simple message. In reality, they've authorized a contract to spend all their tokens. Hours or days later, the attacker drains everything.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.webacy.com/scan/eip712" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "walletAddress": "0xUserAddress...",
      "msg": {
        "from": "0xUserAddress...",
        "data": {
          "types": {
            "Permit": [
              {"name": "owner", "type": "address"},
              {"name": "spender", "type": "address"},
              {"name": "value", "type": "uint256"}
            ]
          },
          "primaryType": "Permit",
          "message": {
            "owner": "0xUserAddress...",
            "spender": "0xSuspiciousAddress...",
            "value": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
          }
        }
      },
      "domain": "suspicious-site.com"
    }'
  ```

  ```typescript TypeScript theme={null}
  const result = await client.scan.scanEip712(
    '0xUserAddress...',
    {
      msg: {
        from: '0xUserAddress...',
        data: {
          types: {
            Permit: [
              { name: 'owner', type: 'address' },
              { name: 'spender', type: 'address' },
              { name: 'value', type: 'uint256' },
            ],
          },
          primaryType: 'Permit',
          message: {
            owner: '0xUserAddress...',
            spender: '0xSuspiciousAddress...',
            value: '115792089237316195423570985008687907853269984665640564039457584007913129639935',
          },
        },
      },
      domain: 'suspicious-site.com',
    }
  );

  if (result.riskLevel === 'high' || result.riskLevel === 'critical') {
    // Block signature and warn user
    showSignatureWarning({
      type: result.messageType,
      risk: result.riskLevel,
      message: 'This signature could give unlimited access to your tokens.'
    });
  }
  ```

  ```python Python theme={null}
  response = requests.post(
      "https://api.webacy.com/scan/eip712",
      headers={
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={
          "walletAddress": "0xUserAddress...",
          "msg": {
              "from": "0xUserAddress...",
              "data": {
                  "types": {
                      "Permit": [
                          {"name": "owner", "type": "address"},
                          {"name": "spender", "type": "address"},
                          {"name": "value", "type": "uint256"}
                      ]
                  },
                  "primaryType": "Permit",
                  "message": {
                      "owner": "0xUserAddress...",
                      "spender": "0xSuspiciousAddress...",
                      "value": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
                  }
              }
          },
          "domain": "suspicious-site.com"
      }
  )
  ```
</CodeGroup>

<Tip>
  **The max uint256 red flag**: If you see `value: "115792089237316195423570985008687907853269984665640564039457584007913129639935"`, that's unlimited approval. Always flag this for users.
</Tip>

***

## Phishing Protection

If your wallet has a dApp browser, you need URL screening.

### URL Scanning

Check URLs before allowing users to connect their wallet.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.webacy.com/url/check" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"url": "https://uniswap-claim.com"}'
  ```

  ```typescript TypeScript theme={null}
  const result = await client.url.check('https://uniswap-claim.com');

  if (result.isPhishing) {
    // Block the connection
    blockDappConnection({
      url: 'https://uniswap-claim.com',
      reason: 'This site has been identified as a phishing site.',
      categories: result.categories
    });
  }
  ```

  ```python Python theme={null}
  response = requests.post(
      "https://api.webacy.com/url/check",
      headers={
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={"url": "https://uniswap-claim.com"}
  )
  ```
</CodeGroup>

***

## Approval Management

Help users understand and manage their existing token approvals.

### Get Risky Approvals

Show users their current approvals and highlight dangerous ones.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.webacy.com/wallets/0xUserAddress.../approvals?chain=eth" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```typescript TypeScript theme={null}
  const approvals = await client.wallets.getApprovals(
    '0xUserAddress...',
    { chain: Chain.ETH }
  );

  // Categorize approvals by risk
  const riskyApprovals = approvals.approvals.filter(
    a => a.isUnlimited || a.spenderRisk === 'high'
  );

  console.log(`Found ${riskyApprovals.length} risky approvals`);

  for (const approval of riskyApprovals) {
    console.log(`${approval.symbol} approved to ${approval.spenderName || approval.spender}`);
    console.log(`  Amount: ${approval.isUnlimited ? 'UNLIMITED' : approval.amount}`);
  }
  ```

  ```python Python theme={null}
  response = requests.get(
      "https://api.webacy.com/wallets/0xUserAddress.../approvals",
      params={"chain": "eth"},
      headers={"x-api-key": "YOUR_API_KEY"}
  )
  ```
</CodeGroup>

**Help users clean up:**

* Show unlimited approvals prominently
* Flag approvals to contracts that no longer exist
* Identify approvals to known drainer contracts
* Provide easy revoke functionality

***

## Complete Integration Workflow

### Send Flow

```mermaid theme={null}
flowchart TD
    A[User Enters Address] --> B{Address Poisoning Check}
    B -->|Poisoned| C["BLOCK + Show Warning"]
    B -->|Clear| D{Sanctions Check}
    D -->|Sanctioned| E["BLOCK + Compliance Notice"]
    D -->|Clear| F{Quick Profile}
    F -->|High Risk| G["WARN + Require Confirmation"]
    F -->|Medium Risk| H["Show Caution Banner"]
    F -->|Low Risk| I[Proceed to Confirmation]
    G --> I
    H --> I
```

### Transaction Signing Flow

```mermaid theme={null}
flowchart TD
    A[Transaction Request] --> B{Is EIP-712 Signature?}
    B -->|Yes| C[Scan EIP-712]
    B -->|No| D[Simulate Transaction]
    C --> E{Risk Level?}
    D --> E
    E -->|Critical| F["BLOCK Transaction"]
    E -->|High| G["Show Strong Warning"]
    E -->|Medium| H["Show Asset Changes + Caution"]
    E -->|Low| I["Show Asset Changes"]
    G --> J{User Confirms?}
    H --> J
    I --> K[Sign Transaction]
    J -->|Yes| K
    J -->|No| L[Cancel]
```

### Full TypeScript Implementation

<Accordion title="Complete Wallet Security Module">
  ```typescript theme={null}
  import { ThreatClient, Chain } from '@webacy-xyz/sdk';

  const client = new ThreatClient({
    apiKey: process.env.WEBACY_API_KEY,
    defaultChain: Chain.ETH,
  });

  // Send flow protection
  async function validateSendAddress(address: string, chain: Chain) {
    // 1. Address poisoning (most critical)
    const poisoning = await client.addresses.checkPoisoning(address, { chain });
    if (poisoning.is_poisoned) {
      return {
        allowed: false,
        severity: 'critical',
        reason: 'Address poisoning attack detected',
        details: 'This address looks similar to legitimate addresses and may be part of a scam.'
      };
    }

    // 2. Sanctions check (compliance)
    const sanctions = await client.addresses.checkSanctioned(address, { chain });
    if (sanctions.is_sanctioned) {
      return {
        allowed: false,
        severity: 'critical',
        reason: 'Sanctioned address',
        details: 'This address is on the OFAC sanctions list.'
      };
    }

    // 3. Quick profile (risk assessment)
    const profile = await client.addresses.getQuickProfile(address, { chain });

    if (profile.riskLevel === 'critical') {
      return {
        allowed: false,
        severity: 'critical',
        reason: 'Extremely high risk address',
        riskScore: profile.riskScore
      };
    }

    if (profile.riskLevel === 'high') {
      return {
        allowed: true,
        severity: 'high',
        requireConfirmation: true,
        reason: 'High risk address detected',
        riskScore: profile.riskScore
      };
    }

    return {
      allowed: true,
      severity: profile.riskLevel,
      riskScore: profile.riskScore
    };
  }

  // Transaction preview
  async function previewTransaction(
    userAddress: string,
    txData: { to: string; data: string; value: string },
    chain: number,
    dappDomain?: string
  ) {
    const simulation = await client.scan.scanTransaction(userAddress, {
      tx: {
        from: userAddress,
        to: txData.to,
        data: txData.data,
        value: txData.value,
      },
      chain,
      domain: dappDomain,
    });

    return {
      riskLevel: simulation.riskLevel,
      warnings: simulation.warnings,
      assetChanges: simulation.assetChanges,
      shouldBlock: simulation.riskLevel === 'critical',
      requiresExtraConfirmation: simulation.riskLevel === 'high',
    };
  }

  // Signature analysis
  async function analyzeSignature(
    userAddress: string,
    typedData: object,
    dappDomain: string
  ) {
    const result = await client.scan.scanEip712(userAddress, {
      msg: {
        from: userAddress,
        data: typedData,
      },
      domain: dappDomain,
    });

    return {
      riskLevel: result.riskLevel,
      messageType: result.messageType,
      shouldBlock: result.riskLevel === 'critical',
      isPermit: result.messageType?.toLowerCase().includes('permit'),
    };
  }

  // URL screening for dApp browser
  async function checkDappUrl(url: string) {
    const result = await client.url.check(url);

    return {
      safe: !result.isPhishing && !result.isMalware,
      isPhishing: result.isPhishing,
      isMalware: result.isMalware,
      riskScore: result.riskScore,
      categories: result.categories,
    };
  }
  ```
</Accordion>

***

## Example Addresses for Testing

### Address Poisoning

| Address                                      | Chain | Description                                |
| -------------------------------------------- | ----- | ------------------------------------------ |
| `0xd9A1C3788D81257612E2581A6ea0aDa244853a91` | ETH   | Known poisoned address (\$68M WBTC attack) |
| `0x5f90e59d0a03fd2f8c56b8cc896c5b42594eb3a0` | ETH   | \$50M address poisoning drain              |

### Sanctioned Addresses

| Address                                      | Chain | Attribution                  |
| -------------------------------------------- | ----- | ---------------------------- |
| `0x098B716B8Aaf21512996dC57EB0615e2383E2f96` | ETH   | Lazarus Group (Ronin Bridge) |
| `0x566f827a4988d4a3eb9da469d8d3d0b536da196e` | ETH   | OFAC SDN List                |

### Phishing & Drainers

| Address                                      | Chain | Attribution                     |
| -------------------------------------------- | ----- | ------------------------------- |
| `0x84672cc56b6dad30cfa5f9751d9ccae6c39e29cd` | ETH   | Permit phishing drainer         |
| `0xe7d13137923142a0424771e1778865b88752b3c7` | ETH   | WalletConnect phishing campaign |
| `0x624Fc3Dc249E37E8BFd3e834C4dF81Ff2dA1D0Ca` | BSC   | Malicious Permit scammer        |

### Clean Addresses (for comparison)

| Address                                      | Chain | Description                 |
| -------------------------------------------- | ----- | --------------------------- |
| `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` | ETH   | Vitalik's wallet (low risk) |

***

## API Quick Reference

| Endpoint                                 | Use Case                | Response Time |
| ---------------------------------------- | ----------------------- | ------------- |
| `GET /addresses/{address}/quick-profile` | Fast risk assessment    | \~200ms       |
| `GET /addresses/{address}/poisoning`     | Address poisoning check | \~300ms       |
| `GET /addresses/sanctioned/{address}`    | Sanctions screening     | \~100ms       |
| `POST /scan/transaction`                 | Transaction simulation  | \~500ms       |
| `POST /scan/eip712`                      | Signature analysis      | \~300ms       |
| `POST /url/check`                        | URL screening           | \~200ms       |
| `GET /wallets/{address}/approvals`       | Token approvals         | \~400ms       |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Get Your API Key" icon="key" href="https://developers.webacy.co/billing">
    Start protecting users today
  </Card>

  <Card title="API Reference" icon="book" href="../api-reference/introduction">
    Complete endpoint documentation
  </Card>

  <Card title="Install the SDK" icon="download" href="../sdk/installation">
    TypeScript SDK for faster integration
  </Card>

  <Card title="Risk Tags Reference" icon="tags" href="../essentials/risk-tags">
    Understand what each risk means
  </Card>
</CardGroup>
