diff --git a/apps/dashboard/src/components/buttons/TransactionButton.tsx b/apps/dashboard/src/components/buttons/TransactionButton.tsx index 4224f2cb5..50781fb48 100644 --- a/apps/dashboard/src/components/buttons/TransactionButton.tsx +++ b/apps/dashboard/src/components/buttons/TransactionButton.tsx @@ -35,7 +35,6 @@ interface TransactionButtonProps extends Omit { isLoading: boolean; isGasless?: boolean; upsellTestnet?: boolean; - onChainSelect?: (chainId: number) => void; } function useWalletRequiresExternalConfirmation() { @@ -55,7 +54,7 @@ export const TransactionButton: React.FC = ({ colorScheme, variant, isGasless, - onChainSelect, + ...restButtonProps }) => { const activeWallet = useActiveWallet(); @@ -93,7 +92,6 @@ export const TransactionButton: React.FC = ({ > { field, isColumn, claimConditionType, - isClaimPhaseV1, } = useClaimConditionsFormContext(); - if (!isClaimPhaseV1 && claimConditionType === "creator") { + if (claimConditionType === "creator") { return null; } diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/ClaimerSelection.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/ClaimerSelection.tsx index 1ea94e943..32fb84e90 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/ClaimerSelection.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/ClaimerSelection.tsx @@ -18,7 +18,6 @@ export const ClaimerSelection = () => { field, dropType, isErc20, - isClaimPhaseV1, setOpenSnapshotIndex: setOpenIndex, isAdmin, isColumn, @@ -31,14 +30,10 @@ export const ClaimerSelection = () => { if (val === "any") { form.setValue(`phases.${phaseIndex}.snapshot`, undefined); } else { - if (val === "specific" && !isClaimPhaseV1) { + if (val === "specific") { form.setValue(`phases.${phaseIndex}.maxClaimablePerWallet`, 0); } - if ( - val === "overrides" && - !isClaimPhaseV1 && - field.maxClaimablePerWallet !== 1 - ) { + if (val === "overrides" && field.maxClaimablePerWallet !== 1) { form.setValue(`phases.${phaseIndex}.maxClaimablePerWallet`, 1); } form.setValue(`phases.${phaseIndex}.snapshot`, []); @@ -50,39 +45,31 @@ export const ClaimerSelection = () => { const disabledSnapshotButton = isAdmin && formDisabled; - if (isClaimPhaseV1) { - helperText = - "Snapshot spots are one-time-use! Once a wallet has claimed the drop, it cannot claim again, even if it did not claim the entire amount assigned to it in the snapshot."; + if (dropType === "specific") { + helperText = ( + <> + Only wallets on the allowlist can claim. + + ); + } else if (dropType === "any") { + helperText = ( + <> + Anyone can claim based on the rules defined in this phase. + ("Public Mint") + + ); } else { - if (dropType === "specific") { - helperText = ( - <> - Only wallets on the allowlist can claim. - - ); - } else if (dropType === "any") { - helperText = ( - <> - Anyone can claim based on the rules defined in this phase. - ("Public Mint") - - ); - } else { - helperText = ( - <> - Anyone can claim based on the rules defined in this phase. -
- Wallets in the snapshot can claim with special rules defined in - the snapshot. - - ); - } + helperText = ( + <> + Anyone can claim based on the rules defined in this phase. +
+ Wallets in the snapshot can claim with special rules defined in + the snapshot. + + ); } - if ( - !isClaimPhaseV1 && - (claimConditionType === "public" || claimConditionType === "creator") - ) { + if (claimConditionType === "public" || claimConditionType === "creator") { return null; } @@ -113,9 +100,7 @@ export const ClaimerSelection = () => { onChange={handleClaimerChange} > - {!isClaimPhaseV1 ? ( - - ) : null} + )} diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimablePerWalletInput.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimablePerWalletInput.tsx index 7eb66f9b3..2f7397767 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimablePerWalletInput.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimablePerWalletInput.tsx @@ -10,7 +10,6 @@ export const MaxClaimablePerWalletInput: React.FC = () => { const { formDisabled, isErc20, - isClaimPhaseV1, form, tokenDecimals, field, @@ -26,9 +25,7 @@ export const MaxClaimablePerWalletInput: React.FC = () => { return ( { } helperText={ <> - {!isClaimPhaseV1 ? ( - <> - This value applies for all wallets - {claimConditionType !== "public" - ? ", and can be overridden for specific wallets in the snapshot. " - : ". "} - - ) : null} + This value applies for all wallets + {claimConditionType !== "public" + ? ", and can be overridden for specific wallets in the snapshot. " + : ". "} Limits are set per wallets and not per user, sophisticated actors could get around wallet restrictions.{" "} { form.setValue( diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimableSupplyInput.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimableSupplyInput.tsx index 41077587b..c550ede28 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimableSupplyInput.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/MaxClaimableSupplyInput.tsx @@ -14,10 +14,9 @@ export const MaxClaimableSupplyInput: React.FC = () => { tokenDecimals, field, claimConditionType, - isClaimPhaseV1, } = useClaimConditionsFormContext(); - if (!isClaimPhaseV1 && claimConditionType === "creator") { + if (claimConditionType === "creator") { return null; } diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/PhaseNameInput.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/PhaseNameInput.tsx index 89302a317..4b2639390 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/PhaseNameInput.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/Inputs/PhaseNameInput.tsx @@ -6,15 +6,11 @@ import { useClaimConditionsFormContext } from "../index"; * Allows users to edit the name for the claim phase. */ export const PhaseNameInput: React.FC = () => { - const { phaseIndex, formDisabled, isClaimPhaseV1, form, field } = + const { phaseIndex, formDisabled, form, field } = useClaimConditionsFormContext(); const inputPlaceholder = `Phase ${phaseIndex + 1}`; const inputValue = field.metadata?.name; - if (isClaimPhaseV1) { - return null; - } - return ( & { + price: bigint; + currencyMetadata: Omit< + LegacyClaimCondition["currencyMetadata"], + "value" + > & { + value: bigint; + }; + } +>; + +type Options = + | { + type: "erc20"; + } + | { + type: "erc721"; + } + | { + type: "erc1155"; + tokenId: bigint; + }; + +export async function getClaimPhasesInLegacyFormat( + options: BaseTransactionOptions, +): Promise { + const conditions = await (async () => { + switch (options.type) { + case "erc20": + return ERC20Ext.getClaimConditions(options); + case "erc721": + return ERC721Ext.getClaimConditions(options); + case "erc1155": + return ERC1155Ext.getClaimConditions(options); + } + })(); + + return Promise.all( + conditions.map(async (condition) => { + const [currencyMetadata, metadata, contractMetadata] = await Promise.all([ + await ERC20Ext.getCurrencyMetadata({ + contract: { ...options.contract, address: condition.currency }, + }).then((m) => ({ + ...m, + displayValue: toTokens(condition.pricePerToken, m.decimals), + value: condition.pricePerToken, + })), + download({ + uri: condition.metadata, + client: options.contract.client, + }).then((r) => r.json()), + getContractMetadata(options), + ]); + const snapshot = await fetchSnapshot( + condition.merkleRoot, + contractMetadata.merkle, + options.contract.client, + ); + return { + ...condition, + startTime: new Date(Number(condition.startTimestamp * 1000n)), + currencyAddress: condition.currency, + price: condition.pricePerToken, + maxClaimableSupply: toUnlimited(condition.maxClaimableSupply), + currencyMetadata, + currentMintSupply: ( + condition.maxClaimableSupply - condition.supplyClaimed + ).toString(), + maxClaimablePerWallet: toUnlimited(condition.quantityLimitPerWallet), + merkleRootHash: condition.merkleRoot, + metadata, + snapshot, + } satisfies CombinedClaimCondition; + }), + ); +} + +type PhaseInput = z.input; + +export function setClaimPhasesTx( + baseOptions: BaseTransactionOptions, + rawPhases: PhaseInput[], +) { + const phases = rawPhases.map((phase) => { + return { + startTime: toDate(phase.startTime), + maxClaimableSupply: toBigInt(phase.maxClaimableSupply), + maxClaimablePerWallet: toBigInt(phase.maxClaimablePerWallet), + merkleRootHash: phase.merkleRootHash as string | undefined, + overrideList: phase.snapshot?.length + ? snapshotToOverrides(phase.snapshot) + : undefined, + price: phase.price?.toString(), + currencyAddress: phase.currencyAddress, + metadata: phase.metadata, + } satisfies ERC20Ext.SetClaimConditionsParams["phases"][0]; + }); + + switch (baseOptions.type) { + case "erc20": + return ERC20Ext.setClaimConditions({ + contract: baseOptions.contract, + phases, + }); + case "erc721": + return ERC721Ext.setClaimConditions({ + contract: baseOptions.contract, + phases, + }); + case "erc1155": + return ERC1155Ext.setClaimConditions({ + contract: baseOptions.contract, + phases, + tokenId: baseOptions.tokenId, + }); + } +} + +// HELPERS +function snapshotToOverrides(snapshot: PhaseInput["snapshot"]) { + if (!snapshot) { + return []; + } + + return snapshot.map((entry) => { + if (typeof entry === "string") { + return { + address: entry, + } satisfies OverrideEntry; + } + return { + address: entry.address, + maxClaimable: entry.maxClaimable?.toString(), + price: entry.price?.toString(), + currencyAddress: entry.currencyAddress, + } satisfies OverrideEntry; + }); +} +function toDate(timestamp: number | Date | undefined) { + if (timestamp === undefined) { + return undefined; + } + if (timestamp instanceof Date) { + return timestamp; + } + return new Date(timestamp); +} +function toBigInt(value: string | number | undefined) { + if (value === undefined) { + return undefined; + } + if (value === "unlimited") { + return maxUint256; + } + return BigInt(value); +} + +function toUnlimited(value: bigint) { + return value === maxUint256 ? "unlimited" : value.toString(); +} + +async function fetchSnapshot( + merkleRoot: string, + merkleMetadata: Record | undefined, + client: ThirdwebClient, +): Promise { + if (!merkleMetadata) { + return null; + } + + try { + const snapshotUri = merkleMetadata[merkleRoot]; + if (snapshotUri) { + const raw = await download({ + uri: snapshotUri, + client: client, + }).then((r) => r.json()); + if (raw.isShardedMerkleTree && raw.merkleRoot === merkleRoot) { + return download({ + uri: raw.originalEntriesUri, + client: client, + }) + .then((r) => r.json()) + .catch(() => null); + } + if (merkleRoot === raw.merkleRoot) { + return raw.claims.map( + (claim: { + address: string; + maxClaimable: bigint; + price: bigint; + currencyAddress: string; + }) => ({ + address: claim.address, + maxClaimable: claim.maxClaimable, + price: claim.price, + currencyAddress: claim.currencyAddress, + }), + ); + } + } + return null; + } catch (e) { + console.error("failed to fetch snapshot", e); + return null; + } +} diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/index.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/index.tsx index e7faf4d5c..48c18728a 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/index.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/index.tsx @@ -13,11 +13,6 @@ import { MenuList, Spinner, } from "@chakra-ui/react"; -import { - type DropContract, - useClaimConditions, - useSetClaimConditions, -} from "@thirdweb-dev/react"; import { type ClaimConditionInput, ClaimConditionInputSchema, @@ -42,12 +37,17 @@ import { ZERO_ADDRESS, } from "thirdweb"; import { decimals } from "thirdweb/extensions/erc20"; -import { useActiveAccount, useReadContract } from "thirdweb/react"; +import { + useActiveAccount, + useReadContract, + useSendAndConfirmTransaction, +} from "thirdweb/react"; import invariant from "tiny-invariant"; import { Button, Heading, MenuItem, Text } from "tw-components"; import * as z from "zod"; import { ZodError } from "zod"; import { ResetClaimEligibility } from "../reset-claim-eligibility"; +import { getClaimPhasesInLegacyFormat, setClaimPhasesTx } from "./hooks"; import { ClaimConditionsPhase } from "./phase"; type ClaimConditionDashboardInput = ClaimConditionInput & { @@ -59,7 +59,6 @@ const DEFAULT_PHASE: ClaimConditionDashboardInput = { startTime: new Date(), maxClaimableSupply: "unlimited", maxClaimablePerWallet: "unlimited", - waitInSeconds: "0", price: "0", currencyAddress: NATIVE_TOKEN_ADDRESS, snapshot: undefined, @@ -153,7 +152,6 @@ interface ClaimsConditionFormContextData { phaseIndex: number; formDisabled: boolean; tokenDecimals: number; - isClaimPhaseV1: boolean; isMultiPhase: boolean; isActive: boolean; dropType: DropType; @@ -177,14 +175,10 @@ export function useClaimConditionsFormContext() { return data; } -// TODO: refactor, this is no longer supported -const isClaimPhaseV1 = false; - interface ClaimConditionsFormProps { - contract: DropContract; + contract: ThirdwebContract; tokenId?: string; isColumn?: true; - contractV5: ThirdwebContract; isErc20: boolean; isMultiPhase: boolean; } @@ -193,26 +187,39 @@ export const ClaimConditionsForm: React.FC = ({ contract, tokenId, isColumn, - contractV5, isErc20, isMultiPhase, }) => { + // assume 1155 if we have a tokenId + const isErc1155 = tokenId !== undefined; + // if neither 1155 or 20 then it's 721 + const isErc721 = !isErc20 && !isErc1155; const walletAddress = useActiveAccount()?.address; const trackEvent = useTrack(); - const [resetFlag, setResetFlag] = useState(false); - const isAdmin = useIsAdmin(contractV5); - const [openSnapshotIndex, setOpenSnapshotIndex] = useState(-1); - const setClaimConditionsQuery = useSetClaimConditions(contract, tokenId); - const tokenDecimals = useReadContract(decimals, { contract: contractV5 }); + const isAdmin = useIsAdmin(contract); + const [openSnapshotIndex, setOpenSnapshotIndex] = useState(-1); + const sendTx = useSendAndConfirmTransaction(); + + const tokenDecimals = useReadContract(decimals, { + contract, + queryOptions: { + enabled: isErc20, + }, + }); const tokenDecimalsData = tokenDecimals.data ?? 0; const saveClaimPhaseNotification = useTxNotifications( "Saved claim phases", "Failed to save claim phases", ); - const claimConditionsQuery = useClaimConditions(contract, tokenId, { - withAllowList: true, + const claimConditionsQuery = useReadContract(getClaimPhasesInLegacyFormat, { + contract, + ...(isErc20 + ? { type: "erc20" } + : isErc721 + ? { type: "erc721" } + : { type: "erc1155", tokenId: BigInt(tokenId || 0) }), }); const transformedQueryData = useMemo(() => { @@ -227,7 +234,6 @@ export const ClaimConditionsForm: React.FC = ({ }, currencyAddress: phase.currencyAddress?.toLowerCase() || "0", maxClaimablePerWallet: phase.maxClaimablePerWallet?.toString() || "0", - waitInSeconds: phase.waitInSeconds?.toString() || "0", startTime: new Date(phase.startTime), snapshot: phase.snapshot?.map( ({ address, maxClaimable, price, currencyAddress }) => ({ @@ -249,8 +255,7 @@ export const ClaimConditionsForm: React.FC = ({ ); }, [claimConditionsQuery.data, isMultiPhase]); - const isFetchingData = - claimConditionsQuery.isFetching || setClaimConditionsQuery.isLoading; + const isFetchingData = claimConditionsQuery.isFetching || sendTx.isPending; const canEditForm = isAdmin && !isFetchingData; @@ -346,10 +351,18 @@ export const ClaimConditionsForm: React.FC = ({ }); try { - await setClaimConditionsQuery.mutateAsync({ - phases: d.phases as ClaimConditionInput[], - reset: resetFlag, - }); + const tx = setClaimPhasesTx( + { + contract, + ...(isErc20 + ? { type: "erc20" } + : isErc721 + ? { type: "erc721" } + : { type: "erc1155", tokenId: BigInt(tokenId || 0) }), + }, + d.phases, + ); + await sendTx.mutateAsync(tx); trackEvent({ category, action: "set-claim-conditions", @@ -365,6 +378,7 @@ export const ClaimConditionsForm: React.FC = ({ form.setValue("phases", newPhases); } catch (error) { + console.error(error); trackEvent({ category, action: "set-claim-conditions", @@ -448,8 +462,7 @@ export const ClaimConditionsForm: React.FC = ({ )} {controlledFields.map((field, index) => { const dropType: DropType = field.snapshot - ? isClaimPhaseV1 || - field.maxClaimablePerWallet?.toString() === "0" + ? field.maxClaimablePerWallet?.toString() === "0" ? "specific" : "overrides" : "any"; @@ -478,7 +491,6 @@ export const ClaimConditionsForm: React.FC = ({ setOpenSnapshotIndex(-1)} value={snapshotValue} @@ -496,7 +508,6 @@ export const ClaimConditionsForm: React.FC = ({ formDisabled: !canEditForm, isErc20, tokenDecimals: tokenDecimalsData, - isClaimPhaseV1, dropType, setOpenSnapshotIndex, isAdmin, @@ -507,14 +518,11 @@ export const ClaimConditionsForm: React.FC = ({ }} > { removePhase(index); - if (!isMultiPhase) { - setResetFlag(true); - } }} - isLoading={setClaimConditionsQuery.isLoading} + isLoading={sendTx.isPending} /> @@ -545,115 +553,92 @@ export const ClaimConditionsForm: React.FC = ({ gap={2} > - {contractV5 && ( - - {!isClaimPhaseV1 ? ( - <> - - 0 ? "outline" : "solid"} - borderRadius="md" - leftIcon={} - isDisabled={ - setClaimConditionsQuery.isLoading || - (!isMultiPhase && phases?.length > 0) - } - > - Add {isMultiPhase ? "Phase" : "Claim Conditions"} - - - {Object.keys(ClaimConditionTypeData).map((key) => { - const type = key as ClaimConditionType; + + + 0 ? "outline" : "solid"} + borderRadius="md" + leftIcon={} + isDisabled={ + sendTx.isPending || (!isMultiPhase && phases?.length > 0) + } + > + Add {isMultiPhase ? "Phase" : "Claim Conditions"} + + + {Object.keys(ClaimConditionTypeData).map((key) => { + const type = key as ClaimConditionType; - if (type === "custom") { - return null; - } + if (type === "custom") { + return null; + } + + return ( + { + addPhase(type); + // TODO: Automatically start editing the new phase after adding it + }} + > +
+ {ClaimConditionTypeData[type].name} + + {ClaimConditionTypeData[type].description} + + } + /> +
+
+ ); + })} +
+
+
- return ( - { - addPhase(type); - // TODO: Automatically start editing the new phase after adding it - }} - > -
- {ClaimConditionTypeData[type].name} - - { - ClaimConditionTypeData[type] - .description - } - - } - /> -
-
- ); - })} -
-
- - ) : ( - - )} -
- )} {controlledFields.some((field) => field.fromSdk) && ( )}
- {contractV5 && ( - }> - - {(hasRemovedPhases || hasAddedPhases) && ( - - You have unsaved changes - - )} - {controlledFields.length > 0 || - hasRemovedPhases || - !isMultiPhase ? ( - - Save Phases - - ) : null} - - - )} + }> + + {(hasRemovedPhases || hasAddedPhases) && ( + + You have unsaved changes + + )} + {controlledFields.length > 0 || + hasRemovedPhases || + !isMultiPhase ? ( + + Save Phases + + ) : null} + + diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/phase.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/phase.tsx index d1036c1ee..45225b032 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/phase.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/phase.tsx @@ -30,7 +30,6 @@ export const ClaimConditionsPhase: React.FC = ({ form, field, isErc20, - isClaimPhaseV1, isAdmin, claimConditionType, isActive, @@ -82,26 +81,15 @@ export const ClaimConditionsPhase: React.FC = ({ - - {isClaimPhaseV1 - ? isMultiPhase - ? `Claim Phase ${phaseIndex + 1}` - : "Claim Conditions" - : ClaimConditionTypeData[claimConditionType].name} - + {ClaimConditionTypeData[claimConditionType].name} {isActive && ( Currently active )} - {isClaimPhaseV1 ? ( - "" - ) : ( - - {ClaimConditionTypeData[claimConditionType].description} - - )} + + {ClaimConditionTypeData[claimConditionType].description} {!field.isEditing ? ( diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions.tsx index 70d06eb99..a0f86cf7e 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions.tsx @@ -1,5 +1,4 @@ import { Flex, Stack } from "@chakra-ui/react"; -import { useContract } from "@thirdweb-dev/react"; import type { ThirdwebContract } from "thirdweb"; import { Heading, Text } from "tw-components"; import { ClaimConditionsForm } from "./claim-conditions-form/index"; @@ -16,8 +15,6 @@ export const ClaimConditions: React.FC = ({ isColumn, isERC20, }) => { - const contractQuery = useContract(contract.address); - return ( @@ -39,17 +36,14 @@ export const ClaimConditions: React.FC = ({ {/* Set Claim Conditions */} - {contractQuery.contract && ( - - )} + diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/reset-claim-eligibility.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/reset-claim-eligibility.tsx index 7932744d3..a0831abc6 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/reset-claim-eligibility.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/reset-claim-eligibility.tsx @@ -87,9 +87,6 @@ export const ResetClaimEligibility: React.FC = ({ return ( }> = ({ loadingText="Resetting..." size="sm" > - Reset Eligibility{" "} + Reset Eligibility diff --git a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx index 7783f82f8..e72c99552 100644 --- a/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx +++ b/apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx @@ -27,7 +27,7 @@ import { } from "@chakra-ui/react"; import { Logo } from "components/logo"; import Papa from "papaparse"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { type DropzoneOptions, useDropzone } from "react-dropzone"; import { BsFillCloudUploadFill } from "react-icons/bs"; import { FiDownload } from "react-icons/fi"; @@ -64,7 +64,6 @@ interface SnapshotUploadProps { }[] | null; dropType: "specific" | "any" | "overrides"; - isV1ClaimCondition: boolean; isDisabled: boolean; } @@ -74,7 +73,6 @@ export const SnapshotUpload: React.FC = ({ onClose, value, dropType, - isV1ClaimCondition, isDisabled, }) => { const [validSnapshot, setValidSnapshot] = useState( @@ -224,11 +222,7 @@ export const SnapshotUpload: React.FC = ({ {validSnapshot.length > 0 ? ( - + ) : ( @@ -275,33 +269,7 @@ export const SnapshotUpload: React.FC = ({ Requirements - {isV1ClaimCondition ? ( - <> - - Files must contain one .csv file with a list - of addresses. -
- - Example snapshot - -
- - You may optionally add a maxClaimable{" "} - column to specify how many NFTs can be claimed by that - specific address per transaction, if not specified, - the default value is the one you have set on your - claim phase. -
- - Example snapshot - -
- - ) : dropType === "specific" ? ( + {dropType === "specific" ? ( <> Files must contain one .csv file with a list @@ -384,13 +352,10 @@ export const SnapshotUpload: React.FC = ({ Repeated addresses will be removed and only the first found will be kept. - {!isV1ClaimCondition && ( - - The limit you set is for the maximum amount of NFTs a - wallet can claim, not how many they can receive in - total. - - )} + + The limit you set is for the maximum amount of NFTs a + wallet can claim, not how many they can receive in total. +
@@ -459,81 +424,67 @@ export const SnapshotUpload: React.FC = ({ interface SnapshotTableProps { data: SnapshotAddressInput[]; portalRef: React.RefObject; - isV1ClaimCondition: boolean; } -const SnapshotTable: React.FC = ({ - data, - portalRef, - isV1ClaimCondition, -}) => { - const columns = useMemo(() => { - let cols = [ - { - Header: "Address", - accessor: ({ address, isValid }) => { - if (isValid) { - return address; - } - return ( - - - - - - {address} - - - - - ); - }, - }, - { - Header: "Max claimable", - accessor: ({ maxClaimable }) => { - return maxClaimable === "0" || !maxClaimable - ? "Default" - : maxClaimable === "unlimited" - ? "Unlimited" - : maxClaimable; - }, - }, - ] as Column[]; - - if (!isV1ClaimCondition) { - cols = cols.concat([ - { - Header: "Price", - accessor: ({ price }) => { - return price === "0" - ? "Free" - : !price || price === "unlimited" - ? "Default" - : price; - }, - }, - { - Header: "Currency Address", - accessor: ({ currencyAddress }) => { - return currencyAddress === - "0x0000000000000000000000000000000000000000" || !currencyAddress - ? "Default" - : currencyAddress; - }, - }, - ]); - } - - return cols; - }, [isV1ClaimCondition]); +const SnapshotTableColumns = [ + { + Header: "Address", + accessor: ({ address, isValid }) => { + if (isValid) { + return address; + } + return ( + + + + + + {address} + + + + + ); + }, + }, + { + Header: "Max claimable", + accessor: ({ maxClaimable }) => { + return maxClaimable === "0" || !maxClaimable + ? "Default" + : maxClaimable === "unlimited" + ? "Unlimited" + : maxClaimable; + }, + }, + { + Header: "Price", + accessor: ({ price }) => { + return price === "0" + ? "Free" + : !price || price === "unlimited" + ? "Default" + : price; + }, + }, + { + Header: "Currency Address", + accessor: ({ currencyAddress }) => { + return currencyAddress === "0x0000000000000000000000000000000000000000" || + !currencyAddress + ? "Default" + : currencyAddress; + }, + }, +] as Column[]; +const SnapshotTable: React.FC = ({ data, portalRef }) => { const { getTableProps, getTableBodyProps, @@ -555,7 +506,7 @@ const SnapshotTable: React.FC = ({ state: { pageIndex, pageSize }, } = useTable( { - columns, + columns: SnapshotTableColumns, data, initialState: { pageSize: 50, diff --git a/apps/dashboard/src/contract-ui/tabs/nfts/components/reveal-button.tsx b/apps/dashboard/src/contract-ui/tabs/nfts/components/reveal-button.tsx index e3c0cba02..32dbd81c3 100644 --- a/apps/dashboard/src/contract-ui/tabs/nfts/components/reveal-button.tsx +++ b/apps/dashboard/src/contract-ui/tabs/nfts/components/reveal-button.tsx @@ -18,7 +18,6 @@ export const NFTRevealButton: React.FC = ({ const batchesQuery = useReadContract(getBatchesToReveal, { contract, }); - console.log("*** batches", batchesQuery); return batchesQuery.data?.length ? ( , ): Promise { - if ("amount" in options) { - // for native token, we know decimals are 18 - if (!options.erc20Address || isNativeTokenAddress(options.erc20Address)) { - return toUnits(options.amount.toString(), 18); + try { + if ("amount" in options) { + // for native token, we know decimals are 18 + if (!options.erc20Address || isNativeTokenAddress(options.erc20Address)) { + return toUnits(options.amount.toString(), 18); + } + // otherwise get the decimals of the currency + const currencyContract = getContract({ + client: options.client, + chain: options.chain, + address: options.erc20Address, + }); + const { decimals } = await import( + "../../extensions/erc20/read/decimals.js" + ); + const currencyDecimals = await decimals({ + contract: currencyContract, + }); + return toUnits(options.amount.toString(), currencyDecimals); } - // otherwise get the decimals of the currency - const currencyContract = getContract({ - client: options.client, - chain: options.chain, - address: options.erc20Address, - }); - const { decimals } = await import( - "../../extensions/erc20/read/decimals.js" + return options.amountInWei; + } catch (e) { + throw new Error( + `Failed to convert ERC20 amount for token: ${options.erc20Address}: ${e}`, ); - const currencyDecimals = await decimals({ - contract: currencyContract, - }); - return toUnits(options.amount.toString(), currencyDecimals); } - return options.amountInWei; }