With ERC6551 accounts, users can now own assets that are owned by several layers of NFTs.
With such a feature, traditional token-gating with regular ERC20s, ERC721s, or ERC1155s will not be able to detect assets if they are owned by an ERC6551 token-bound account, even if technically they are owned and controlled by a certain user.
In order to provide proper token-gating for assets owned by ERC6551 token-bound accounts, it requires several steps to ensure that verification is done not just on the EOA level, but also on the proceeding ERC6551 accounts within the NFT ownership tree.
Thus, the algorithm for ERC6551 token-gating will be as follows:
If the amount field exists, then it indicates that the user has ownership of the token or the NFT inside the EOA. Thus, gating access can be provided to the user.
On the other hand, if the amount field does not exist, the EOA does not hold the asset and should proceed to the next step to check the asset in the TBAs.
Step 2: Get All Token Bound ERC6551 Accounts
Given a 0x address, Lens profile, Farcaster, or ENS, you can fetch all the :
def format_function(data):
result = []
if data and 'TokenBalances' in data and 'TokenBalance' in data['TokenBalances'] and data['TokenBalances']['TokenBalance']:
for item in data['TokenBalances']['TokenBalance']:
if 'tokenNfts' in item and 'erc6551Accounts' in item['tokenNfts']:
for account in item['tokenNfts']['erc6551Accounts']:
if 'address' in account and 'addresses' in account['address']:
result.append(account['address']['addresses'])
result = [item for sublist in result for item in sublist]
result = list(set(result))
return result
The formatted data will be a flat array of all the ERC6551 account address:
Step 3: Verify Ownership of Token(s) or NFT(s) on ERC6551 Accounts
Once you have all the ERC6551 accounts on the 1st level of the tree compiled into a single array, you can provide it as an array input into the following query to verify the ownership of token(s) or NFT(s):
Similarly to above, if the amount field does not exist, none of the TBAs in the array hold the asset and should proceed to the next step to check the asset in the TBAs.
Step 4: Iterate On The Next ERC6551 Accounts Level
After going through and checking the 1st layer, you can go through the 2nd, 3rd, ..., nth layer of the ERC6551 tree to verify the ownership of token or NFT on each level.
import asyncio
from airstack.execute_query import AirstackClient
api_client = AirstackClient(api_key='YOUR_AIRSTACK_API_KEY')
verify_ownership = """
query MyQuery(
$owner: [Identity!]
$tokenAddress: Address!
$tokenId: String
) {
TokenBalances(
input: {
blockchain: polygon
filter: {
tokenAddress: { _eq: $tokenAddress }
tokenId: { _eq: $tokenId }
owner: { _in: $owner }
}
}
) {
TokenBalance {
amount
}
}
}
"""
get_all_erc6551 = """
query MyQuery($owner: [Identity!]) {
TokenBalances(
input: {
filter: { owner: { _in: $owner } }
blockchain: polygon
limit: 200
}
) {
TokenBalance {
tokenNfts {
erc6551Accounts {
address {
addresses
}
}
}
}
}
}
"""
def format_function(data):
result = []
if data and 'TokenBalances' in data and 'TokenBalance' in data['TokenBalances'] and data['TokenBalances']['TokenBalance']:
for item in data['TokenBalances']['TokenBalance']:
if 'tokenNfts' in item and 'erc6551Accounts' in item['tokenNfts']:
for account in item['tokenNfts']['erc6551Accounts']:
if 'address' in account and 'addresses' in account['address']:
result.append(account['address']['addresses'])
result = [item for sublist in result for item in sublist]
result = list(set(result))
return result
# print `Access Granted` if the asset is owned within one of the TBA
async def isAccessGrantedERC6551(walletAddress, tokenAddress, tokenId):
addresses = [walletAddress]
while len(addresses) > 0:
execute_query_client = api_client.create_execute_query_object(
query=verify_ownership, variables={"owner": addresses, "tokenAddress": tokenAddress, "tokenId": tokenId})
query_response = await execute_query_client.execute_query()
data = query_response.data
if data and "TokenBalances" in data and "TokenBalance" in data["TokenBalances"] and data["TokenBalances"]["TokenBalance"] and len(data["TokenBalances"]["TokenBalance"]) > 0 and "amount" in data["TokenBalances"]["TokenBalance"][0]:
print("Access Granted")
break
else:
execute_query_client = api_client.create_execute_query_object(
query=get_all_erc6551, variables={"owner": addresses})
query_response = await execute_query_client.execute_query()
addresses = format_function(query_response.data)
asyncio.run(
isAccessGrantedERC6551(
"0x6da658f5840fecc688a4bd007ef6b314d9138135",
"0x99d3fd2f1cF2E99C43F95083B98033d191F4eAbb",
"13"
)
)
Developer Support
If you have any questions or need help regarding building token gating for ERC6551 accounts, please join our Airstack's Telegram group.