diff --git a/pages/_meta.json b/pages/_meta.json index d6587ff..f1e5bf7 100644 --- a/pages/_meta.json +++ b/pages/_meta.json @@ -7,6 +7,7 @@ }, "sdk": "SDK", "contracts": "Contracts", + "advanced": "Advanced", "eip": { "title": "EIP-6551 ↗️", "type": "page", diff --git a/pages/advanced/_meta.json b/pages/advanced/_meta.json new file mode 100644 index 0000000..5e18a13 --- /dev/null +++ b/pages/advanced/_meta.json @@ -0,0 +1,4 @@ +{ + "indexing-erc6551": "Indexing ERC6551", + "token-gating": "Token Gating" +} diff --git a/pages/advanced/indexing-erc6551.mdx b/pages/advanced/indexing-erc6551.mdx new file mode 100644 index 0000000..8e90e1c --- /dev/null +++ b/pages/advanced/indexing-erc6551.mdx @@ -0,0 +1,491 @@ +import { Tab, Tabs } from "nextra-theme-docs"; + +# Indexing ERC6551 + +If you need to index ERC6551 on-chain data, you can use [Airstack](https://docs.airstack.xyz) to do so. + +## Get Started + +Airstack provides a GraphQL API solution to index [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts on both Ethereum and Polygon. + +You can try using Airstack now to index [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts by using the [Airstack API Studio](https://app.airstack.xyz/api-studio). + +For production, the Airstack GraphQL endpoint is available at https://api.airstack.xyz/graphql. + +### Airstack SDK + +Airstack provides three official SDKs to help you index [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts in your application: + +- [Airstack React SDK](https://www.npmjs.com/package/@airstack/airstack-react) +- [Airstack NodeJS SDK](https://www.npmjs.com/package/@airstack/node) +- [Airstack Python SDK](https://pypi.org/project/airstack/) + +#### Install SDK + + + + +```bash +pnpm install @airstack/airstack-react +``` + + + + +```bash +yarn add @airstack/airstack-react +``` + + + + +```bash +npm install @airstack/airstack-react +``` + + + + +```bash +pip3 install airstack asyncio +``` + + + + +#### Call Your First Query + +To get your Airstack API key, go to https://app.airstack.xyz/profile-settings/api-keys + + + + +```jsx +import { init, useQuery } from "@airstack/airstack-react"; + +// Initialize the React SDK +init("YOUR_AIRSTACK_API_KEY"); + +const query = ` +query MyQuery { + Accounts( + input: { + filter: { + tokenAddress: { _eq: "0x26727ed4f5ba61d3772d1575bca011ae3aef5d36" } + tokenId: { _eq: "0" } + } + blockchain: ethereum + limit: 50 + } + ) { + Account { + address { + addresses + } + implementation + registry + salt + standard + updatedAtBlockNumber + updatedAtBlockTimestamp + createdAtBlockNumber + createdAtBlockTimestamp + creationTransactionHash + deployer + } + } +} +`; + +const Component = () => { + const { data, loading, error } = useQuery(query, {}, { cache: false }); + + if (error) console.log(error); + + if (loading) return
Loading...
; + + if (data) { + return ( + //Your React UI Component + ); + } +}; +``` + +
+ + +```python +import asyncio +from airstack.execute_query import AirstackClient + +api_client = AirstackClient(api_key='YOUR_AIRSTACK_API_KEY') + +query = """ +query MyQuery { + Accounts( + input: { + filter: { + tokenAddress: { _eq: "0x26727ed4f5ba61d3772d1575bca011ae3aef5d36" } + tokenId: { _eq: "0" } + } + blockchain: ethereum + limit: 50 + } + ) { + Account { + address { + addresses + } + implementation + registry + salt + standard + updatedAtBlockNumber + updatedAtBlockTimestamp + createdAtBlockNumber + createdAtBlockTimestamp + creationTransactionHash + deployer + } + } +} +""" + +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()) +``` + + +
+ +### Airstack AI + +You can use [Airstack AI Assistant](https://docs.airstack.xyz/airstack-docs-and-faqs/get-started/airstack-ai) to help you construct your query easily using natural languages. + +Go to the [Airstack Explorer](https://app.airstack.xyz/explorer) to try it out. + +Airstack AI UI + +Here are a few example prompts that you can try: + +- [Show the most recent 10 6551 accounts on Ethereum and Polygon](https://app.airstack.xyz/ha8qvF/cyapsZc2O6) +- [Show me all @Sapienz ERC6551 accounts and their balances](https://app.airstack.xyz/ha8qvF/uqLmTIlW7o) +- [Show all ERC65111 accounts owned by @BoredApeYachtClub and the token balances](https://app.airstack.xyz/ha8qvF/CRcpv04wq4) +- [Show sapienz_0.lens ERC6551 accounts](https://app.airstack.xyz/ha8qvF/Kf6QGAUiaF) +- [Show me 6551 accounts created on July 12, 2023, on Ethereum](https://app.airstack.xyz/ha8qvF/qwcEcAqxbT) + +## Examples + +### Get the most recently created ERC-6551 accounts on Ethereum and Polygon + +#### Try Demo + +https://app.airstack.xyz/DTyOZg/eStK6UmL89 + +### Code + + + + +```graphql +query MyQuery { + ethereum: Accounts( + input: { + filter: { standard: { _eq: ERC6551 } } + blockchain: ethereum + order: { createdAtBlockTimestamp: DESC } + limit: 200 + } + ) { + Account { + id + standard + blockchain + tokenAddress + tokenId + address { + identity + } + registry + implementation + salt + createdAtBlockNumber + createdAtBlockTimestamp + creationTransactionHash + deployer + updatedAtBlockNumber + updatedAtBlockTimestamp + } + } + polygon: Accounts( + input: { + filter: { standard: { _eq: ERC6551 } } + blockchain: polygon + order: { createdAtBlockTimestamp: DESC } + limit: 1 + } + ) { + Account { + id + standard + blockchain + tokenAddress + tokenId + address { + identity + } + registry + implementation + salt + createdAtBlockNumber + createdAtBlockTimestamp + creationTransactionHash + deployer + updatedAtBlockNumber + updatedAtBlockTimestamp + } + } +} +``` + + + + +```json +{ + "data": { + "ethereum": { + "Account": [ + { + "id": "a304f27b838f47353a0e7282e935588e02086d88b62bd93f6857c5f38a530dea", + "standard": "ERC6551", + "blockchain": "ethereum", + "tokenAddress": "0xb6a37b5d14d502c3ab0ae6f3a0e058bc9517786e", + "tokenId": "599", + "address": { + "identity": "0x5bb5b498ff300e2ed23804443d340c7418fab4c4" + }, + "registry": "0x02101dfb77fde026414827fdc604ddaf224f0921", + "implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", + "salt": "0", + "createdAtBlockNumber": 17713013, + "createdAtBlockTimestamp": "2023-07-17T12:35:11Z", + "creationTransactionHash": "0x0102df35f0b9e07f2c375ea6ab37838251ce43d0b8da3bfb39d02d70cd5f8cea", + "deployer": "0x186bad94057591918c3265c4ddb12874324be8ac", + "updatedAtBlockNumber": 17713013, + "updatedAtBlockTimestamp": "2023-07-17T12:35:11Z" + } + ] + }, + "polygon": { + "Account": [ + { + "id": "05bb6fa00c99e9aceca905c7b3c0adbbbe4c463d9cd21e46986156b8075e0704", + "standard": "ERC6551", + "blockchain": "polygon", + "tokenAddress": "0xed97678450405fc37fcd08f026c0bbdc3af835f2", + "tokenId": "58", + "address": { + "identity": "0xc44f0f48b14dd230cd694a268a442ffb198b36b1" + }, + "registry": "0x02101dfb77fde026414827fdc604ddaf224f0921", + "implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", + "salt": "0", + "createdAtBlockNumber": 45187150, + "createdAtBlockTimestamp": "2023-07-17T12:35:50Z", + "creationTransactionHash": "0x8cb955fc174f9198a753c64953acbb1692c2739839280599b491c400cf7c2918", + "deployer": "0x58d8c0efc5b006e4686b15bcdd6ae9517ddaa788", + "updatedAtBlockNumber": 45187150, + "updatedAtBlockTimestamp": "2023-07-17T12:35:50Z" + } + ] + } + } +} +``` + + + + +### Get all ERC6551 accounts owned by a given [Sapienz](https://etherscan.io/token/0x26727ed4f5ba61d3772d1575bca011ae3aef5d36) NFT and their token holdings + +#### Try Demo + +https://app.airstack.xyz/DTyOZg/kAehhArEKf + +#### Code + + + + +```graphql +query MyQuery { + Accounts( + input: { + filter: { + tokenAddress: { _eq: "0x26727ed4f5ba61d3772d1575bca011ae3aef5d36" } + tokenId: { _eq: "0" } + } + blockchain: ethereum + limit: 50 + } + ) { + Account { + address { + addresses + } + implementation + registry + salt + standard + updatedAtBlockNumber + updatedAtBlockTimestamp + createdAtBlockNumber + createdAtBlockTimestamp + creationTransactionHash + deployer + } + } +} +``` + + + + +```json +{ + "data": { + "Accounts": { + "Account": [ + { + "address": { + "addresses": [ + "0x5416e5dc14caa0950b2a24ede1eb0e97c360bcf5" + ], + "tokenBalances": [ + { + "amount": "1", + "tokenType": "ERC721", + "tokenAddress": "0x8ee9a60cb5c0e7db414031856cb9e0f1f05988d1", + "tokenId": "9707", + "formattedAmount": 1 + }, + { + "amount": "1", + "tokenType": "ERC1155", + "tokenAddress": "0xafda8953da1099a38a6de2aeeb181cd360beb22e", + "tokenId": "1", + "formattedAmount": 1 + }, + { + "amount": "1", + "tokenType": "ERC1155", + "tokenAddress": "0xafda8953da1099a38a6de2aeeb181cd360beb22e", + "tokenId": "7", + "formattedAmount": 1 + } + ] + }, + "implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", + "registry": "0x02101dfb77fde026414827fdc604ddaf224f0921", + "salt": "0", + "standard": "ERC6551", + "updatedAtBlockNumber": 17213826, + "updatedAtBlockTimestamp": "2023-05-08T05:53:59Z", + "createdAtBlockNumber": 17213826, + "createdAtBlockTimestamp": "2023-05-08T05:53:59Z", + "creationTransactionHash": "0xf998cb400eebe89aa1d369792daf4c202be74dcd88981b34eb49d510b7837332", + "deployer": "0xa75b7833c78eba62f1c5389f811ef3a7364d44de" + } + ] + } + } +} +``` + + + + +### Get NFT that owns TBA account with Lens Profile [sapienz_0.lens](https://lenster.xyz/u/sapienz_0) + +#### Try Demo + +https://app.airstack.xyz/DTyOZg/dcgvPiHtZn + +#### Code + + + + +```graphql +query MyQuery { + Accounts( + input: { + filter: { address: { _eq: "sapienz_0.lens" } } + blockchain: ethereum + limit: 50 + } + ) { + Account { + nft { + address + tokenId + contentValue { + image { + original + } + } + } + } + } +} +``` + + + + +```json +{ + "data": { + "Accounts": { + "Account": [ + { + "nft": { + "address": "0x26727ed4f5ba61d3772d1575bca011ae3aef5d36", + "tokenId": "0", + "contentValue": { + "image": { + "original": "https://assets.airstack.xyz/image/nft/1/0x26727ed4f5ba61d3772d1575bca011ae3aef5d36/0/original_image.gif" + } + } + } + } + ] + } + } +} +``` + + + + +## Developer Support + +If you have any questions or need help regarding your queries on [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts, please join our Airstack's [Telegram](https://t.me/+1k3c2FR7z51mNDRh) group. + +## More resources + +- [ERC6551 Query Templates](https://docs.airstack.xyz/airstack-docs-and-faqs/guides/token-bound-accounts) +- [API Reference](https://docs.airstack.xyz/airstack-docs-and-faqs/api-references/api-reference/accounts-api) diff --git a/pages/advanced/token-gating.mdx b/pages/advanced/token-gating.mdx new file mode 100644 index 0000000..f36df80 --- /dev/null +++ b/pages/advanced/token-gating.mdx @@ -0,0 +1,662 @@ +import { Tab, Tabs } from "nextra-theme-docs"; + +# 🚪 Token Gating + +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: + +1. [Verify ownership of Token(s) or NFT(s) on an EOA](#step-1-verify-ownership-of-tokens-or-nfts-on-an-eoa) +2. [Get all token-bound ERC6551 accounts](#step-2-get-all-token-bound-erc6551-accounts) +3. [Verify ownership of Token(s) or NFT(s) on ERC6551 accounts](#step-3-verify-ownership-of-tokens-or-nfts-on-erc6551-accounts) +4. [Iterate on the next ERC6551 accounts level](#step-4-iterate-on-the-next-erc6551-accounts-level) + +## Get Started + +Airstack provides a GraphQL API solution to index [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts on both Ethereum and Polygon. + +You can try using Airstack now to index [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts by using the [Airstack API Studio](https://app.airstack.xyz/api-studio). + +For production, the Airstack GraphQL endpoint is available at https://api.airstack.xyz/graphql. + +### Airstack SDK + +Airstack provides three official SDKs to help you index [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) accounts in your application: + +- [Airstack React SDK](https://www.npmjs.com/package/@airstack/airstack-react) +- [Airstack NodeJS SDK](https://www.npmjs.com/package/@airstack/node) +- [Airstack Python SDK](https://pypi.org/project/airstack/) + +#### Install SDK + + + + +```bash +pnpm install @airstack/airstack-react +``` + + + + +```bash +yarn add @airstack/airstack-react +``` + + + + +```bash +npm install @airstack/airstack-react +``` + + + + +```bash +pip3 install airstack asyncio +``` + + + + +## Step 1: Verify Ownership of Token(s) or NFT(s) on an EOA + +Given a 0x address, Lens profile, Farcaster, or ENS, simply check if the owner holds the specific NFT that is gated: + +### Try Demo + +https://app.airstack.xyz/DTyOZg/06EErmlEIE + +### Code + + + + +```graphql +query MyQuery { + TokenBalances( + input: { + blockchain: polygon + filter: { + tokenAddress: { _eq: "0x99d3fd2f1cF2E99C43F95083B98033d191F4eAbb" } + tokenId: { _eq: "10" } + owner: { _in: "0x6da658f5840fecc688a4bd007ef6b314d9138135" } + } + } + ) { + TokenBalance { + amount + } + } +} +``` + + + + +```json +{ + "data": { + "TokenBalances": { + "TokenBalance": [ + { + "amount": "1" + } + ] + } + } +} +``` + + + + +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 1st-level token-bound accounts: + +### Try Demo + +https://app.airstack.xyz/DTyOZg/YjTI8VMvY8 + +### Code + + + + +```graphql +query MyQuery { + TokenBalances( + input: { + filter: { owner: { _in: ["0x6da658f5840fecc688a4bd007ef6b314d9138135"] } } + blockchain: polygon + limit: 200 + } + ) { + TokenBalance { + tokenNfts { + erc6551Accounts { + address { + addresses + } + } + } + } + } +} +``` + + + + +```json +{ + "data": { + "TokenBalances": { + "TokenBalance": [ + { + "tokenNfts": { + "erc6551Accounts": [ + { + "address": { + "addresses": ["0x9b220ed6f11f0223d1e01140fbb0e1b22c713a1a"] + } + } + ] + } + }, + { + "tokenNfts": { + "erc6551Accounts": [] // NFT does not own any TBA + } + }, + { + "tokenNfts": { + "erc6551Accounts": [ + { + "address": { + "addresses": ["0x9aacd59af1615b44cf066a9245caea7bdd44c98b"] + } + } + ] + } + }, + { + "tokenNfts": { + "erc6551Accounts": [ + { + "address": { + "addresses": ["0x06265b9caeae3fe4c6b557daaff80a20546d16cf"] + } + } + ] + } + } + ] + } + } +} +``` + + + + +From this example, you can see that there are 3 TBA on the 1st level owned by the given address `0x6da658f5840fecc688a4bd007ef6b314d9138135`. + +By formatting the output with the following format function: + + + + +```javascript +const formatFunction = (data) => + data?.TokenBalances?.TokenBalance?.map(({ tokenNfts }) => + tokenNfts?.erc6551Accounts?.map(({ address }) => + address?.addresses?.map((addr) => addr) + ) + ) + .filter(Boolean) + .flat(2) + .filter((address, index, array) => array.indexOf(address) === index) ?? []; +``` + + + + +```python +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 addresses: + +```json +[ + "0x9b220ed6f11f0223d1e01140fbb0e1b22c713a1a", + "0x9aacd59af1615b44cf066a9245caea7bdd44c98b", + "0x06265b9caeae3fe4c6b557daaff80a20546d16cf" +] +``` + +## 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): + +### Try Demo + +https://app.airstack.xyz/query/s4QaHbs3hZ + +### Code + + + + +```graphql +query MyQuery { + TokenBalances( + input: { + blockchain: polygon + filter: { + tokenAddress: { _eq: "0x99d3fd2f1cF2E99C43F95083B98033d191F4eAbb" } + tokenId: { _eq: "14" } + owner: { + _in: [ + "0xd8dc5794dd43aa9d7495f05bf110614ed32e950f" + "0x333d0ddaf1ecf507f54641055f732914c7f00f18" + "0x8bce0326262c140f82b754ee15dbd7b0a52654a6" + "0x97bd7bb13368348f10c872b5cc7d06e6993aa6eb" + ] + } + } + } + ) { + TokenBalance { + amount + } + } +} +``` + + + + +```json +{ + "data": { + "TokenBalances": { + "TokenBalance": [ + { + "amount": "1" + } + ] + } + } +} +``` + + + + +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. + +The complete code will look like as follows: + + + + +```jsx +import { useState, useEffect } from "react"; +import { init, useLazyQuery } from "@airstack/airstack-react"; + +init("YOUR_AIRSTACK_API_KEY"); + +const 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 + } + } + } +`; + +const GET_ALL_ERC6551 = ` + query MyQuery($owner: [Identity!]) { + TokenBalances( + input: { + filter: { owner: { _in: $owner } } + blockchain: polygon + limit: 200 + } + ) { + TokenBalance { + tokenNfts { + erc6551Accounts { + address { + addresses + } + } + } + } + } + } +`; + +const formatFunction = (data) => + data?.TokenBalances?.TokenBalance?.map(({ tokenNfts }) => + tokenNfts?.erc6551Accounts?.map(({ address }) => + address?.addresses?.map((addr) => addr) + ) + ) + .filter(Boolean) + .flat(2) + .filter((address, index, array) => array.indexOf(address) === index) ?? []; + +const Component = () => { + const [owner, setOwner] = useState(["0x6da658f5840fecc688a4bd007ef6b314d9138135"]); + const [tokenAddress] = useState("0x99d3fd2f1cF2E99C43F95083B98033d191F4eAbb"); + const [tokenId] = useState("13"); + // provide access if `isAccessGrantedERC6551` is true, otherwise don't + const [isAccessGrantedERC6551, setIsAccessGrantedERC6551] = useState(false); + const [verifyOwnership] = useLazyQuery( + VERIFY_OWNERSHIP, + {}, + { + onCompleted: async (data) => { + console.log(data); + if (data?.TokenBalances?.TokenBalance?.[0]?.amount) { + setIsAccessGrantedERC6551(true); + } else { + getAllERC6551({ owner }); + } + }, + } + ); + const [getAllERC6551] = useLazyQuery( + GET_ALL_ERC6551, + {}, + { + dataFormatter: formatFunction, + onCompleted: (data) => { + console.log(data); + if (data?.length > 0) { + verifyOwnership({ + owner: data, + tokenAddress, + tokenId, + }); + } + }, + } + ); + + useEffect(() => { + verifyOwnership({ + owner, + tokenAddress, + tokenId, + }); + }, []); + + return ( + // + ) +} +``` + + + + +```javascript +import { init, fetchQuery } from "@airstack/node"; + +init("YOUR_AIRSTACK_API_KEY"); + +const 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 + } + } + } +`; + +const GET_ALL_ERC6551 = ` + query MyQuery($owner: [Identity!]) { + TokenBalances( + input: { + filter: { owner: { _in: $owner } } + blockchain: polygon + limit: 200 + } + ) { + TokenBalance { + tokenNfts { + erc6551Accounts { + address { + addresses + } + } + } + } + } + } +`; + +const formatFunction = (data) => + data?.TokenBalances?.TokenBalance?.map(({ tokenNfts }) => + tokenNfts?.erc6551Accounts?.map(({ address }) => + address?.addresses?.map((addr) => addr) + ) + ) + .filter(Boolean) + .flat(2) + .filter((address, index, array) => array.indexOf(address) === index) ?? []; + +// Console `Access Granted` if the asset is owned within one of the TBA +const isAccessGrantedERC6551 = async (walletAddress, tokenAddress, tokenId) => { + let addresses = [walletAddress]; + while (addresses?.length > 0) { + const { data } = await fetchQuery( + VERIFY_OWNERSHIP, + { + owner: addresses, + tokenAddress, + tokenId, + }, + { cache: false } + ); + if (data?.TokenBalances?.TokenBalance?.[0]?.amount) { + console.log("Access Granted"); + break; + } else { + const { data: erc6551Data } = await fetchQuery( + GET_ALL_ERC6551, + { + owner: addresses, + }, + { cache: false } + ); + addresses = formatFunction(erc6551Data); + } + } +}; + +isAccessGrantedERC6551( + "0x6da658f5840fecc688a4bd007ef6b314d9138135", + "0x99d3fd2f1cF2E99C43F95083B98033d191F4eAbb", + "14" +); +``` + + + + +```python +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](https://t.me/+1k3c2FR7z51mNDRh) group. + +## More Resources + +- [TokenBalances API](https://docs.airstack.xyz/airstack-docs-and-faqs/api-references/api-reference/tokenbalances-api) +- [Accounts API](https://docs.airstack.xyz/airstack-docs-and-faqs/api-references/api-reference/accounts-api) +- [Other Tokenbound ERC6551 Tutorials](https://docs.airstack.xyz/airstack-docs-and-faqs/guides/token-bound-accounts) + - [NFTs](https://docs.airstack.xyz/airstack-docs-and-faqs/guides/token-bound-accounts/nfts) + - [NFT Owners](https://docs.airstack.xyz/airstack-docs-and-faqs/guides/token-bound-accounts/nft-owners) + - [Sort Results](https://docs.airstack.xyz/airstack-docs-and-faqs/guides/token-bound-accounts/sort-results) diff --git a/pages/sdk/installation.mdx b/pages/sdk/installation.mdx index 390b109..3512cbc 100644 --- a/pages/sdk/installation.mdx +++ b/pages/sdk/installation.mdx @@ -1,9 +1,9 @@ -import { Callout } from "nextra-theme-docs" -import { Tab, Tabs } from "nextra-theme-docs" +import { Callout } from "nextra-theme-docs"; +import { Tab, Tabs } from "nextra-theme-docs"; # Overview -The Tokenbound SDK currently supports projects using Ethers or Viem to interact with Ethereum. The SDK makes it easy to query ERC-6551 account addresses for any NFT and execute transactions against accounts. +The Tokenbound SDK currently supports projects using Ethers or Viem to interact with Ethereum. The SDK makes it easy to query ERC-6551 account addresses for any NFT and execute transactions against accounts. # Installation @@ -12,9 +12,27 @@ The Tokenbound SDK is compatible with both [viem](https://viem.sh/) and [Ethers] Note: If making use of one of the many Web3 starter kits, please make sure that you're using a recent release of viem (>1.0), Ethers 5.7+, or 6 to avoid issues. - ```pnpm install @tokenbound/sdk ``` - ```yarn add @tokenbound/sdk ``` - ```npm install @tokenbound/sdk ``` + + +```bash +pnpm install @tokenbound/sdk +``` + + + + +```bash +yarn add @tokenbound/sdk +``` + + + + +```bash +npm install @tokenbound/sdk +``` + + ## Example apps diff --git a/public/airstack-ai.webp b/public/airstack-ai.webp new file mode 100644 index 0000000..2fbfe2d Binary files /dev/null and b/public/airstack-ai.webp differ