Skip to content

Commit aa1035d

Browse files
committed
[TOOL-4988] Dashboard, SDK: Add gas sponsorship option for asset creation for in-app wallets (#7566)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the handling of gasless transactions across various components in the `thirdweb` dashboard, specifically for NFT and token creation processes. It introduces new parameters and logic to support gas sponsorship features. ### Detailed summary - Added `useAuthToken` option in `bundler.ts` fetch requests. - Enhanced `fetch.ts` to include authentication headers for bundler requests. - Updated `CreateTokenFunctions` and `CreateNFTCollectionFunctions` to accept `gasless` parameter. - Modified multiple functions in the NFT and token creation pages to support gasless transactions. - Implemented UI elements for enabling gas sponsorship in the `LaunchNFT` and `LaunchTokenStatus` components. - Adjusted error handling for unsupported gas sponsorship on certain chains. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit Here are the updated release notes based on the provided summary: * **New Features** * Added support for gasless transactions when launching NFT collections and tokens, available for eligible team plans and in-app wallets. * Introduced a toggle in the launch UI to enable or disable gasless mode for NFT and token creation. * Updated UI labels and dialogs for launching NFT collections. * **Refactor** * Standardized function signatures for NFT and token creation to accept a unified parameter object, including a new gasless flag. * Centralized account and contract retrieval logic for improved maintainability and consistency. * Improved error logging in the token creation workflow. * **Bug Fixes** * Enhanced error handling during token launch to detect unsupported gas sponsorship and provide user-friendly retry options. * **Chores** * Updated request headers logic to properly handle authorization tokens and additional headers for bundler URLs. * Enabled authentication token usage in bundler request configurations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent bd395a3 commit aa1035d

File tree

9 files changed

+353
-157
lines changed

9 files changed

+353
-157
lines changed

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/nft/_common/form.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,29 @@ export type CreateNFTCollectionFunctions = {
4242
address: string;
4343
}[];
4444
chain: string;
45+
gasless: boolean;
4546
}) => Promise<void>;
4647
erc721: {
47-
deployContract: (values: CreateNFTCollectionAllValues) => Promise<{
48+
deployContract: (params: {
49+
values: CreateNFTCollectionAllValues;
50+
gasless: boolean;
51+
}) => Promise<{
4852
contractAddress: string;
4953
}>;
50-
setClaimConditions: (values: CreateNFTCollectionAllValues) => Promise<void>;
51-
lazyMintNFTs: (values: CreateNFTCollectionAllValues) => Promise<void>;
54+
setClaimConditions: (params: {
55+
values: CreateNFTCollectionAllValues;
56+
gasless: boolean;
57+
}) => Promise<void>;
58+
lazyMintNFTs: (params: {
59+
values: CreateNFTCollectionAllValues;
60+
gasless: boolean;
61+
}) => Promise<void>;
5262
};
5363
erc1155: {
54-
deployContract: (values: CreateNFTCollectionAllValues) => Promise<{
64+
deployContract: (params: {
65+
values: CreateNFTCollectionAllValues;
66+
gasless: boolean;
67+
}) => Promise<{
5568
contractAddress: string;
5669
}>;
5770
setClaimConditions: (params: {
@@ -60,8 +73,12 @@ export type CreateNFTCollectionFunctions = {
6073
startIndex: number;
6174
count: number;
6275
};
76+
gasless: boolean;
77+
}) => Promise<void>;
78+
lazyMintNFTs: (params: {
79+
values: CreateNFTCollectionAllValues;
80+
gasless: boolean;
6381
}) => Promise<void>;
64-
lazyMintNFTs: (values: CreateNFTCollectionAllValues) => Promise<void>;
6582
};
6683
};
6784

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/nft/create-nft-page.tsx

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
import { grantRole } from "thirdweb/extensions/permissions";
2222
import { useActiveAccount } from "thirdweb/react";
2323
import { maxUint256 } from "thirdweb/utils";
24+
import { create7702MinimalAccount } from "thirdweb/wallets/smart";
2425
import { revalidatePathAction } from "@/actions/revalidate";
2526
import {
2627
reportAssetCreationFailed,
@@ -42,15 +43,26 @@ export function CreateNFTPage(props: {
4243
teamPlan: Team["billingPlan"];
4344
}) {
4445
const activeAccount = useActiveAccount();
45-
4646
const addContractToProject = useAddContractToProject();
4747
const contractAddressRef = useRef<string | undefined>(undefined);
4848

49-
function getContractAndAccount(params: { chain: string }) {
49+
function getAccount(params: { gasless: boolean }) {
5050
if (!activeAccount) {
5151
throw new Error("Wallet is not connected");
5252
}
5353

54+
if (params.gasless) {
55+
return create7702MinimalAccount({
56+
adminAccount: activeAccount,
57+
client: props.client,
58+
sponsorGas: true,
59+
});
60+
}
61+
62+
return activeAccount;
63+
}
64+
65+
function getDeployedContract(params: { chain: string }) {
5466
// eslint-disable-next-line no-restricted-syntax
5567
const chain = defineChain(Number(params.chain));
5668

@@ -60,30 +72,26 @@ export function CreateNFTPage(props: {
6072
throw new Error("Contract not found");
6173
}
6274

63-
const contract = getContract({
75+
return getContract({
6476
address: contractAddress,
6577
chain,
6678
client: props.client,
6779
});
68-
69-
return {
70-
activeAccount,
71-
contract,
72-
};
7380
}
7481

7582
async function handleContractDeploy(params: {
7683
values: CreateNFTCollectionAllValues;
7784
ercType: "erc721" | "erc1155";
85+
gasless: boolean;
7886
}) {
7987
const { values: formValues, ercType } = params;
8088
const { collectionInfo, sales } = formValues;
8189
const contractType =
8290
ercType === "erc721" ? ("DropERC721" as const) : ("DropERC1155" as const);
8391

84-
if (!activeAccount) {
85-
throw new Error("Wallet is not connected");
86-
}
92+
const account = getAccount({
93+
gasless: params.gasless,
94+
});
8795

8896
// eslint-disable-next-line no-restricted-syntax
8997
const chain = defineChain(Number(collectionInfo.chain));
@@ -93,7 +101,7 @@ export function CreateNFTPage(props: {
93101

94102
if (ercType === "erc721") {
95103
contractAddress = await deployERC721Contract({
96-
account: activeAccount,
104+
account,
97105
chain: chain,
98106
client: props.client,
99107
params: {
@@ -110,7 +118,7 @@ export function CreateNFTPage(props: {
110118
});
111119
} else {
112120
contractAddress = await deployERC1155Contract({
113-
account: activeAccount,
121+
account,
114122
chain: chain,
115123
client: props.client,
116124
params: {
@@ -166,27 +174,32 @@ export function CreateNFTPage(props: {
166174
}
167175

168176
async function handleLazyMintNFTs(params: {
169-
formValues: CreateNFTCollectionAllValues;
177+
values: CreateNFTCollectionAllValues;
170178
ercType: "erc721" | "erc1155";
179+
gasless: boolean;
171180
}) {
172-
const { formValues, ercType } = params;
181+
const { values, ercType } = params;
173182
const contractType =
174183
ercType === "erc721" ? ("DropERC721" as const) : ("DropERC1155" as const);
175184

176-
const { contract, activeAccount } = getContractAndAccount({
177-
chain: formValues.collectionInfo.chain,
185+
const contract = getDeployedContract({
186+
chain: values.collectionInfo.chain,
187+
});
188+
189+
const account = getAccount({
190+
gasless: params.gasless,
178191
});
179192

180193
const lazyMintFn = ercType === "erc721" ? lazyMint721 : lazyMint1155;
181194

182195
const transaction = lazyMintFn({
183196
contract,
184-
nfts: formValues.nfts,
197+
nfts: values.nfts,
185198
});
186199

187200
try {
188201
await sendAndConfirmTransaction({
189-
account: activeAccount,
202+
account,
190203
transaction,
191204
});
192205
} catch (error) {
@@ -205,14 +218,19 @@ export function CreateNFTPage(props: {
205218
}
206219

207220
async function handleSetClaimConditionsERC721(params: {
208-
formValues: CreateNFTCollectionAllValues;
221+
values: CreateNFTCollectionAllValues;
222+
gasless: boolean;
209223
}) {
210-
const { formValues } = params;
211-
const { contract, activeAccount } = getContractAndAccount({
212-
chain: formValues.collectionInfo.chain,
224+
const { values } = params;
225+
const contract = getDeployedContract({
226+
chain: values.collectionInfo.chain,
213227
});
214228

215-
const firstNFT = formValues.nfts[0];
229+
const account = getAccount({
230+
gasless: params.gasless,
231+
});
232+
233+
const firstNFT = values.nfts[0];
216234
if (!firstNFT) {
217235
throw new Error("No NFTs found");
218236
}
@@ -235,7 +253,7 @@ export function CreateNFTPage(props: {
235253

236254
try {
237255
await sendAndConfirmTransaction({
238-
account: activeAccount,
256+
account,
239257
transaction,
240258
});
241259
} catch (error) {
@@ -259,12 +277,17 @@ export function CreateNFTPage(props: {
259277
startIndex: number;
260278
count: number;
261279
};
280+
gasless: boolean;
262281
}) {
263282
const { values, batch } = params;
264-
const { contract, activeAccount } = getContractAndAccount({
283+
const contract = getDeployedContract({
265284
chain: values.collectionInfo.chain,
266285
});
267286

287+
const account = getAccount({
288+
gasless: params.gasless,
289+
});
290+
268291
const endIndexExclusive = batch.startIndex + batch.count;
269292
const nfts = values.nfts.slice(batch.startIndex, endIndexExclusive);
270293

@@ -315,7 +338,7 @@ export function CreateNFTPage(props: {
315338

316339
try {
317340
await sendAndConfirmTransaction({
318-
account: activeAccount,
341+
account,
319342
transaction: tx,
320343
});
321344
} catch (error) {
@@ -339,15 +362,20 @@ export function CreateNFTPage(props: {
339362
admins: {
340363
address: string;
341364
}[];
365+
gasless: boolean;
342366
chain: string;
343367
}) {
344-
const { contract, activeAccount } = getContractAndAccount({
368+
const contract = getDeployedContract({
345369
chain: params.chain,
346370
});
347371

372+
const account = getAccount({
373+
gasless: params.gasless,
374+
});
375+
348376
// remove the current account from the list - its already an admin, don't have to add it again
349377
const adminsToAdd = params.admins.filter(
350-
(admin) => admin.address !== activeAccount.address,
378+
(admin) => admin.address !== account.address,
351379
);
352380

353381
const encodedTxs = await Promise.all(
@@ -369,7 +397,7 @@ export function CreateNFTPage(props: {
369397

370398
try {
371399
await sendAndConfirmTransaction({
372-
account: activeAccount,
400+
account,
373401
transaction: tx,
374402
});
375403
} catch (e) {
@@ -392,35 +420,35 @@ export function CreateNFTPage(props: {
392420
{...props}
393421
createNFTFunctions={{
394422
erc721: {
395-
deployContract: (formValues) => {
423+
deployContract: (params) => {
396424
return handleContractDeploy({
397425
ercType: "erc721",
398-
values: formValues,
426+
...params,
399427
});
400428
},
401-
lazyMintNFTs: (formValues) => {
429+
lazyMintNFTs: (params) => {
402430
return handleLazyMintNFTs({
403431
ercType: "erc721",
404-
formValues,
432+
...params,
405433
});
406434
},
407-
setClaimConditions: async (formValues) => {
435+
setClaimConditions: async (params) => {
408436
return handleSetClaimConditionsERC721({
409-
formValues,
437+
...params,
410438
});
411439
},
412440
},
413441
erc1155: {
414-
deployContract: (formValues) => {
442+
deployContract: (params) => {
415443
return handleContractDeploy({
416444
ercType: "erc1155",
417-
values: formValues,
445+
...params,
418446
});
419447
},
420-
lazyMintNFTs: (formValues) => {
448+
lazyMintNFTs: (params) => {
421449
return handleLazyMintNFTs({
422450
ercType: "erc1155",
423-
formValues,
451+
...params,
424452
});
425453
},
426454
setClaimConditions: async (params) => {

0 commit comments

Comments
 (0)