Honeypot Checks

Honeypot checks is the core part of Honeypot.is, the very reason that this project exists. On this page we'll dive into the IsHoneypot endpoint and it's detailed response.

GET/v2/IsHoneypot

Check a token

This endpoint allows you to retrieve Honeypot details for a token. Please continue reading below for explanation of the response. The sample response includes fake data to showcase potential responses.

Required attributes

  • Name
    address
    Type
    address
    Description

    The address of the token you want to check. Also supports the pair/pool address.

Optional attributes

  • Name
    chainID
    Type
    integer
    Description

    The chain you want to check the token on. If not specified, it will try to find the most suitable chain based on liquidity.

  • Name
    pair
    Type
    address
    Description

    The pair address you want to check with. If not specified, it will try to find the most suitable pair based on liquidity..

  • Name
    simulateLiquidity
    Type
    bool
    Description

    If set to true, the endpoint will try to simulate liquidity for the token IF no pair exists. If there is a pair for the token, it will use the pair instead of simulating. To force simulate liquidity, look at forceSimulateLiquidity.

    NOTE: Requires chainID.

  • Name
    forceSimulateLiquidity
    Type
    bool
    Description

    If set to true, the endpoint will try to simulate liquidity for the token. This is useful when you want to check a token that is not yet listed on any DEX.

    NOTE: Requires chainID.

Request

GET
/v2/IsHoneypot
curl -G https://api.honeypot.is/v2/IsHoneypot \
  -H "X-API-KEY: {APIKEY}" \
  -d address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48

Response

{
"token": {
    "name": "USD Coin",
    "symbol": "USDC",
    "decimals": 6,
    "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "totalHolders": 1755847
},
"withToken": {
    "name": "Ether",
    "symbol": "ETH",
    "decimals": 18,
    "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "totalHolders": 671397
},
"summary": {
    "risk": "very_low",
    "riskLevel": 0,
},
"simulationSuccess": true,
// "simulationError": "Insufficient liquidity for this trade."
"honeypotResult": {
    "isHoneypot": false
    // "honeypotReason": "PancakeSwap: TRANSFER_FROM_FAILED"
},
"simulationResult": {
    // USDC doesn't actually have maxBuy and maxSell, but this is just an example.
    "maxBuy": {
        "token": 500000,
        "tokenWei": "500000000000000",
        "withToken": 9.62705611028878,
        "withTokenWei": "9627056110288779597"
    },
    "maxSell": {
        "token": 500000,
        "tokenWei": "500000000000000",
        "withToken": 9.62705611028878,
        "withTokenWei": "9627056110288779597"
    },
    "buyTax": 0,
    "sellTax": 0,
    "transferTax": 0,
    "buyGas": "154591",
    "sellGas": "107886"
},
"holderAnalysis": {
    // NOTE: This is NOT the number of holders for the token.
    // This is only how many holders we are analyzing.
    // Look at the "token" section for the actual number of holders.
    "holders": "2",
    "successful": "2",
    "failed": "0",
    "siphoned": "0",
    "averageTax": 0,
    "averageGas": 134250.5,
    "highestTax": 0,
    "highTaxWallets": "0",
    "taxDistribution": [
        {
            "tax": 0,
            "count": 2
        }
    ]
},
"flags": [],
"contractCode": {
    "openSource": true,
    "rootOpenSource": true,
    "isProxy": true,
    "hasProxyCalls": true
},
"chain": {
    "id": "1",
    "name": "Ethereum",
    "shortName": "ETH",
    "currency": "ETH"
},
"router": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
"pair": {
    "pair": {
        "name": "Uniswap V2: USDC-WETH",
        "address": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc",
        "token0": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "token1": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
        // Type will be either "UniswapV2" or "UniswapV3", even on Pancakeswap.
        "type": "UniswapV2",
    },
    "chainId": "1",
    "reserves0": "37345754334572",
    "reserves1": "18943616626757258383905",
    "liquidity": 74766200.17781314, // USD Value.
    "router": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
    "createdAtTimestamp": "1620250931",
    "creationTxHash": "0x125e0b641d4a4b08806bf52c0c6757648c9963bcda8681e4f996f09e00d4c2cc"
},
"pairAddress": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"
}

