Skip to content

Commit 08c86ca

Browse files
committed
mint and burnToRedeem implmented
1 parent 189e624 commit 08c86ca

File tree

4 files changed

+1887
-941
lines changed

4 files changed

+1887
-941
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import {
2+
Form,
3+
FormControl,
4+
FormField,
5+
FormItem,
6+
FormLabel,
7+
} from "@/components/ui/form";
8+
import { Input } from "@/components/ui/input";
9+
import { Skeleton } from "@/components/ui/skeleton";
10+
import { zodResolver } from "@hookform/resolvers/zod";
11+
import { useMutation } from "@tanstack/react-query";
12+
import { useForm } from "react-hook-form";
13+
import { toast } from "sonner";
14+
import {
15+
type ContractOptions,
16+
prepareContractCall,
17+
waitForReceipt,
18+
} from "thirdweb";
19+
import { useActiveAccount, useSendTransaction } from "thirdweb/react";
20+
import { z } from "zod";
21+
import { ModuleCardUI, type ModuleCardUIProps } from "./module-card";
22+
23+
const formSchema = z.object({
24+
tokenId: z.string(),
25+
amount: z.string(),
26+
});
27+
28+
export type BurnToRedeemModuleFormValues = z.infer<typeof formSchema>;
29+
30+
export function BurnToRedeemModule(
31+
props: Omit<ModuleCardUIProps, "children"> & {
32+
contract: ContractOptions;
33+
isOwnerAccount: boolean;
34+
},
35+
) {
36+
const { contract } = props;
37+
const account = useActiveAccount();
38+
const { mutateAsync: sendTransaction } = useSendTransaction();
39+
40+
async function burnToRedeem(values: {
41+
tokenId: string;
42+
amount: string;
43+
}) {
44+
const { tokenId, amount } = values;
45+
46+
const transaction = prepareContractCall({
47+
contract,
48+
method:
49+
"function burnToRedeem(address _from, uint256 _tokenId, uint256 _amount)",
50+
params: [account?.address || "0x0", BigInt(tokenId), BigInt(amount)],
51+
});
52+
53+
const txResult = await sendTransaction(transaction);
54+
55+
try {
56+
await waitForReceipt(txResult);
57+
toast.success("Successfully burned to redeem");
58+
} catch (_) {
59+
toast.error("Failed to burn to redeem");
60+
}
61+
}
62+
63+
return (
64+
<BurnToRedeemModuleUI isPending={false} update={burnToRedeem} {...props} />
65+
);
66+
}
67+
68+
export function BurnToRedeemModuleUI(
69+
props: Omit<ModuleCardUIProps, "children" | "updateButton"> & {
70+
isPending: boolean;
71+
update: (values: {
72+
tokenId: string;
73+
amount: string;
74+
}) => Promise<void>;
75+
},
76+
) {
77+
const form = useForm<BurnToRedeemModuleFormValues>({
78+
resolver: zodResolver(formSchema),
79+
values: {
80+
tokenId: "",
81+
amount: "",
82+
},
83+
reValidateMode: "onChange",
84+
});
85+
86+
const updateMutation = useMutation({
87+
mutationFn: props.update,
88+
});
89+
90+
const onSubmit = async () => {
91+
const _values = form.getValues();
92+
const values = { ..._values };
93+
94+
updateMutation.mutate(values);
95+
};
96+
97+
if (props.isPending) {
98+
return <Skeleton className="h-36" />;
99+
}
100+
101+
return (
102+
<ModuleCardUI
103+
{...props}
104+
updateButton={{
105+
onClick: onSubmit,
106+
isPending: updateMutation.isPending,
107+
isDisabled: !form.formState.isDirty,
108+
}}
109+
>
110+
<Form {...form}>
111+
<form onSubmit={form.handleSubmit(onSubmit)}>
112+
<div className="flex gap-4">
113+
<FormField
114+
control={form.control}
115+
name="tokenId"
116+
render={({ field }) => (
117+
<FormItem className="flex flex-1 flex-col gap-3">
118+
<FormLabel>Token ID</FormLabel>
119+
<FormControl>
120+
<Input
121+
placeholder="0"
122+
{...field}
123+
disabled={!props.isOwnerAccount}
124+
/>
125+
</FormControl>
126+
</FormItem>
127+
)}
128+
/>
129+
130+
<FormField
131+
control={form.control}
132+
name="amount"
133+
render={({ field }) => (
134+
<FormItem className="flex flex-1 flex-col gap-3">
135+
<FormLabel>Amount</FormLabel>
136+
<FormControl>
137+
<Input
138+
placeholder="0x..."
139+
{...field}
140+
disabled={!props.isOwnerAccount}
141+
/>
142+
</FormControl>
143+
</FormItem>
144+
)}
145+
/>
146+
</div>
147+
</form>
148+
</Form>
149+
</ModuleCardUI>
150+
);
151+
}

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Mintable.tsx

