Skip to content

Commit e6d335d

Browse files
committed
[SDK + Dashboard] BatchMintAddtionalSupplyTo
1 parent 2206311 commit e6d335d

File tree

4 files changed

+200
-1
lines changed

4 files changed

+200
-1
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
"use client";
2+
3+
import { Flex, useDisclosure } from "@chakra-ui/react";
4+
import { TransactionButton } from "components/buttons/TransactionButton";
5+
import {
6+
type AirdropAddressInput,
7+
AirdropUpload,
8+
} from "contract-ui/tabs/nfts/components/airdrop-upload";
9+
import { useTrack } from "hooks/analytics/useTrack";
10+
import { useTxNotifications } from "hooks/useTxNotifications";
11+
import { UploadIcon } from "lucide-react";
12+
import { useForm } from "react-hook-form";
13+
import type { ThirdwebContract } from "thirdweb";
14+
import { batchMintAdditionalSupplyTo } from "thirdweb/extensions/erc1155";
15+
import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react";
16+
import { Button, Text } from "tw-components";
17+
18+
export default function BatchMintAdditionalSupplyTab({
19+
contract,
20+
tokenId,
21+
}: {
22+
contract: ThirdwebContract;
23+
tokenId: string;
24+
}) {
25+
const address = useActiveAccount()?.address;
26+
const { handleSubmit, setValue, watch, reset, formState } = useForm<{
27+
addresses: AirdropAddressInput[];
28+
}>({
29+
defaultValues: { addresses: [] },
30+
});
31+
const trackEvent = useTrack();
32+
33+
const { isOpen, onOpen, onClose } = useDisclosure();
34+
35+
const { mutate, isPending } = useSendAndConfirmTransaction();
36+
37+
const { onSuccess, onError } = useTxNotifications(
38+
"Batch mint successful",
39+
"Error batch mint",
40+
contract,
41+
);
42+
43+
const addresses = watch("addresses");
44+
45+
return (
46+
<div className="flex w-full flex-col gap-2">
47+
<form
48+
onSubmit={handleSubmit(async (_data) => {
49+
trackEvent({
50+
category: "nft",
51+
action: "airdrop",
52+
label: "attempt",
53+
contract_address: contract.address,
54+
token_id: tokenId,
55+
});
56+
const transaction = batchMintAdditionalSupplyTo({
57+
contract,
58+
tokenId: BigInt(tokenId),
59+
content: _data.addresses.map((item) => ({
60+
to: item.address,
61+
supply: BigInt(item.quantity),
62+
})),
63+
});
64+
mutate(transaction, {
65+
onSuccess: () => {
66+
trackEvent({
67+
category: "nft",
68+
action: "airdrop",
69+
label: "success",
70+
contract_address: contract.address,
71+
token_id: tokenId,
72+
});
73+
onSuccess();
74+
reset();
75+
},
76+
onError: (error) => {
77+
trackEvent({
78+
category: "nft",
79+
action: "airdrop",
80+
label: "success",
81+
contract_address: contract.address,
82+
token_id: tokenId,
83+
error,
84+
});
85+
onError(error);
86+
},
87+
});
88+
})}
89+
>
90+
<div className="flex flex-col gap-2">
91+
<div className="mb-3 flex w-full flex-col gap-6 md:flex-row">
92+
<AirdropUpload
93+
isOpen={isOpen}
94+
onClose={onClose}
95+
setAirdrop={(value) =>
96+
setValue("addresses", value, { shouldDirty: true })
97+
}
98+
/>
99+
<Flex direction={{ base: "column", md: "row" }} gap={4}>
100+
<Button
101+
colorScheme="primary"
102+
borderRadius="md"
103+
onClick={onOpen}
104+
rightIcon={<UploadIcon className="size-5" />}
105+
>
106+
Upload addresses
107+
</Button>
108+
109+
<Flex
110+
gap={2}
111+
direction="row"
112+
align="center"
113+
justify="center"
114+
color={addresses.length === 0 ? "orange.500" : "green.500"}
115+
>
116+
{addresses.length > 0 && (
117+
<Text size="body.sm" color="inherit">
118+
<strong>{addresses.length} addresses</strong> ready to be
119+
minted
120+
</Text>
121+
)}
122+
</Flex>
123+
</Flex>
124+
</div>
125+
<Text>
126+
You can mint to a maximum of 250 addresses at a time. If you have
127+
more, please do it in multiple transactions.
128+
</Text>
129+
<TransactionButton
130+
txChainID={contract.chain.id}
131+
transactionCount={1}
132+
isLoading={isPending}
133+
type="submit"
134+
colorScheme="primary"
135+
disabled={!!address && addresses.length === 0}
136+
alignSelf="flex-end"
137+
isDisabled={!formState.isDirty}
138+
>
139+
Batch mint
140+
</TransactionButton>
141+
</div>
142+
</form>
143+
</div>
144+
);
145+
}

