Skip to content

Commit 0f8679a

Browse files
committed
nft extension detection v5 (#4399)
<!-- start pr-codex --> ## PR-Codex overview This PR adds support for checking if specific ERC721 and ERC1155 methods are supported by contracts. It also updates function exports and improves code consistency. ### Detailed summary - Added functions to check method support for ERC721 and ERC1155 contracts - Updated function exports for minting, updating metadata, and token URI - Improved code consistency and clarity in various files > The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/erc721/read/getNFTs.ts`, `packages/thirdweb/src/extensions/erc1155/write/mintAdditionalSupplyTo.ts`, `apps/dashboard/src/contract-ui/tabs/claim-conditions/page.tsx`, `packages/thirdweb/src/exports/extensions/erc721.ts`, `apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/table.tsx`, `packages/thirdweb/src/extensions/erc1155/drops/write/updateMetadata.ts`, `packages/thirdweb/src/extensions/erc721/drops/write/updateMetadata.ts`, `apps/dashboard/src/contract-ui/hooks/useRouteConfig.tsx`, `apps/dashboard/src/core-ui/nft-drawer/useNftDrawerTabs.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/page.tsx` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 54f0294 commit 0f8679a

File tree

26 files changed

+406
-397
lines changed

26 files changed

+406
-397
lines changed

apps/dashboard/src/contract-ui/hooks/useRouteConfig.tsx

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,58 @@ export function useContractRouteConfig(
169169
].every(Boolean);
170170
}, [functionSelectorQuery.data]);
171171

172+
const hasERC721ClaimConditions = useMemo(() => {
173+
return [
174+
// reads
175+
ERC721Ext.isGetClaimConditionByIdSupported(functionSelectorQuery.data),
176+
ERC721Ext.isGetActiveClaimConditionIdSupported(
177+
functionSelectorQuery.data,
178+
),
179+
ERC721Ext.isGetClaimConditionsSupported(functionSelectorQuery.data),
180+
ERC721Ext.isGetActiveClaimConditionSupported(functionSelectorQuery.data),
181+
// writes
182+
ERC721Ext.isSetClaimConditionsSupported(functionSelectorQuery.data),
183+
ERC721Ext.isResetClaimEligibilitySupported(functionSelectorQuery.data),
184+
].every(Boolean);
185+
}, [functionSelectorQuery.data]);
186+
187+
const hasERC20ClaimConditions = useMemo(() => {
188+
return [
189+
// reads
190+
ERC20Ext.isGetClaimConditionByIdSupported(functionSelectorQuery.data),
191+
ERC20Ext.isGetActiveClaimConditionIdSupported(functionSelectorQuery.data),
192+
ERC20Ext.isGetClaimConditionsSupported(functionSelectorQuery.data),
193+
ERC20Ext.isGetActiveClaimConditionSupported(functionSelectorQuery.data),
194+
// writes
195+
ERC20Ext.isSetClaimConditionsSupported(functionSelectorQuery.data),
196+
ERC20Ext.isResetClaimEligibilitySupported(functionSelectorQuery.data),
197+
].every(Boolean);
198+
}, [functionSelectorQuery.data]);
199+
200+
const hasERC1155ClaimConditions = useMemo(() => {
201+
return [
202+
// reads
203+
ERC1155Ext.isGetClaimConditionByIdSupported(functionSelectorQuery.data),
204+
ERC1155Ext.isGetClaimConditionsSupported(functionSelectorQuery.data),
205+
ERC1155Ext.isGetActiveClaimConditionSupported(functionSelectorQuery.data),
206+
// writes
207+
ERC1155Ext.isSetClaimConditionsSupported(functionSelectorQuery.data),
208+
ERC1155Ext.isResetClaimEligibilitySupported(functionSelectorQuery.data),
209+
].every(Boolean);
210+
}, [functionSelectorQuery.data]);
211+
212+
const hasClaimConditions = useMemo(() => {
213+
return [
214+
hasERC721ClaimConditions,
215+
hasERC20ClaimConditions,
216+
hasERC1155ClaimConditions,
217+
].some(Boolean);
218+
}, [
219+
hasERC721ClaimConditions,
220+
hasERC20ClaimConditions,
221+
hasERC1155ClaimConditions,
222+
]);
223+
172224
// old
173225
const ensQuery = useEns(contract.address);
174226