Lines changed: 152 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Spinner } from "@/components/ui/Spinner/Spinner";
2+
import { Button } from "@/components/ui/button";
13
import {
24
Form,
35
FormControl,
@@ -11,14 +13,25 @@ import { zodResolver } from "@hookform/resolvers/zod";
1113
import { useMutation } from "@tanstack/react-query";
1214
import { useForm } from "react-hook-form";
1315
import { toast } from "sonner";
14-
import { type ContractOptions, waitForReceipt } from "thirdweb";
16+
import {
17+
type ContractOptions,
18+
prepareContractCall,
19+
waitForReceipt,
20+
} from "thirdweb";
1521
import { MintableERC721 } from "thirdweb/modules";
16-
import { useReadContract, useSendTransaction } from "thirdweb/react";
22+
import {
23+
useActiveAccount,
24+
useReadContract,
25+
useSendTransaction,
26+
} from "thirdweb/react";
1727
import { z } from "zod";
1828
import { ModuleCardUI, type ModuleCardUIProps } from "./module-card";
1929

2030
const formSchema = z.object({
2131
primarySaleRecipient: z.string(),
32+
tokenId: z.string(),
33+
amount: z.string(),
34+
recipient: z.string(),
2235
});
2336

2437
export type MintableModuleFormValues = z.infer<typeof formSchema>;
@@ -30,6 +43,7 @@ export function MintableModule(
3043
},
3144
) {
3245
const { contract } = props;
46+
const account = useActiveAccount();
3347
const { mutateAsync: sendTransaction } = useSendTransaction();
3448
const { data: primarySaleRecipient, isLoading } = useReadContract(
3549
MintableERC721.getSaleConfig,
@@ -56,11 +70,57 @@ export function MintableModule(
5670
}
5771
}
5872

73+
async function mint(values: {
74+
tokenId: string;
75+
amount: string;
76+
recipient: string;
77+
//_uri: string,
78+
//_data: string,
79+
}) {
80+
const { tokenId, amount, recipient } = values;
81+
const grantTransaction = prepareContractCall({
82+
contract,
83+
method: "function grantRoles(address user, uint256 roles)",
84+
params: [account?.address || "0x0", BigInt(1)],
85+
});
86+
87+
const grantTxResult = await sendTransaction(grantTransaction);
88+
console.log("grantTxResult: ", grantTxResult);
89+
90+
try {
91+
await waitForReceipt(grantTxResult);
92+
toast.success("Successfully granted Roles to account");
93+
} catch (_) {
94+
toast.error("Failed to grant Roles to account");
95+
}
96+
try {
97+
const transaction = prepareContractCall({
98+
contract,
99+
method:
100+
"function mint(address to, uint256 tokenId, uint256 amount, string calldata baseURI, bytes memory data)",
101+
params: [recipient, BigInt(tokenId), BigInt(amount), "", "0x"],
102+
});
103+
104+
const txResult = await sendTransaction(transaction);
105+
console.log("mint txResult: ", txResult);
106+
107+
try {
108+
await waitForReceipt(txResult);
109+
toast.success("Successfully minted");
110+
} catch (_) {
111+
toast.error("Failed to mint");
112+
}
113+
} catch (e) {
114+
console.log("mint error: ", e);
115+
}
116+
}
117+
59118
return (
60119
<MintableModuleUI
61120
isPending={isLoading}
62121
primarySaleRecipient={primarySaleRecipient || ""}
63122
update={update}
123+
mint={mint}
64124
{...props}
65125
/>
66126
);
@@ -72,12 +132,20 @@ export function MintableModuleUI(
72132
isPending: boolean;
73133
isOwnerAccount: boolean;
74134
update: (values: MintableModuleFormValues) => Promise<void>;
135+
mint: (values: {
136+
tokenId: string;
137+
amount: string;
138+
recipient: string;
139+
}) => Promise<void>;
75140
},
76141
) {
77142
const form = useForm<MintableModuleFormValues>({
78143
resolver: zodResolver(formSchema),
79144
values: {
80145
primarySaleRecipient: props.primarySaleRecipient,
146+
tokenId: "",
147+
amount: "",
148+
recipient: "",
81149
},
82150
reValidateMode: "onChange",
83151
});
@@ -86,13 +154,24 @@ export function MintableModuleUI(
86154
mutationFn: props.update,
87155
});
88156