apps/dashboard/src/core-ui/nft-drawer/useNftDrawerTabs.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ const ClaimTabERC1155 = dynamic(
3636
const UpdateMetadataTab = dynamic(
3737
() => import("contract-ui/tabs/nfts/components/update-metadata-tab"),
3838
);
39-
39+
const BatchMintAdditionalSupplyTab = dynamic(
40+
() =>
41+
import("contract-ui/tabs/nfts/components/batch-mint-additional-supply-tab"),
42+
);
4043
export function useNFTDrawerTabs({
4144
contract,
4245
tokenId,
@@ -181,6 +184,17 @@ export function useNFTDrawerTabs({
181184
disabledText: "You don't have minter permissions",
182185
children: <MintSupplyTab contract={contract} tokenId={tokenId} />,
183186
},
187+
{
188+
title: "Batch Mint Supply",
189+
isDisabled: false,
190+
disabledText: "You don't have minter permission",
191+
children: (
192+
<BatchMintAdditionalSupplyTab
193+
contract={contract}
194+
tokenId={tokenId}
195+
/>
196+
),
197+
},
184198
]);
185199
}
186200
if (hasERC1155ClaimConditions) {

packages/thirdweb/src/exports/extensions/erc1155.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ export {
8282
type MintAdditionalSupplyToParams,
8383
isMintAdditionalSupplyToSupported,
8484
} from "../../extensions/erc1155/write/mintAdditionalSupplyTo.js";
85+
export {
86+
batchMintAdditionalSupplyTo,
87+
type BatchMintAdditionalSupplyToParams,
88+
} from "../../extensions/erc1155/write/batchMintAdditionalSupplyTo.js";
8589
export {
8690
setTokenURI,
8791
type SetTokenURIParams,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { multicall } from "../../../extensions/common/__generated__/IMulticall/write/multicall.js";
2+
import type { BaseTransactionOptions } from "../../../transaction/types.js";
3+
import * as URI from "../__generated__/IERC1155/read/uri.js";
4+
import * as MintTo from "../__generated__/IMintableERC1155/write/mintTo.js";
5+
6+
export type BatchMintAdditionalSupplyToParams = {
7+
tokenId: bigint;
8+
content: Array<{
9+
to: string;
10+
supply: bigint;
11+
}>;
12+
};
13+
14+
export function batchMintAdditionalSupplyTo(
15+
options: BaseTransactionOptions<BatchMintAdditionalSupplyToParams>,
16+
) {
17+
return multicall({
18+
contract: options.contract,
19+
asyncParams: async () => {
20+
// we'll be re-using the exising token URI
21+
const tokenUri = await URI.uri({
22+
contract: options.contract,
23+
tokenId: options.tokenId,
24+
});
25+
const data = options.content.map((item) =>
26+
MintTo.encodeMintTo({
27+
to: item.to,
28+
tokenId: options.tokenId,
29+
uri: tokenUri,
30+
amount: item.supply,
31+
}),
32+
);
33+
return { data };
34+
},
35+
});
36+
}

0 commit comments

Comments
 (0)