Summary

The summary object contains a brief summary of the results, it is an easy way to quickly parse the response. Most of the summary is derived from other data in the response. The summary object is guaranteed to be present. riskLevel is not present if risk is unknown.

flags is an array (may be empty/not present) of flags. List of flags and their descriptions can be found in Summary Flags section. Flags can be warnings or purely informational.

The risk field is the risk level of the token. It is always present.
The risk will be one of: unknown, very_low, low, medium, high, very_high, honeypot.

NOTE: The summary is still new. If you see any inconsistencies or have suggestions, please let us know. We will be expanding what risk level is influenced by. It is recommended to use riskLevel field instead of the risk field for programmatic use, as we may expand amount of risks in the future.

  • Name
    unknown
    Type
    Description

    The risk level of the token is unknown.
    riskLevel is not present.

  • Name
    very_low
    Type
    Description

    The token is very low risk. Only whitelisted tokens can get this rating, such as WETH, USDC, USDT etc...
    riskLevel is 0.

  • Name
    low
    Type
    Description

    The token is low risk. Honeypot didn't find anything suspicious about the token.
    riskLevel is between 1 and 19 (inclusive).

    NOTE: In the future, additional requirements may be added, such as liquidity burned/locked, or a certain amount of time since launch.

  • Name
    medium
    Type
    Description

    The token is medium risk. There's some potential issues. Caution is advised.
    riskLevel is between 20 and 59 (inclusive).

  • Name
    high
    Type
    Description

    The token is high risk. There are some issues that need to be considered. Caution is advised.
    riskLevel is between 60 and 79 (inclusive).

  • Name
    very_high
    Type
    Description

    The token is very high risk. It is likely a honeypot, but not certain yet.
    riskLevel is between 80 and 89 (inclusive).

  • Name
    honeypot
    Type
    Description

    The token is almost certainly a honeypot.
    riskLevel is between 90 and 100 (inclusive).

Summaries

GET
/v2/IsHoneypot
"summary": {
  "risk": "honeypot",
  "riskLevel": 100,
  "flags": [
    {
      "flag": "high_fail_rate",
      "description": "Transfers between normal wallets are blockedA very high amount of users can not sell their tokens.",
      "severity": "critical",
      "severityIndex": 20
    },
    {
      "flag": "CLOSED_SOURCE",
      "description": "The source code is not available, allowing for hidden functionality.",
      "severity": "high",
      "severityIndex": 16
    }
  ]
}

Simulation Success

The simulationSuccess object is a bool that indicates whether the simulation was successful. If it is false, the simulationError object will contain the error message. If this is true, the honeypotResult and simulationResult objects will be present. However honeypotResult can still be present if the simulation was not successful, if there's enough data to determine the honeypot status of the token from other sources such as holder analysis.

Response

GET
/v2/IsHoneypot
  {
    // ...
    "simulationSuccess": true,
    // ...
  }

Honeypot Result

The honeypotResult object contains the honeypot status of the token. This field is not guaranteed to be present, for example in cases where we were unable to check the status of the token. if honeypotResult.isHoneypot is true, the honeypotResult.honeypotReason object will contain the reason why it is a honeypot.

Response

GET
/v2/IsHoneypot
{
  // ...
  "honeypotResult": {
    "isHoneypot": true,
    "honeypotReason": "Insufficient liquidity"
  },
  // ...
}

Simulation Result

The simulationResult object contains the simulation result of the token. This field is not guaranteed to be present, for example if the token is a honeypot or the simulation failed.

The maxBuy and maxSell objects are not guaranteed to be present. They will only be present if we detected them. If the token has unlimited max buy or sell, the fields will not be present.