157+
const mintMutation = useMutation({
158+
mutationFn: props.mint,
159+
});
160+
89161
const onSubmit = async () => {
90162
const _values = form.getValues();
91163
const values = { ..._values };
92164

93165
updateMutation.mutate(values);
94166
};
95167

168+
const mint = () => {
169+
const _values = form.getValues();
170+
const values = { ..._values };
171+
172+
mintMutation.mutate(values);
173+
};
174+
96175
if (props.isPending) {
97176
return <Skeleton className="h-36" />;
98177
}
@@ -108,8 +187,7 @@ export function MintableModuleUI(
108187
>
109188
<Form {...form}>
110189
<form onSubmit={form.handleSubmit(onSubmit)}>
111-
<div className="flex gap-4">
112-
{/* Switch */}
190+
<div className="flex flex-col gap-4">
113191
<FormField
114192
control={form.control}
115193
name="primarySaleRecipient"
@@ -126,6 +204,76 @@ export function MintableModuleUI(
126204
</FormItem>
127205
)}
128206
/>
207+
208+
<div className="h-5" />
209+
210+
<div className="flex gap-4">
211+
<FormField
212+
control={form.control}
213+
name="tokenId"
214+
render={({ field }) => (
215+
<FormItem className="flex flex-1 flex-col gap-3">
216+
<FormLabel>Token ID</FormLabel>
217+
<FormControl>
218+
<Input
219+
placeholder="0"
220+
{...field}
221+
disabled={!props.isOwnerAccount}
222+
/>
223+
</FormControl>
224+
</FormItem>
225+
)}
226+
/>
227+
228+
<FormField
229+
control={form.control}
230+
name="amount"
231+
render={({ field }) => (
232+
<FormItem className="flex flex-1 flex-col gap-3">
233+
<FormLabel>Amount</FormLabel>
234+
<FormControl>
235+
<Input
236+
placeholder="0"
237+
{...field}
238+
disabled={!props.isOwnerAccount}
239+
/>
240+
</FormControl>
241+
</FormItem>
242+
)}
243+
/>
244+
245+
<FormField
246+
control={form.control}
247+
name="recipient"
248+
render={({ field }) => (
249+
<FormItem className="flex flex-1 flex-col gap-3">
250+
<FormLabel>Recipient</FormLabel>
251+
<FormControl>
252+
<Input
253+
placeholder="0x..."
254+
{...field}
255+
disabled={!props.isOwnerAccount}
256+
/>
257+
</FormControl>
258+
</FormItem>
259+
)}
260+
/>
261+
</div>
262+
</div>
263+
264+
<div className="h-5" />
265+
266+
<div className="flex justify-end">
267+
<Button
268+
size="sm"
269+
className="min-w-24 gap-2"
270+
type="button"
271+
onClick={() => mint()}
272+
disabled={mintMutation.isPending || !props.isOwnerAccount}
273+
>
274+
{mintMutation.isPending && <Spinner className="size-4" />}
275+
Mint
276+
</Button>
129277
</div>
130278
</form>
131279
</Form>

0 commit comments

Comments
 (0)