@@ -192,57 +244,11 @@ export function useContractRouteConfig(
192244
});
193245

194246
// claim condition related stuff
195-
const claimconditionExtensionDetection = extensionDetectedState({
196-
contractQuery,
197-
feature: [
198-
// erc 721
199-
"ERC721ClaimPhasesV1",
200-
"ERC721ClaimPhasesV2",
201-
"ERC721ClaimConditionsV1",
202-
"ERC721ClaimConditionsV2",
203-
204-
// erc 20
205-
"ERC20ClaimConditionsV1",
206-
"ERC20ClaimConditionsV2",
207-
"ERC20ClaimPhasesV1",
208-
"ERC20ClaimPhasesV2",
209-
],
210-
});
211-
212-
const hasNewClaimConditions = extensionDetectedState({
213-
contractQuery,
214-
feature: [
215-
// erc721
216-
"ERC721ClaimConditionsV2",
217-
"ERC721ClaimPhasesV2",
218-
// erc1155
219-
"ERC1155ClaimConditionsV2",
220-
"ERC1155ClaimPhasesV2",
221-
// erc20
222-
"ERC20ClaimConditionsV2",
223-
"ERC20ClaimPhasesV2",
224-
],
225-
});
226-
227-
const hasMultiPhaseClaimConditions = extensionDetectedState({
228-
contractQuery,
229-
feature: [
230-
// erc721
231-
"ERC721ClaimPhasesV2",
232-
// erc1155
233-
"ERC1155ClaimPhasesV2",
234-
// erc20
235-
"ERC20ClaimPhasesV2",
236-
],
237-
});
238247

239248
return {
240-
claimconditionExtensionDetection,
241249
detectedEnglishAuctions,
242250
detectedDirectListings,
243251
detectedModularExtension,
244-
hasNewClaimConditions,
245-
hasMultiPhaseClaimConditions,
246252
};
247253
}, [contractQuery]);
248254

@@ -256,7 +262,7 @@ export function useContractRouteConfig(
256262
return "marketplace-v3";
257263
}
258264
// others only matter if claim conditions are detected
259-
if (contractData.hasNewClaimConditions) {
265+
if (hasClaimConditions) {
260266
// if erc721 its that
261267
if (isERC721Query.data) {
262268
return "erc721";
@@ -270,7 +276,12 @@ export function useContractRouteConfig(
270276
}
271277
// otherwise null
272278
return null;
273-
}, [contractData, isERC721Query.data, isERC1155Query.data]);
279+
}, [
280+
contractData,
281+
hasClaimConditions,
282+
isERC721Query.data,
283+
isERC1155Query.data,
284+
]);
274285

