description | layout | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Learn how to use Airstack to filter out spam ERC20s and check whether an ERC20 token is a spam or not. |
|
Airstack provides easy-to-use ERC20 token APIs for enriching Web3 applications with onchain and offchain ERC20 token data from Ethereum, Base, Degen Chain, and other Airstack-supported chains.
When indexing any new token, Airstack takes into consideration contract deployer address history, and other factors to determine if the token might be spam.
Those contracts are the marked spam and can be filtered out. If you think that a given contract was incorrectly labeled as spam, please reach out to us [email protected].
In this guide you will learn how to use Airstack to:
- Get Non-Spam ERC20 Token Balances Of Users
- Check If ERC20 Token(s) Are Spam Or Not
- Show All Non-Spam ERC20 Tokens
- An Airstack account
- Basic knowledge of GraphQL
If you are using JavaScript/TypeScript or Python, Install the Airstack SDK:
{% tabs %} {% tab title="npm" %} React
npm install @airstack/airstack-react
Node
npm install @airstack/node
{% endtab %}
{% tab title="yarn" %} React
yarn add @airstack/airstack-react
Node
yarn add @airstack/node
{% endtab %}
{% tab title="pnpm" %} React
pnpm install @airstack/airstack-react
Node
pnpm install @airstack/node
{% endtab %}
{% tab title="pip" %}
pip install airstack
{% endtab %} {% endtabs %}
Then, add the following snippets to your code:
{% tabs %} {% tab title="React" %}
import { init, useQuery } from "@airstack/airstack-react";
init("YOUR_AIRSTACK_API_KEY");
const query = `YOUR_QUERY`; // Replace with GraphQL Query
const Component = () => {
const { data, loading, error } = useQuery(query);
if (data) {
return <p>Data: {JSON.stringify(data)}</p>;
}
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Error: {error.message}</p>;
}
};
{% endtab %}
{% tab title="Node" %}
import { init, fetchQuery } from "@airstack/node";
init("YOUR_AIRSTACK_API_KEY");
const query = `YOUR_QUERY`; // Replace with GraphQL Query
const { data, error } = await fetchQuery(query);
console.log("data:", data);
console.log("error:", error);
{% endtab %}
{% tab title="Python" %}
import asyncio
from airstack.execute_query import AirstackClient
api_client = AirstackClient(api_key="YOUR_AIRSTACK_API_KEY")
query = """YOUR_QUERY""" # Replace with GraphQL Query
async def main():
execute_query_client = api_client.create_execute_query_object(
query=query)
query_response = await execute_query_client.execute_query()
print(query_response.data)
asyncio.run(main())
{% endtab %} {% endtabs %}
To access the Airstack APIs in other languages, you can use https://api.airstack.xyz/gql as your GraphQL endpoint.
🤖 AI Natural Language
Airstack provides an AI solution for you to build GraphQL queries to fulfill your use case easily. You can find the AI prompt of each query in the demo's caption or title for yourself to try.
Airstack AI (Demo)
First, you can fetch the ERC20 token balances of user(s) and show each ERC20 token whether they are a spam or not using the token.isSpam
field from the TokenBalances
API.
With the query below, provide an array of users' 0x addresses, ENS domains, cb.ids, Lens profiles, Farcaster fnames/fids to owner
input:
{% embed url="https://app.airstack.xyz/query/gd2fCLJFjJ" %} Show users' ERC20 token balances and check if each ERC20 token is a spam or not {% endembed %}
{% tabs %} {% tab title="Query" %}
query MyQuery {
Ethereum: TokenBalances(
input: {
filter: {
owner: {
_in: [
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
"vitalik.eth"
"lens/@vitalik"
"fc_fname:vitalik.eth"
]
}
tokenType: { _eq: ERC20 }
}
blockchain: ethereum
}
) {
TokenBalance {
tokenAddress
token {
isSpam
name
symbol
}
}
}
Polygon: TokenBalances(
input: {
filter: {
owner: {
_in: [
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
"vitalik.eth"
"lens/@vitalik"
"fc_fname:vitalik.eth"
]
}
tokenType: { _eq: ERC20 }
}
blockchain: polygon
}
) {
TokenBalance {
tokenAddress
token {
isSpam
name
symbol
}
}
}
Base: TokenBalances(
input: {
filter: {
owner: {
_in: [
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
"vitalik.eth"
"lens/@vitalik"
"fc_fname:vitalik.eth"
]
}
tokenType: { _eq: ERC20 }
}
blockchain: base
}
) {
TokenBalance {
tokenAddress
token {
isSpam
name
symbol
}
}
}
}
{% endtab %}
{% tab title="Response" %}
{
"data": {
"Ethereum": {
"TokenBalance": [
{
"tokenAddress": "0xbaaa3b3b00def381c0794d0253a4a1ef3b2a9fbc",
"token": {
"isSpam": false, // Not a spam ERC20 token
"name": "Monkeys George",
"symbol": "Monkeys George"
}
},
{
"tokenAddress": "0xfe7377b49567387345b44fc603f0fa3d294e62c7",
"token": {
"isSpam": false, // A Spam ERC20 token
"name": "THE PEOPLEs MONEY",
"symbol": "TPM"
}
},
// Other Ethereum ERC20 tokens
]
},
"Polygon": {
"TokenBalance": [
{
"tokenAddress": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
"token": {
"isSpam": false, // Not a spam ERC20 token
"name": "(PoS) Tether USD",
"symbol": "USDT"
}
},
{
"tokenAddress": "0xb27cea9e38eeb387d3b0672287ca304fbff00b7c",
"token": {
"isSpam": true, // A spam ERC20 token
"name": "Lens Rewards",
"symbol": "Claim via lens-rewards.xyz"
}
},
// Other Polygon ERC20 tokens
]
},
"Base": {
"TokenBalance": [
{
"tokenAddress": "0xac1bd2486aaf3b5c0fc3fd868558b082a531b2b4",
"token": {
"isSpam": false, // Not a spam ERC20 token
"name": "Toshi",
"symbol": "TOSHI"
}
},
{
"tokenAddress": "0xa11ab779517a0edfabb1b5d9db1cd3167b268858",
"token": {
"isSpam": true, // A spam ERC20 token
"name": "In 𝕏 S",
"symbol": "𝕏S"
}
},
],
// Other Base ERC20 tokens
}
}
}
{% endtab %} {% endtabs %}
Using the GraphQL response, you can filter out and aggregate the ERC20 tokens across Ethereum, Base, Degen Chain, and other Airstack-supported chains by providing the response as to the data
input of the filterSpamERC20Tokens
function:
{% tabs %} {% tab title="TypeScript" %}
interface ERC20 {
tokenAddress: string;
token: {
isSpam: boolean;
name: string;
symbol: string;
};
}
interface ERC20WithBlockchain extends ERC20 {
blockchain: "ethereum" | "polygon" | "base";
}
interface TokenBalancesResponse {
Ethereum: {
TokenBalance?: ERC20[];
};
Polygon: {
TokenBalance?: ERC20[];
};
Base: {
TokenBalance?: ERC20[];
};
}
const filterSpamERC20Tokens = (
data: TokenBalancesResponse
): ERC20WithBlockchain[] | undefined => {
try {
const { Ethereum, Polygon, Base } = data ?? {};
const ethErc20Tokens =
Ethereum?.TokenBalance?.map((erc20Token: ERC20) =>
erc20Token?.token?.isSpam
? null
: {
...erc20Token,
blockchain: "ethereum",
}
) ?? [];
const polygonErc20Tokens =
Polygon?.TokenBalance?.map((erc20Token: ERC20) =>
erc20Token?.token?.isSpam
? null
: {
...erc20Token,
blockchain: "polygon",
}
) ?? [];
const baseErc20Tokens =
Base?.TokenBalance?.map((erc20Token: ERC20) =>
erc20Token?.token?.isSpam
? null
: {
...erc20Token,
blockchain: "base",
}
) ?? [];
return [
...ethErc20Tokens,
...polygonErc20Tokens,
...baseErc20Tokens,
]?.filter(Boolean) as ERC20WithBlockchain[];
} catch (e) {
console.error(e);
}
};
{% endtab %}
{% tab title="JavaScript" %}
const filterSpamERC20Tokens = (data) => {
try {
const { Ethereum, Polygon, Base } = data ?? {};
const ethErc20Tokens =
Ethereum?.TokenBalance?.map((erc20Token) =>
erc20Token?.token?.isSpam
? null
: {
...erc20Token,
blockchain: "ethereum",
}
) ?? [];
const polygonErc20Tokens =
Polygon?.TokenBalance?.map((erc20Token) =>
erc20Token?.token?.isSpam
? null
: {
...erc20Token,
blockchain: "polygon",
}
) ?? [];
const baseErc20Tokens =
Base?.TokenBalance?.map((erc20Token) =>
erc20Token?.token?.isSpam
? null
: {
...erc20Token,
blockchain: "base",
}
) ?? [];
return [
...ethErc20Tokens,
...polygonErc20Tokens,
...baseErc20Tokens,
]?.filter(Boolean);
} catch (e) {
console.error(e);
}
};
{% endtab %}
{% tab title="Python" %}
from typing import List, Dict, Any, Optional
import traceback
def filter_spam_erc20_tokens(data: Optional[Dict[str, Any]]) -> List[Dict[str, Any]]:
try:
ethereum = data.get('Ethereum', {}) if data else {}
polygon = data.get('Polygon', {}) if data else {}
base = data.get('Base', {}) if data else {}
eth_erc20_tokens = [
{**erc20_token, 'blockchain': 'ethereum'} for erc20_token in ethereum.get('TokenBalance', [])
if erc20_token and not erc20_token.get('token', {}).get('isSpam')
]
polygon_erc20_tokens = [
{**erc20_token, 'blockchain': 'polygon'} for erc20_token in polygon.get('TokenBalance', [])
if erc20_token and not erc20_token.get('token', {}).get('isSpam')
]
base_erc20_tokens = [
{**erc20_token, 'blockchain': 'base'} for erc20_token in polygon.get('TokenBalance', [])
if erc20_token and not erc20_token.get('token', {}).get('isSpam')
]
return [erc20_token for erc20_token in eth_erc20_tokens + polygon_erc20_tokens + base_erc20_tokens if erc20_token]
except Exception:
error = traceback.print_exc()
raise Exception(error)
{% endtab %} {% endtabs %}
The formatted data will combine Ethereum, Base, Degen Chain, and other Airstack-supported chains NFTs hold by the user and filtered out all spam NFTs:
[
{
"tokenAddress": "0xbaaa3b3b00def381c0794d0253a4a1ef3b2a9fbc",
"token": {
"isSpam": false,
"name": "Monkeys George",
"symbol": "Monkeys George"
},
"blockchain": "ethereum"
},
// Other Ethereum non-spam ERC20 tokens
{
"tokenAddress": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
"token": { "isSpam": false, "name": "(PoS) Tether USD", "symbol": "USDT" },
"blockchain": "polygon"
},
// Other Polygon non-spam ERC20 tokens
{
"tokenAddress": "0xac1bd2486aaf3b5c0fc3fd868558b082a531b2b4",
"token": { "isSpam": false, "name": "Toshi", "symbol": "TOSHI" },
"blockchain": "base"
}
// Other Base non-spam ERC20 tokens
]
You can use Airstack to check if ERC20 token(s) are spam or not by using Tokens
API and providing the ERC20 token address(es) to address
input:
{% embed url="https://app.airstack.xyz/query/lbqjtIyFrJ" %} Check if Wrapped Ether, USD Coin, and MATIC are spam ERC20 tokens or not {% endembed %}
{% tabs %} {% tab title="Query" %}
query MyQuery {
Tokens(
input: {
filter: {
type: { _eq: ERC20 }
address: {
_in: [
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
"0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0"
]
}
}
blockchain: ethereum
}
) {
Token {
isSpam
address
name
symbol
type
}
}
}
{% endtab %}
{% tab title="Response" %}
{
"data": {
"Tokens": {
"Token": [
{
"isSpam": false, // not Spam ERC20 tokens
"address": "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0",
"name": "Matic Token",
"symbol": "MATIC",
"type": "ERC20"
},
{
"isSpam": false, // not Spam ERC20 tokens
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"name": "USD Coin",
"symbol": "USDC",
"type": "ERC20"
},
{
"isSpam": false, // not Spam ERC20 tokens
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"name": "Wrapped Ether",
"symbol": "WETH",
"type": "ERC20"
}
]
}
}
}
{% endtab %} {% endtabs %}
You can use Airstack to fetch all existing non-spam ERC20 tokens across Ethereum, Base, Degen Chain, and other Airstack-supported chains:
{% embed url="https://app.airstack.xyz/query/ikS5WzdNMc" %} Show all non-spam ERC20s on Ethereum, Polygon, and Base {% endembed %}
{% tabs %} {% tab title="Query" %}
query MyQuery {
Ethereum: Tokens(
input: {
filter: { isSpam: { _eq: false }, type: { _eq: ERC20 } }
blockchain: ethereum
}
) {
Token {
isSpam
address
name
symbol
type
}
pageInfo {
hasNextPage
hasPrevPage
nextCursor
prevCursor
}
}
Polygon: Tokens(
input: {
filter: { isSpam: { _eq: false }, type: { _eq: ERC20 } }
blockchain: polygon
}
) {
Token {
isSpam
address
name
symbol
type
}
pageInfo {
hasNextPage
hasPrevPage
nextCursor
prevCursor
}
}
Base: Tokens(
input: {
filter: { isSpam: { _eq: false }, type: { _eq: ERC20 } }
blockchain: base
}
) {
Token {
isSpam
address
name
symbol
type
}
pageInfo {
hasNextPage
hasPrevPage
nextCursor
prevCursor
}
}
}
{% endtab %}
{% tab title="Response" %}
{
"data": {
"Ethereum": {
"Token": [
{
"isSpam": false,
"address": "0x000000000000073760fc462304360d9e887e4ef4",
"name": "Fides",
"symbol": "FIDES",
"type": "ERC20"
},
{
"isSpam": false,
"address": "0x0000000000000af8fe6e4de40f4804c90fa8ea8f",
"name": "EPS API",
"symbol": "EPSAPI",
"type": "ERC20"
},
{
"isSpam": false,
"address": "0x00000000000045166c45af0fc6e4cf31d9e14b9a",
"name": "TopBidder",
"symbol": "BID",
"type": "ERC20"
}
// Other non-spam Ethereum ERC20 tokens
],
"pageInfo": {
"hasNextPage": true,
"hasPrevPage": false,
"nextCursor": "eyJMYXN0VmFsdWVzTWFwIjp7Il9pZCI6eyJWYWx1ZSI6IjEweDAwMDExOTZmMzM5NjNiMWUzYTkzODM2ODg3YTgwODBkZjM4ODg4ODgiLCJEYXRhVHlwZSI6InN0cmluZyJ9fSwiUGFnaW5hdGlvbkRpcmVjdGlvbiI6Ik5FWFQifQ==",
"prevCursor": ""
}
},
"Polygon": {
"Token": [
{
"isSpam": false,
"address": "0x0000000000000000000000000000000000001010",
"name": "Matic Token",
"symbol": "MATIC",
"type": "ERC20"
},
{
"isSpam": false,
"address": "0x0000000000004946c0e9f43f4dee607b0ef1fa1c",
"name": "Chi Gastoken by 1inch",
"symbol": "CHI",
"type": "ERC20"
},
{
"isSpam": false,
"address": "0x000000000000bd3c2d7cba506f2b058f3589ac60",
"name": "U",
"symbol": "U",
"type": "ERC20"
}
// Other non-spam Polygon ERC20 tokens
],
"pageInfo": {
"hasNextPage": true,
"hasPrevPage": false,
"nextCursor": "eyJMYXN0VmFsdWVzTWFwIjp7Il9pZCI6eyJWYWx1ZSI6IjEzNzB4MDAwMTc0YTQzOWMyYzdkYjZmNWExMzEyNWE3NmE3NjdlMDJkOTgyZiIsIkRhdGFUeXBlIjoic3RyaW5nIn19LCJQYWdpbmF0aW9uRGlyZWN0aW9uIjoiTkVYVCJ9",
"prevCursor": ""
}
},
"Base": {
"Token": [
{
"isSpam": false,
"address": "0x0000c16643e2b6849218cb33224ed3837bd85249",
"name": "ruse",
"symbol": "ruse",
"type": "ERC20"
},
{
"isSpam": false,
"address": "0x0001bd3cecb64f58843a135303d160246d02454e",
"name": "Archly DEX Volatile AMM - ERN/HOP",
"symbol": "vAMM-ERN/HOP",
"type": "ERC20"
},
{
"isSpam": false,
"address": "0x0003787e89033f89d3659b01d9c2f0e48b190e5a",
"name": "155",
"symbol": "15",
"type": "ERC20"
}
// Other non-spam Base ERC20 tokens
],
"pageInfo": {
"hasNextPage": true,
"hasPrevPage": false,
"nextCursor": "eyJMYXN0VmFsdWVzTWFwIjp7Il9pZCI6eyJWYWx1ZSI6IjEzNzB4MDAwMTc0YTQzOWMyYzdkYjZmNWExMzEyNWE3NmE3NjdlMDJkOTgyZiIsIkRhdGFUeXBlIjoic3RyaW5nIn19LCJQYWdpbmF0aW9uRGlyZWN0aW9uIjoiTkVYVCJ9",
"prevCursor": ""
}
}
}
}
{% endtab %} {% endtabs %}
If you have any questions or need help regarding fetching NFT details data, please join our Airstack's Telegram group.