Skip to content

Commit

Permalink
feat: add erc1155 to token gating group conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
kalashshah committed Jul 31, 2024
1 parent 0bf1b9b commit 8768bb1
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 64 deletions.
2 changes: 1 addition & 1 deletion packages/uiweb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"uuid": "^9.0.1"
},
"peerDependencies": {
"@pushprotocol/restapi": "1.7.19",
"@pushprotocol/restapi": "1.7.25",
"@pushprotocol/socket": "^0.5.0",
"react": ">=16.8.0",
"styled-components": "^6.0.8"
Expand Down
35 changes: 33 additions & 2 deletions packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
checkIfCustomEndpoint,
checkIfGuild,
checkIfPushInvite,
checkIfTokenId,
checkIfTokenNFT,
fetchContractInfo,
getCategoryDropdownValues,
Expand All @@ -56,6 +57,7 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
const [guildComparison, setGuildComparison] = useState('');
const [selectedChainValue, setSelectedChainValue] = useState<number>(0);
const [contract, setContract] = useState<string>('');
const [tokenId, setTokenId] = useState<string>('');
const [inviteCheckboxes, setInviteCheckboxes] = useState<{
admin: boolean;
owner: boolean;
Expand Down Expand Up @@ -154,6 +156,12 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
title: 'Custom Endpoint',
function: () => setSelectedCategoryValue(3),
},
{
id: 4,
value: CATEGORY.ERC1155,
title: 'Token ERC1155',
function: () => setSelectedCategoryValue(4),
},
],
GUILD: {
value: CATEGORY.ROLES,
Expand All @@ -170,6 +178,10 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
value: SUBCATEGORY.HOLDER,
title: 'Holder',
},
ERC1155: {
value: SUBCATEGORY.HOLDER,
title: 'Holder',
},
INVITE: {
value: SUBCATEGORY.DEFAULT,
title: 'Default',
Expand Down Expand Up @@ -256,7 +268,7 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea

let subCategory = 'DEFAULT';
if (_type === 'PUSH') {
if (category === CATEGORY.ERC20 || category === CATEGORY.ERC721) {
if (category === CATEGORY.ERC20 || category === CATEGORY.ERC721 || category === CATEGORY.ERC1155) {
subCategory = SUBCATEGORY.HOLDER;
} else if (category === CATEGORY.CustomEndpoint) {
subCategory = 'GET';
Expand All @@ -283,6 +295,7 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
dropdownQuantityRangeValues,
selectedChainValue,
dropdownChainsValues,
tokenId: Number(tokenId)
}),
};

Expand Down Expand Up @@ -320,7 +333,7 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
const pushData = oldValue.data as PushData;

// sub category
if (oldValue.category === CATEGORY.ERC20 || oldValue.category === CATEGORY.ERC721) {
if (oldValue.category === CATEGORY.ERC20 || oldValue.category === CATEGORY.ERC721 || oldValue.category === CATEGORY.ERC1155) {
if (pushData.token) {
setUnit(pushData.token);
}
Expand All @@ -335,6 +348,7 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
dropdownChainsValues.findIndex((obj) => obj.value === contractAndChain[0] + ':' + contractAndChain[1])
);
setContract(contractAndChain.length === 3 ? contractAndChain[2] : '');
setTokenId(pushData.tokenId?.toString() || '')
setQuantity({
value: pushData.amount || 0,
range: dropdownQuantityRangeValues.findIndex((obj) => obj.value === pushData.comparison),
Expand Down Expand Up @@ -374,6 +388,7 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
setDecimals,
selectedChainValue,
dropdownChainsValues,
tokenId: Number(tokenId)
});
}, 2000);
return () => clearTimeout(getData);
Expand Down Expand Up @@ -536,6 +551,22 @@ const AddCriteria = ({ handlePrevious, onClose, criteriaStateManager }: ModalHea
/>
{!!validationErrors?.tokenError && <ErrorSpan>{validationErrors?.tokenError}</ErrorSpan>}
</Section>
{checkIfTokenId({ dropdownCategoryValues, dropdownTypeValues, selectedCategoryValue, selectedTypeValue }) && (
<Section
gap="10px"
flexDirection="column"
alignItems="start"
>
<TextInput
labelName="Token Id"
inputValue={tokenId}
onInputChange={(e: any) => setTokenId(e.target.value)}
placeholder="e.g. 2"
error={!!validationErrors?.tokenId}
/>
{!!validationErrors?.tokenId && <ErrorSpan>{validationErrors?.tokenId}</ErrorSpan>}
</Section>
)}
<Section
gap="10px"
flexDirection="column"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,17 @@ const CriteriaSection = ({ criteria }: { criteria: ConditionData }) => {
const checkIfNftToken = () => {
if (
criteria?.category === CATEGORY.ERC721 ||
criteria?.category === CATEGORY.ERC20
criteria?.category === CATEGORY.ERC20 ||
criteria?.category === CATEGORY.ERC1155
)
return true;
return false;
};

const checkIfIDToken = () => {
return criteria?.category === CATEGORY.ERC1155;
}

const getGuildRole = () => {
if (!criteria?.data?.['comparison']) {
return 'SPECIFIC';
Expand Down Expand Up @@ -123,12 +128,26 @@ const CriteriaSection = ({ criteria }: { criteria: ConditionData }) => {
justifyContent="space-between"
alignItems="center"
>
<Span fontWeight="700" color={theme.textColor?.modalHeadingText}>
<Span fontWeight="500" color={theme.textColor?.modalSubHeadingText}>
{getTokenNftComparisionLabel()}{' '}
{checkIfIDToken() ?
<Section>
<Span fontWeight="500" color={theme.textColor?.modalSubHeadingText}>
{getTokenNftComparisionLabel()}{' '}
</Span>
<Section flexDirection='column' alignItems='start' margin="0px 0px 0px 8px">
<Span color={theme.textColor?.modalSubHeadingText} fontSize='10px'>
{criteria?.data?.['amount']} {tokenSymbol}
</Span>
<Span color={theme.textColor?.modalHeadingText} textAlign='flex-start'>ID: {criteria?.data?.['tokenId']}</Span>
</Section>
</Section>
:
<Span fontWeight="700" color={theme.textColor?.modalHeadingText}>
<Span fontWeight="500" color={theme.textColor?.modalSubHeadingText}>
{getTokenNftComparisionLabel()}{' '}
</Span>
{criteria?.data?.['amount']} {tokenSymbol}
</Span>
{criteria?.data?.['amount']} {tokenSymbol}
</Span>
}
<ChainIconSVG padding="3px 6px 0 0" >
{
NETWORK_ICON_DETAILS[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ export const getCategoryDropdownValues = ({
dropdownTypeValues,
selectedTypeValue,
}: InputFunctionParams) => {
return dropdownCategoryValues![
dropdownTypeValues![selectedTypeValue!]?.value as TypeKeys
];
return dropdownCategoryValues![dropdownTypeValues![selectedTypeValue!]?.value as TypeKeys];
};

export const getSelectedCategoryValue = ({
Expand All @@ -39,8 +37,7 @@ export const getSelectedCategoryValue = ({
dropdownTypeValues,
selectedTypeValue,
});
if (Array.isArray(category))
return (category as DropdownValueType[])[selectedCategoryValue!].value!;
if (Array.isArray(category)) return (category as DropdownValueType[])[selectedCategoryValue!].value!;
else return category.value! as SubCategoryKeys;
};

Expand All @@ -60,8 +57,7 @@ export const getSelectedSubCategoryValue = ({
dropdownSubCategoryValues,
selectedTypeValue,
});
if (Array.isArray(subCategory))
return (subCategory as DropdownValueType[])[selectedCategoryValue!].value!;
if (Array.isArray(subCategory)) return (subCategory as DropdownValueType[])[selectedCategoryValue!].value!;
else return subCategory.value! as SubCategoryKeys;
};

Expand All @@ -77,7 +73,24 @@ export const checkIfTokenNFT = ({
selectedTypeValue,
selectedCategoryValue,
});
if (category === CATEGORY.ERC20 || category === CATEGORY.ERC721) return true;
if (category === CATEGORY.ERC20 || category === CATEGORY.ERC721 || category === CATEGORY.ERC1155) return true;

return false;
};

export const checkIfTokenId = ({
dropdownCategoryValues,
dropdownTypeValues,
selectedCategoryValue,
selectedTypeValue,
}: InputFunctionParams) => {
const category = getSelectedCategoryValue({
dropdownCategoryValues,
dropdownTypeValues,
selectedTypeValue,
selectedCategoryValue,
});
if (category === CATEGORY.ERC1155) return true;

return false;
};
Expand Down Expand Up @@ -118,10 +131,7 @@ export const checkIfPushInvite = ({
return false;
};

export const checkIfGuild = (
dropdownTypeValues: Array<DropdownValueType>,
selectedTypeValue: number
) => {
export const checkIfGuild = (dropdownTypeValues: Array<DropdownValueType>, selectedTypeValue: number) => {
const accessType = dropdownTypeValues[selectedTypeValue].value;
if (accessType === TYPE.GUILD) {
return true;
Expand All @@ -147,35 +157,23 @@ export const getSubCategoryDropdownValues = ({
});
if (Array.isArray(category))
return dropdownSubCategoryValues[
(category as DropdownValueType[])[selectedCategoryValue!]
.value as SubCategoryKeys
(category as DropdownValueType[])[selectedCategoryValue!].value as SubCategoryKeys
];
else return dropdownSubCategoryValues[category.value as SubCategoryKeys];
};

export const getSeletedType = ({
dropdownTypeValues,
selectedTypeValue,
}: InputFunctionParams) => {
export const getSeletedType = ({ dropdownTypeValues, selectedTypeValue }: InputFunctionParams) => {
return dropdownTypeValues![selectedTypeValue!].value || 'PUSH';
};

export const getSelectedCategory = ({
dropdownCategoryValues,
selectedCategoryValue,
}: InputFunctionParams) => {
export const getSelectedCategory = ({ dropdownCategoryValues, selectedCategoryValue }: InputFunctionParams) => {
const category: string =
(dropdownCategoryValues!['PUSH'] as DropdownValueType[])[
selectedCategoryValue!
].value || CATEGORY.ERC20;
(dropdownCategoryValues!['PUSH'] as DropdownValueType[])[selectedCategoryValue!].value || CATEGORY.ERC20;

return category;
};

export const getSelectedChain = (
dropdownChainsValues: Array<DropdownValueType>,
selectedChainValue: number
) => {
export const getSelectedChain = (dropdownChainsValues: Array<DropdownValueType>, selectedChainValue: number) => {
return dropdownChainsValues[selectedChainValue].value || 'eip155:1';
};

Expand All @@ -184,6 +182,7 @@ type FetchContractInfoParamType = {
setUnit: Dispatch<SetStateAction<string>>;
setDecimals: Dispatch<SetStateAction<number>>;
contract: string;
tokenId: number;
dropdownChainsValues: Array<DropdownValueType>;
selectedChainValue: number;
} & InputFunctionParams;
Expand All @@ -199,6 +198,7 @@ export const fetchContractInfo = async ({
setDecimals,
selectedChainValue,
dropdownChainsValues,
tokenId
}: FetchContractInfoParamType) => {
setValidationErrors((prev: any) => ({ ...prev, tokenError: undefined }));

Expand All @@ -209,14 +209,7 @@ export const fetchContractInfo = async ({
});
const _chainInfo = getSelectedChain(dropdownChainsValues, selectedChainValue);

await tokenFetchHandler(
contract,
_type,
_category,
_chainInfo,
setUnit,
setDecimals
);
await tokenFetchHandler(contract, _type, _category, _chainInfo, setUnit, setDecimals, tokenId);
};

type GetCriteriaDataParamType = {
Expand All @@ -228,6 +221,7 @@ type GetCriteriaDataParamType = {
selectedChainValue: number;
decimals: number;
unit: string;
tokenId: number;
url: string;
guildId: string;
specificRoleId: string;
Expand All @@ -240,7 +234,7 @@ type GetCriteriaDataParamType = {
value: number;
range: number;
};
} ;
};

export const getCriteriaData = ({
type,
Expand All @@ -257,17 +251,18 @@ export const getCriteriaData = ({
dropdownQuantityRangeValues,
selectedChainValue,
dropdownChainsValues,
tokenId,
}: GetCriteriaDataParamType): Data => {
if (type === 'PUSH') {
if (category === CATEGORY.ERC20 || category === CATEGORY.ERC721) {
const selectedChain =
dropdownChainsValues[selectedChainValue].value || 'eip155:1';
if (category === CATEGORY.ERC20 || category === CATEGORY.ERC721 || category === CATEGORY.ERC1155) {
const selectedChain = dropdownChainsValues[selectedChainValue].value || 'eip155:1';
return {
contract: `${selectedChain}:${contract}`,
amount: quantity.value,
comparison: dropdownQuantityRangeValues[quantity.range].value,
decimals: category === CATEGORY.ERC20 ? decimals : undefined,
decimals: (category === CATEGORY.ERC20 || category === CATEGORY.ERC1155) ? decimals : undefined,
token: unit,
tokenId
};
} else if (category === CATEGORY.INVITE) {
const _inviteRoles = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ConditionArray } from '../exportedTypes';
import * as PushAPI from '@pushprotocol/restapi';
import { fetchERC20Info, fetchERC721nfo } from './tokenHelpers';

export interface GroupRulesType {
CHAT: ConditionArray[];
Expand Down
24 changes: 19 additions & 5 deletions packages/uiweb/src/lib/components/chat/helpers/tokenGatedGroup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';
import { ethers } from 'ethers';

import { fetchERC20Info, fetchERC721nfo } from './tokenHelpers';
import { fetchERC1155Info, fetchERC20Info, fetchERC721nfo } from './tokenHelpers';
import {
CATEGORY,
CriteriaStateType,
Expand Down Expand Up @@ -124,10 +124,15 @@ const validateTokenData = async (condition: Rule): Promise<CriteriaValidationErr
if (!ethers.utils.isAddress(address)) {
return { tokenError: `Invalid contract address` };
}
const [err] =
condition.category === CATEGORY.ERC721
? await fetchERC721nfo(address, chainId)
: await fetchERC20Info(address, chainId);

let err;
if (condition.category === CATEGORY.ERC1155) {
err = (await fetchERC1155Info(address, chainId, data.tokenId ?? 0))?.[0];
} else if (condition.category === CATEGORY.ERC721) {
err = (await fetchERC721nfo(address, chainId))?.[0];
} else {
err = (await fetchERC20Info(address, chainId))?.[0];
}

if (err) {
return { tokenError: `Invalid ${condition.category} contract` };
Expand All @@ -139,6 +144,15 @@ const validateTokenData = async (condition: Rule): Promise<CriteriaValidationErr
return { tokenAmount: `Amount cannot be in negative` };
}
}

if(condition.category === CATEGORY.ERC1155) {
if(data.tokenId === undefined || Number.isNaN(data.tokenId)) {
return { tokenId: 'Invalid Token ID' };
} else if(data.tokenId < 0) {
return { tokenId: 'Token ID cannot be in negative' };
}
}

return {};
};

Expand Down
Loading

0 comments on commit 8768bb1

Please sign in to comment.