𧚠Spam ERC20Learn 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 support@airstack.xyz .
Table Of Contents
In this guide you will learn how to use Airstack to:
Pre-requisites
Basic knowledge of GraphQL
Get Started
JavaScript/TypeScript/Python
If you are using JavaScript/TypeScript or Python, Install the Airstack SDK:
npm yarn pnpm pip
React
Copy npm install @airstack/airstack-react
Node
Copy npm install @airstack/node
React
Copy yarn add @airstack/airstack-react
Node
Copy yarn add @airstack/node
React
Copy pnpm install @airstack/airstack-react
Node
Copy pnpm install @airstack/node
Then, add the following snippets to your code:
React Node Python
Copy 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 >;
}
};
Copy 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);
Copy 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 ())
Other Programming Languages
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.
Get Non-Spam ERC20 Token Balances Of User(s)
Fetching
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:
Try Demo
Code
Query Response
Copy 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
}
}
}
}
Copy {
"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
}
}
}
Formatting
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:
TypeScript JavaScript Python
Copy 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);
}
};
Copy 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);
}
};
Copy 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)
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:
Copy [
{
"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
]
Check If ERC20 Token(s) Are Spam Or Not
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:
Try Demo
Code
Query Response
Copy query MyQuery {
Tokens(
input: {
filter : {
type : { _eq : ERC20 }
address : {
_in : [
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
"0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0"
]
}
}
blockchain : ethereum
}
) {
Token {
isSpam
address
name
symbol
type
}
}
}
Copy {
"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"
}
]
}
}
}
Show All Non-Spam ERC20 Tokens
You can use Airstack to fetch all existing non-spam ERC20 tokens across Ethereum, Base, Degen Chain, and other Airstack-supported chains :
Try Demo
Code
Query Response
Copy 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
}
}
}
Copy {
"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" : ""
}
}
}
}
Developer Support
If you have any questions or need help regarding fetching NFT details data, please join our Airstack's Telegram group.
More Resources