The token and tokenWei refer to the token that is being scanned/tested.

The withToken and withTokenWei refer to the other token in the pair that is being used to buy the token.

The token and withToken are converted based on the decimals of the token. The tokenWei and withTokenWei are the raw values.

Response

GET
/v2/IsHoneypot
{
  "simulationResult": {
    "maxBuy": {
        "token": 500000,
        "tokenWei": "500000000000000",
        "withToken": 9.62705611028878,
        "withTokenWei": "9627056110288779597"
    },
    "maxSell": {
        "token": 500000,
        "tokenWei": "500000000000000",
        "withToken": 9.62705611028878,
        "withTokenWei": "9627056110288779597"
    },
    "buyTax": 0,
    "sellTax": 0,
    "transferTax": 0,
    "buyGas": "154591",
    "sellGas": "107886"
  },
}

Holder Analysis

The holderAnalysis object contains the analysis of the holders of the token. This field is not guaranteed to be present.

The holders field is the amount of holders that we have analyzed, and NOT the number of actual holders for the token.

The successful field is the amount of holders that can sell their holdings.

The failed field is the amount of holders that cannot sell their holdings.

The siphoned field is the amount of holders that have been siphoned - their tokens have been transferred without their consent. In some very rare cases, legit transfers are marked as siphoned - we are working on reducing the false positives.

The averageTax field is the average tax that the holders have to pay when they sell their holdings.

The averageGas field is the average gas that the holders have to pay when they sell their holdings.

The highestTax field is the highest tax that a holder would have to pay.

The highTaxWallets field is the amount of wallets that have to pay >=50% tax.

The taxDistribution field is an array of objects that contains the tax percentage, rounded to a whole number, and how many wallets have to pay that percentage.

Response

GET
/v2/IsHoneypot
"holderAnalysis": {
  "holders": "2", // This is NOT the number of holders for the token.
  "successful": "2",
  "failed": "0",
  "siphoned": "0",
  "averageTax": 0,
  "averageGas": 134250.5,
  "highestTax": 0,
  "highTaxWallets": "0",
  "taxDistribution": [
    {
      "tax": 0,
      "count": 2
    }
  ]
},

Flags

The flags is an array of string objects, it contains warnings about the token that we have picked up.

It's recommended to use the summary/flags instead. This object is deprecated, but will still be present for backwards compatibility.

Response

GET
/v2/IsHoneypot
  {
    "flags": ["TRANSFER_BLOCKED", "EXTREMELY_HIGH_TAXES"],
  }

Contract Code

The contractCode object contains information about the contract code of the token. Not guaranteed to be present. Currently, it only contains information if it's open source and if it's a proxy contract.

Note, the results from here are cached and may be outdated. Look at Contract Verification endpoints if you want more up-to-date information.

  • Name
    openSource
    Type
    Description

    If the contract is open source. Unlike other detectors, it's not enough for the token itself to be open source. It requires every single contract called during the buy/sell process to be open source.

  • Name
    rootOpenSource
    Type
    Description

    If the root contract is open source. This is the token contract that is being scanned.

  • Name
    isProxy
    Type
    Description

    If the contract is a proxy contract - essentially if a delegatecall is executed from the token contract.

  • Name
    hasProxyCalls
    Type
    Description

    If the contract has proxy calls. This differs from isProxy as this is set to true if there is ANY delegatecall in the execution path, not just from the contract.

    Example 1: TOKEN -> DELEGATECALL CONTRACT A = hasProxyCalls is true, isProxy is true.

    Example 2: TOKEN -> CALL CONTRACT A -> DELEGATECALL CONTRACT B = hasProxyCalls is true, isProxy is false.

Response

GET
/v2/IsHoneypot
{
  // ...
  "contractCode": {
    "openSource": true,
    "rootOpenSource": true,
    "isProxy": true,
    "hasProxyCalls": true
  },
  // ...
}