Skip to content

Commit 7c07fda

Browse files
committed
[Dashboard] Fix ERC20 claim conditions
1 parent 322e449 commit 7c07fda

File tree

4 files changed

+70
-20
lines changed

4 files changed

+70
-20
lines changed

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
type BaseTransactionOptions,
33
type ThirdwebClient,
44
toTokens,
5+
toUnits,
56
} from "thirdweb";
67
import type { OverrideEntry } from "thirdweb/dist/types/utils/extensions/drops/types";
78
import type { Prettify } from "thirdweb/dist/types/utils/type-utils";
@@ -42,6 +43,7 @@ type CombinedClaimCondition = Prettify<
4243
type Options =
4344
| {
4445
type: "erc20";
46+
decimals?: number;
4547
}
4648
| {
4749
type: "erc721";
@@ -114,8 +116,14 @@ export function setClaimPhasesTx(
114116
const phases = rawPhases.map((phase) => {
115117
return {
116118
startTime: toDate(phase.startTime),
117-
maxClaimableSupply: toBigInt(phase.maxClaimableSupply),
118-
maxClaimablePerWallet: toBigInt(phase.maxClaimablePerWallet),
119+
maxClaimableSupply: toBigInt(
120+
phase.maxClaimableSupply,
121+
baseOptions.type === "erc20" ? baseOptions.decimals : undefined,
122+
),
123+
maxClaimablePerWallet: toBigInt(
124+
phase.maxClaimablePerWallet,
125+
baseOptions.type === "erc20" ? baseOptions.decimals : undefined,
126+
),
119127
merkleRootHash: phase.merkleRootHash as string | undefined,
120128
overrideList: phase.snapshot?.length
121129
? snapshotToOverrides(phase.snapshot)
@@ -175,13 +183,24 @@ function toDate(timestamp: number | Date | undefined) {
175183
}
176184
return new Date(timestamp);
177185
}
178-
function toBigInt(value: string | number | undefined) {
186+
function toBigInt(
187+
value: string | number | undefined,
188+
decimals?: number,
189+
): bigint | undefined {
179190
if (value === undefined) {
180191
return undefined;
181192
}
182193
if (value === "unlimited") {
183194
return maxUint256;
184195
}
196+
// The ERC20Claim condition extension in v5 does not convert to wei for us
197+
// so we have to, manually
198+
if (decimals) {
199+
return toUnits(value.toString(), decimals);
200+
}
201+
202+
// Will cause issue if trying to convert a non-integer string or number
203+
// thankfully the decimals logic above prevents it
185204
return BigInt(value);
186205
}
187206

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/index.tsx

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ import {
2626
useFieldArray,
2727
useForm,
2828
} from "react-hook-form";
29+
import { toast } from "sonner";
2930
import {
3031
NATIVE_TOKEN_ADDRESS,
3132
type ThirdwebContract,
3233
ZERO_ADDRESS,
34+
toTokens,
3335
} from "thirdweb";
3436
import { decimals } from "thirdweb/extensions/erc20";
3537
import {
@@ -152,7 +154,7 @@ interface ClaimsConditionFormContextData {
152154
field: ControlledField;
153155
phaseIndex: number;
154156
formDisabled: boolean;
155-
tokenDecimals: number;
157+
tokenDecimals: number | undefined;
156158
isMultiPhase: boolean;
157159
isActive: boolean;
158160
dropType: DropType;
@@ -210,7 +212,6 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
210212
enabled: isErc20,
211213
},
212214
});
213-
const tokenDecimalsData = tokenDecimals.data ?? 0;
214215
const saveClaimPhaseNotification = useTxNotifications(
215216
"Saved claim phases",
216217
"Failed to save claim phases",
@@ -219,7 +220,7 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
219220
const claimConditionsQuery = useReadContract(getClaimPhasesInLegacyFormat, {
220221
contract,
221222
...(isErc20
222-
? { type: "erc20" }
223+
? { type: "erc20", decimals: tokenDecimals.data }
223224
: isErc721
224225
? { type: "erc721" }
225226
: { type: "erc1155", tokenId: BigInt(tokenId || 0) }),
@@ -259,7 +260,10 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
259260
);
260261
}, [claimConditionsQuery.data, isMultiPhase]);
261262

262-
const isFetchingData = claimConditionsQuery.isFetching || sendTx.isPending;
263+
const isFetchingData =
264+
claimConditionsQuery.isFetching ||
265+
sendTx.isPending ||
266+
(isErc20 && tokenDecimals.isLoading);
263267

264268
const canEditForm = isAdmin && !isFetchingData;
265269

@@ -353,13 +357,17 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
353357
action: "set-claim-conditions",
354358
label: "attempt",
355359
});
356-
360+
if (isErc20 && !tokenDecimals.data) {
361+
return toast.error(
362+
`Could not fetch token decimals for contract ${contract.address}`,
363+
);
364+
}
357365
try {
358366
const tx = setClaimPhasesTx(
359367
{
360368
contract,
361369
...(isErc20
362-
? { type: "erc20" }
370+
? { type: "erc20", decimals: tokenDecimals.data }
363371
: isErc721
364372
? { type: "erc721" }
365373
: { type: "erc1155", tokenId: BigInt(tokenId || 0) }),
@@ -453,6 +461,14 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
453461
);
454462
}
455463

464+
if (isErc20 && tokenDecimals.data === undefined) {
465+
return (
466+
<div className="flex h-[400px] w-full items-center justify-center rounded-lg border border-border">
467+
Failed to load token decimals
468+
</div>
469+
);
470+
}
471+
456472
return (
457473
<>
458474
<Flex onSubmit={handleFormSubmit} direction="column" as="form" gap={10}>
@@ -488,6 +504,30 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
488504
},
489505
);
490506

507+
// With v5, the value of `maxClaimablePerWallet` & `maxClaimableSupply` for ERC20 claim cont. will already be converted to wei
508+
// so we have to convert them back to token (`toTokens`) to make it human-readable
509+
if (isErc20 && tokenDecimals.data) {
510+
if (
511+
field.maxClaimableSupply !== undefined &&
512+
field.maxClaimableSupply !== "unlimited"
513+
) {
514+
field.maxClaimableSupply = toTokens(
515+
BigInt(field.maxClaimableSupply),
516+
tokenDecimals.data,
517+
);
518+
}
519+
520+
if (
521+
field.maxClaimablePerWallet !== undefined &&
522+
field.maxClaimablePerWallet !== "unlimited"
523+
) {
524+
field.maxClaimablePerWallet = toTokens(
525+
BigInt(field.maxClaimablePerWallet),
526+
tokenDecimals.data,
527+
);
528+
}
529+
}
530+
491531
return (
492532
<Fragment key={`snapshot_${field.id}_${index}`}>
493533
<SnapshotUpload
@@ -508,7 +548,7 @@ export const ClaimConditionsForm: React.FC<ClaimConditionsFormProps> = ({
508548
phaseIndex: index,
509549
formDisabled: !canEditForm,
510550
isErc20,
511-
tokenDecimals: tokenDecimalsData,
551+
tokenDecimals: tokenDecimals.data,
512552
dropType,
513553
setOpenSnapshotIndex,
514554
isAdmin,

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/phase.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export const ClaimConditionsPhase: React.FC<ClaimConditionsPhaseProps> = ({
3535
isMultiPhase,
3636
phaseIndex,
3737
} = useClaimConditionsFormContext();
38-
3938
const toggleEditing = () => {
4039
form.setValue(`phases.${phaseIndex}.isEditing`, !field.isEditing);
4140
};

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/quantity-input-with-unlimited.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
type InputProps,
55
InputRightElement,
66
} from "@chakra-ui/react";
7-
import { useEffect, useState } from "react";
7+
import { useState } from "react";
88
import { Button } from "tw-components";
99

1010
interface QuantityInputWithUnlimitedProps
@@ -30,14 +30,6 @@ export const QuantityInputWithUnlimited: React.FC<
3030
Number.isNaN(Number(value)) ? "0" : value.toString(),
3131
);
3232

33-
// FIXME: this needs a re-work
34-
// eslint-disable-next-line no-restricted-syntax
35-
useEffect(() => {
36-
if (value !== undefined) {
37-
setStringValue(value.toString());
38-
}
39-
}, [value]);
40-
4133
const updateValue = (_value: string) => {
4234
if (_value === "") {
4335
onChange(_value);

0 commit comments

Comments
 (0)