275286
return [
276287
{
@@ -419,18 +430,16 @@ export function useContractRouteConfig(
419430
{
420431
title: "Claim Conditions",
421432
path: "claim-conditions",
422-
isEnabled: contractData.claimconditionExtensionDetection,
433+
isEnabled:
434+
hasERC721ClaimConditions || hasERC20ClaimConditions
435+
? "enabled"
436+
: functionSelectorQuery.isLoading
437+
? "loading"
438+
: "disabled",
423439
component: () => (
424440
<LazyContractClaimConditionsPage
425441
contract={contract}
426-
claimconditionExtensionDetection={
427-
contractData.claimconditionExtensionDetection
428-
}
429442
isERC20={isERC20}
430-
hasNewClaimConditions={
431-
contractData.hasNewClaimConditions === "enabled"
432-
}
433-
isMultiPhase={contractData.hasMultiPhaseClaimConditions === "enabled"}
434443
/>
435444
),
436445
},

apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions.tsx

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Flex, Stack } from "@chakra-ui/react";
22
import { useContract } from "@thirdweb-dev/react";
3-
import { UpdateNotice } from "core-ui/update-notice/update-notice";
43
import type { ThirdwebContract } from "thirdweb";
54
import { Heading, Text } from "tw-components";
65
import { ClaimConditionsForm } from "./claim-conditions-form/index";
@@ -9,17 +8,13 @@ interface ClaimConditionsProps {
98
contract: ThirdwebContract;
109
tokenId?: string;
1110
isColumn?: true;
12-
contractInfo: {
13-
hasNewClaimConditions: boolean;
14-
isErc20: boolean;
15-
isMultiPhase: boolean;
16-
};
11+
isERC20: boolean;
1712
}
1813
export const ClaimConditions: React.FC<ClaimConditionsProps> = ({
1914
contract,
2015
tokenId,
2116
isColumn,
22-
contractInfo,
17+
isERC20,
2318
}) => {
2419
const contractQuery = useContract(contract.address);
2520

@@ -37,34 +32,22 @@ export const ClaimConditions: React.FC<ClaimConditionsProps> = ({
3732
<Flex direction="column">
3833
<Heading size="title.md">Set Claim Conditions</Heading>
3934
<Text size="body.md" fontStyle="italic" mt={2}>
40-
Control when the {contractInfo.isErc20 ? "tokens" : "NFTs"} get
41-
dropped, how much they cost, and more.
35+
Control when the {isERC20 ? "tokens" : "NFTs"} get dropped, how
36+
much they cost, and more.
4237
</Text>
4338
</Flex>
44-
{contractInfo.hasNewClaimConditions && (
45-
<UpdateNotice
46-
learnMoreHref="https://blog.thirdweb.com/announcing-improved-claim-conditions"
47-
trackingLabel="claim_conditions"
48-
versions={[
49-
{ version: "3.6.0", sdk: "react" },
50-
{ version: "3.6.0", sdk: "typescript" },
51-
]}
52-
>
53-
Define claim conditions on a per-wallet basis and rename your
54-
claim phases.
55-
</UpdateNotice>
56-
)}
5739
</Flex>
5840

5941
{/* Set Claim Conditions */}
6042
{contractQuery.contract && (
6143
<ClaimConditionsForm
62-
isErc20={contractInfo.isErc20}
44+
isErc20={isERC20}
6345
contract={contractQuery.contract}
6446
tokenId={tokenId}
6547
isColumn={isColumn}
6648
contractV5={contract}
67-
isMultiPhase={contractInfo.isMultiPhase}
49+
// always multi phase!
50+
isMultiPhase={true}
6851
/>
6952
)}
7053
</Flex>
Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,19 @@
1-
import { ButtonGroup, Divider, Flex } from "@chakra-ui/react";
2-
import type { ExtensionDetectedState } from "components/buttons/ExtensionDetectButton";
1+
import { Flex } from "@chakra-ui/react";
32
import type { ThirdwebContract } from "thirdweb";
4-
import { Card, Heading, LinkButton, Text } from "tw-components";
3+
import {} from "tw-components";
54
import { ClaimConditions } from "./components/claim-conditions";
65

76
interface ContractClaimConditionsPageProps {
87
contract: ThirdwebContract;
9-
claimconditionExtensionDetection: ExtensionDetectedState;
108
isERC20: boolean;
11-
hasNewClaimConditions: boolean;
12-
isMultiPhase: boolean;
139
}
1410

1511
export const ContractClaimConditionsPage: React.FC<
1612
ContractClaimConditionsPageProps
17-
> = ({
18-
contract,
19-
claimconditionExtensionDetection,
20-
isERC20,
21-
hasNewClaimConditions,
22-
isMultiPhase,
23-
}) => {
24-
if (!claimconditionExtensionDetection) {
25-
return (
26-
<Card as={Flex} flexDir="column" gap={3}>
27-
{/* TODO extract this out into it's own component and make it better */}
28-
<Heading size="subtitle.md">No Claim Conditions enabled</Heading>
29-
<Text>
30-
To enable Claim Conditions features you will have to extend the
31-
required interfaces in your contract.
32-
</Text>
33-
34-
<Divider my={1} />
35-
<Flex gap={4} align="center">
36-
<Heading size="label.md">Learn more: </Heading>
37-
<ButtonGroup colorScheme="purple" size="sm" variant="solid">
38-
<LinkButton
39-
isExternal
40-
href="https://portal.thirdweb.com/contracts/build/extensions/erc-721/ERC721ClaimConditions"
41-
>
42-
Claim Conditions
43-
</LinkButton>
44-
</ButtonGroup>
45-
</Flex>
46-
</Card>
47-
);
48-
}
49-
13+
> = ({ contract, isERC20 }) => {
5014
return (
5115
<Flex direction="column" gap={6}>
52-
<ClaimConditions
53-
contract={contract}
54-
contractInfo={{ isErc20: isERC20, hasNewClaimConditions, isMultiPhase }}
55-
/>
16+
<ClaimConditions contract={contract} isERC20={isERC20} />
5617
</Flex>
5718
);
5819
};

apps/dashboard/src/contract-ui/tabs/nfts/components/batch-lazy-mint-button.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export const BatchLazyMintButton: React.FC<BatchLazyMintButtonProps> = ({
3030
contractQuery,
3131
contract,
3232
isRevealable,
33-
...restButtonProps
3433
}) => {
3534
const contractV4 = contractQuery.contract;
3635
const trackEvent = useTrack();
@@ -133,7 +132,6 @@ export const BatchLazyMintButton: React.FC<BatchLazyMintButtonProps> = ({
133132
<Button
134133
colorScheme="primary"
135134
leftIcon={<Icon as={RiCheckboxMultipleBlankLine} />}
136-
{...restButtonProps}
137135
onClick={onOpen}
138136
>
139137
Batch Upload

apps/dashboard/src/contract-ui/tabs/nfts/components/claim-button.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import { Icon, useDisclosure } from "@chakra-ui/react";
22
import { GiDiamondHard } from "@react-icons/all-files/gi/GiDiamondHard";
3+
import type { ThirdwebContract } from "thirdweb";
34
import { Button, Drawer } from "tw-components";
45
import { NFTClaimForm } from "./claim-form";
56

67
interface NFTClaimButtonProps {
7-
contractAddress: string;
8-
chainId: number;
8+
contract: ThirdwebContract;
99
}
1010

1111
/**
1212
* This button is used for claiming NFT Drop contract (erc721) only!
1313
* For Edition Drop we have a dedicated ClaimTabERC1155 inside each Edition's page
1414
*/
15-
export const NFTClaimButton: React.FC<NFTClaimButtonProps> = ({
16-
contractAddress,
17-
chainId,
18-
...restButtonProps
19-
}) => {
15+
export const NFTClaimButton: React.FC<NFTClaimButtonProps> = ({ contract }) => {
2016
const { isOpen, onOpen, onClose } = useDisclosure();
2117

2218
return (
@@ -28,12 +24,11 @@ export const NFTClaimButton: React.FC<NFTClaimButtonProps> = ({
2824
onClose={onClose}
2925
isOpen={isOpen}
3026
>
31-
<NFTClaimForm contractAddress={contractAddress} chainId={chainId} />
27+
<NFTClaimForm contract={contract} />
3228
</Drawer>
3329
<Button
3430
colorScheme="primary"
3531
leftIcon={<Icon as={GiDiamondHard} />}
36-
{...restButtonProps}
3732
onClick={onOpen}
3833
>
3934
Claim

apps/dashboard/src/contract-ui/tabs/nfts/components/claim-form.tsx

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { thirdwebClient } from "@/constants/client";
21
import {
32
DrawerBody,
43
DrawerFooter,
@@ -11,10 +10,9 @@ import {
1110
import { TransactionButton } from "components/buttons/TransactionButton";
1211
import { useTrack } from "hooks/analytics/useTrack";
1312
import { useTxNotifications } from "hooks/useTxNotifications";
14-
import { useV5DashboardChain } from "lib/v5-adapter";
1513
import { useForm } from "react-hook-form";
1614
import { toast } from "sonner";
17-
import { ZERO_ADDRESS, getContract } from "thirdweb";
15+
import { type ThirdwebContract, ZERO_ADDRESS } from "thirdweb";
1816
import { getApprovalForTransaction } from "thirdweb/extensions/erc20";
1917
import { claimTo } from "thirdweb/extensions/erc721";
2018
import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react";
@@ -27,20 +25,10 @@ import {
2725

2826
const CLAIM_FORM_ID = "nft-claim-form";
2927
interface NFTClaimFormProps {
30-
contractAddress: string;
31-
chainId: number;
28+
contract: ThirdwebContract;
3229
}
3330

34-
export const NFTClaimForm: React.FC<NFTClaimFormProps> = ({
35-
contractAddress,
36-
chainId,
37-
}) => {
38-
const chain = useV5DashboardChain(chainId);
39-
const contract = getContract({
40-
address: contractAddress,
41-
chain: chain,
42-
client: thirdwebClient,
43-
});
31+
export const NFTClaimForm: React.FC<NFTClaimFormProps> = ({ contract }) => {
4432
const trackEvent = useTrack();
4533
const address = useActiveAccount()?.address;
4634
const { register, handleSubmit, formState } = useForm({

0 commit comments

Comments
 (0)