diff --git a/README.md b/README.md index 96a73f8..50925f6 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ type configDataType = { contractAddress: string, tokenId?: string, amount?: number, + attributes?: { value: string, trait_type: string } [], }, }[]; ``` @@ -167,13 +168,14 @@ configDataType = { contractAddress: string; // contractAddress of Token or NFT tokenId?: string; // Token Id of the NFT (if req.) amount?: number; // Amount of tokens (if req.) + attributes?: { value: string, trait_type: string } []; // Array of NFT Attributes (if req.) }; }[] ``` ### Methods -There are currently 4 methods available , as follows : +There are currently 5 methods available , as follows : - `NFTWithTokenID` for NFT with a Specific Token ID from a collection, E.g. BAYC No. 8378 @@ -237,6 +239,22 @@ Need to add contractAddress and amount of the token }, ``` +- `NFTWithAttributes` for NFT with an Specific Attribute (trait type and value) from a collection, E.g. BAYC. Fur -> Pink. + +Need to add contractAddress and an array of attributes of the NFT + +```javascript +{ + path: "/page", + methodName: methods.NFTWithTokenID, + network: networks.Ethereum, + data: { + contractAddress: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + attributes: [ { value: "Pink", trait_type: "Fur" } ] + }, + }, +``` + These can be accessed by importing methods ```javascript @@ -245,6 +263,7 @@ export enum methods { "NFTCollection", "TOKEN", "TOKENwithAmount", + "NFTWithAttributes" } ``` @@ -270,7 +289,7 @@ export enum networks { ## Example -Here is an example config File , for all the 4 types of Methods. Refer the same for more info - +Here is an example config File , for all the 5 types of Methods. Refer the same for more info - ```javascript import { configType, methods, networks } from "token-gating-sdk"; @@ -307,6 +326,17 @@ export const configData: configType = [ amount: 100000000, }, }, + { + path: "/privateattributes", + methodName: methods.NFTWithAttributes, + network: networks.Ethereum, + data: { + contractAddress: "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", + attributes: [ + { value: "letter", trait_type: "Character Set" }, + ], + }, + }, ]; ``` diff --git a/example/next-demo-app/config/config.ts b/example/next-demo-app/config/config.ts index 72d2cd2..3f2df6f 100644 --- a/example/next-demo-app/config/config.ts +++ b/example/next-demo-app/config/config.ts @@ -32,4 +32,15 @@ export const configData: configType = [ amount: 100000000, }, }, + { + path: "/privateattributes", + methodName: methods.NFTWithAttributes, + network: networks.Ethereum, + data: { + contractAddress: "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", + attributes: [ + { value: "letter", trait_type: "Character Set" }, + ], + }, + }, ]; diff --git a/example/next-demo-app/pages/privateattributes.js b/example/next-demo-app/pages/privateattributes.js new file mode 100644 index 0000000..c364950 --- /dev/null +++ b/example/next-demo-app/pages/privateattributes.js @@ -0,0 +1,7 @@ +import React from "react"; + +const privateattributes = () => { + return
privateattributes
; +}; + +export default privateattributes; diff --git a/example/react-demo-app/src/config/config.ts b/example/react-demo-app/src/config/config.ts index 72d2cd2..3f2df6f 100644 --- a/example/react-demo-app/src/config/config.ts +++ b/example/react-demo-app/src/config/config.ts @@ -32,4 +32,15 @@ export const configData: configType = [ amount: 100000000, }, }, + { + path: "/privateattributes", + methodName: methods.NFTWithAttributes, + network: networks.Ethereum, + data: { + contractAddress: "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", + attributes: [ + { value: "letter", trait_type: "Character Set" }, + ], + }, + }, ]; diff --git a/example/react-demo-app/src/privateattributes.js b/example/react-demo-app/src/privateattributes.js new file mode 100644 index 0000000..c364950 --- /dev/null +++ b/example/react-demo-app/src/privateattributes.js @@ -0,0 +1,7 @@ +import React from "react"; + +const privateattributes = () => { + return
privateattributes
; +}; + +export default privateattributes; diff --git a/src/components/config/config.tsx b/src/components/config/config.tsx index e49a2f1..fb169b9 100644 --- a/src/components/config/config.tsx +++ b/src/components/config/config.tsx @@ -10,6 +10,7 @@ export enum methods { "NFTCollection", "TOKEN", "TOKENwithAmount", + "NFTWithAttributes" } export type configDataType = { @@ -20,6 +21,7 @@ export type configDataType = { contractAddress: string; tokenId?: string; amount?: number; + attributes?: { value: string, trait_type: string } []; }; }; diff --git a/src/components/nextWrapper/nextWrapper.tsx b/src/components/nextWrapper/nextWrapper.tsx index e2127d5..23ebc12 100644 --- a/src/components/nextWrapper/nextWrapper.tsx +++ b/src/components/nextWrapper/nextWrapper.tsx @@ -214,6 +214,53 @@ export const TokenGatingWrapper: React.FunctionComponent< } }; + // 4. Owns a particular attribute from a particular NFT collection + // The trait should match trait type and value. + const checkNFTAttributes = async ( + userAddress: string, + contractAddress: string, + attributes: { value: string, trait_type: string } [], + network: Network, + alchemyApiKey: string + ) => { + try { + const settings = { + apiKey: alchemyApiKey, // Replace with your Alchemy API Key. + network: network, // Replace with your network. + }; + + const alchemy = new Alchemy(settings); + + console.log("Checking for the attributes"); + + const response = await alchemy.nft.getNftsForOwnerIterator(userAddress); + //console.log(response); + + for await (const nft of response) { + if (nft.contract.address === contractAddress) { + const nftAttributes = nft.rawMetadata?.attributes; + if (nftAttributes) { + for (let x = 0; x < nftAttributes.length; x++) { + for (let y = 0; y < attributes.length; y++) { + if ( + nftAttributes[x].trait_type === attributes[y].trait_type && + nftAttributes[x].value === attributes[y].value + ) { + setAuthorised(true); + return true; + } + } + } + } + } + } + setAuthorised(false); + return false; + } catch (error) { + console.log(error); + } + } + // check the URL and accordingly the condition // Open up a ConnectWallet section in case there is no address // Show a Loading icon when the details are loading @@ -305,6 +352,18 @@ export const TokenGatingWrapper: React.FunctionComponent< finalNetwork, alchemyApiKey ); + } else if (configData.methodName == methods.NFTWithAttributes) { + if (!configData.data.attributes) { + console.log("INCORRECT INPUT DATA"); + return; + } + response = await checkNFTAttributes( + address, + configData.data.contractAddress, + configData.data.attributes, + finalNetwork, + alchemyApiKey + ); } console.log(response); @@ -361,6 +420,11 @@ export const TokenGatingWrapper: React.FunctionComponent< 0, 8 )}`; + } else if (configData.methodName == methods.NFTWithAttributes) { + return `NFT from the Collection ${configData.data.contractAddress.slice( + 0, + 8 + )} with the attributes ${configData.data.attributes.map(attribute => JSON.stringify(attribute)).join(",")}`; } else { return `all the conditions fulfilled`; } diff --git a/src/components/reactWrapper/reactWrapper.tsx b/src/components/reactWrapper/reactWrapper.tsx index 65f6f24..4af9dc3 100644 --- a/src/components/reactWrapper/reactWrapper.tsx +++ b/src/components/reactWrapper/reactWrapper.tsx @@ -215,6 +215,53 @@ export const TokenGatingWrapper: React.FunctionComponent< } }; + // 4. Owns a particular attribute from a particular NFT collection + // The trait should match trait type and value. + const checkNFTAttributes = async ( + userAddress: string, + contractAddress: string, + attributes: { value: string, trait_type: string } [], + network: Network, + alchemyApiKey: string + ) => { + try { + const settings = { + apiKey: alchemyApiKey, // Replace with your Alchemy API Key. + network: network, // Replace with your network. + }; + + const alchemy = new Alchemy(settings); + + console.log("Checking for the attributes"); + + const response = await alchemy.nft.getNftsForOwnerIterator(userAddress); + //console.log(response); + + for await (const nft of response) { + if (nft.contract.address === contractAddress) { + const nftAttributes = nft.rawMetadata?.attributes; + if (nftAttributes) { + for (let x = 0; x < nftAttributes.length; x++) { + for (let y = 0; y < attributes.length; y++) { + if ( + nftAttributes[x].trait_type === attributes[y].trait_type && + nftAttributes[x].value === attributes[y].value + ) { + setAuthorised(true); + return true; + } + } + } + } + } + } + setAuthorised(false); + return false; + } catch (error) { + console.log(error); + } + } + // check the URL and accordingly the condition // Open up a ConnectWallet section in case there is no address // Show a Loading icon when the details are loading @@ -306,6 +353,18 @@ export const TokenGatingWrapper: React.FunctionComponent< finalNetwork, alchemyApiKey ); + } else if (configData.methodName == methods.NFTWithAttributes) { + if (!configData.data.attributes) { + console.log("INCORRECT INPUT DATA"); + return; + } + response = await checkNFTAttributes( + address, + configData.data.contractAddress, + configData.data.attributes, + finalNetwork, + alchemyApiKey + ); } console.log(response); @@ -362,6 +421,11 @@ export const TokenGatingWrapper: React.FunctionComponent< 0, 8 )}`; + } else if (configData.methodName == methods.NFTWithAttributes) { + return `NFT from the Collection ${configData.data.contractAddress.slice( + 0, + 8 + )} with the attributes ${configData.data.attributes.map(attribute => JSON.stringify(attribute)).join(",")}`; } else { return `all the conditions fulfilled`; } diff --git a/src/components/universalWrapper/universalWrapper.tsx b/src/components/universalWrapper/universalWrapper.tsx index fce8d40..546e723 100644 --- a/src/components/universalWrapper/universalWrapper.tsx +++ b/src/components/universalWrapper/universalWrapper.tsx @@ -210,6 +210,53 @@ export const TokenGatingWrapper: React.FunctionComponent< console.log(error); } }; + + // 4. Owns a particular attribute from a particular NFT collection + // The trait should match trait type and value. + const checkNFTAttributes = async ( + userAddress: string, + contractAddress: string, + attributes: { value: string, trait_type: string } [], + network: Network, + alchemyApiKey: string + ) => { + try { + const settings = { + apiKey: alchemyApiKey, // Replace with your Alchemy API Key. + network: network, // Replace with your network. + }; + + const alchemy = new Alchemy(settings); + + console.log("Checking for the attributes"); + + const response = await alchemy.nft.getNftsForOwnerIterator(userAddress); + //console.log(response); + + for await (const nft of response) { + if (nft.contract.address === contractAddress) { + const nftAttributes = nft.rawMetadata?.attributes; + if (nftAttributes) { + for (let x = 0; x < nftAttributes.length; x++) { + for (let y = 0; y < attributes.length; y++) { + if ( + nftAttributes[x].trait_type === attributes[y].trait_type && + nftAttributes[x].value === attributes[y].value + ) { + setAuthorised(true); + return true; + } + } + } + } + } + } + setAuthorised(false); + return false; + } catch (error) { + console.log(error); + } + } // check the URL and accordingly the condition // Open up a ConnectWallet section in case there is no address @@ -302,6 +349,18 @@ export const TokenGatingWrapper: React.FunctionComponent< finalNetwork, alchemyApiKey ); + } else if (configData.methodName == methods.NFTWithAttributes) { + if (!configData.data.attributes) { + console.log("INCORRECT INPUT DATA"); + return; + } + response = await checkNFTAttributes( + address, + configData.data.contractAddress, + configData.data.attributes, + finalNetwork, + alchemyApiKey + ); } console.log(response); @@ -358,6 +417,11 @@ export const TokenGatingWrapper: React.FunctionComponent< 0, 8 )}`; + } else if (configData.methodName == methods.NFTWithAttributes) { + return `NFT from the Collection ${configData.data.contractAddress.slice( + 0, + 8 + )} with the attributes ${configData.data.attributes.map(attribute => JSON.stringify(attribute)).join(",")}`; } else { return `all the conditions fulfilled`; }