Skip to content

Commit 93d6147

Browse files
committed
handle if not multiple wallets supported
1 parent a285c12 commit 93d6147

File tree

8 files changed

+128
-116
lines changed

8 files changed

+128
-116
lines changed

apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
44
import type { ResultItem } from "components/engine/system-metrics/components/StatusCodes";
55
import { THIRDWEB_API_HOST } from "constants/urls";
6+
import type { EngineBackendWalletType } from "lib/engine";
67
import { useState } from "react";
78
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
89
import invariant from "tiny-invariant";
@@ -111,10 +112,16 @@ export function useEngineBackendWallets(instance: string) {
111112
});
112113
}
113114

115+
type EngineFeature =
116+
| "KEYPAIR_AUTH"
117+
| "CONTRACT_SUBSCRIPTIONS"
118+
| "IP_ALLOWLIST"
119+
| "HETEROGENEOUS_WALLET_TYPES";
120+
114121
interface EngineSystemHealth {
115122
status: string;
116123
engineVersion?: string;
117-
features?: string[];
124+
features?: EngineFeature[];
118125
}
119126

120127
export function useEngineSystemHealth(
@@ -138,6 +145,15 @@ export function useEngineSystemHealth(
138145
});
139146
}
140147

148+
// Helper function to check if a feature is supported.
149+
export function useHasEngineFeature(
150+
instanceUrl: string,
151+
feature: EngineFeature,
152+
) {
153+
const { data } = useEngineSystemHealth(instanceUrl);
154+
return !!data?.features?.includes(feature);
155+
}
156+
141157
interface EngineSystemQueueMetrics {
142158
result: {
143159
queued: number;
@@ -399,9 +415,7 @@ export function useEngineTransactions(instance: string, autoUpdate: boolean) {
399415
});
400416
}
401417

402-
export type EngineBackendWalletType = "local" | "aws-kms" | "gcp-kms";
403-
404-
interface WalletConfigResponse {
418+
export interface WalletConfigResponse {
405419
type: EngineBackendWalletType;
406420

407421
awsAccessKeyId?: string | null;
@@ -1672,41 +1686,3 @@ export function useEngineDeleteNotificationChannel(engineId: string) {
16721686
},
16731687
});
16741688
}
1675-
1676-
export interface TestNotificationChannelInput {
1677-
notificationChannelId: string;
1678-
status: "firing" | "resolved";
1679-
}
1680-
1681-
export function useEngineTestNotificationChannel(engineId: string) {
1682-
const { isLoggedIn } = useLoggedInUser();
1683-
const queryClient = useQueryClient();
1684-
1685-
return useMutation({
1686-
mutationFn: async (input: TestNotificationChannelInput) => {
1687-
invariant(isLoggedIn, "Must be logged in.");
1688-
1689-
const res = await fetch(
1690-
`${THIRDWEB_API_HOST}/v2/engine/notification-channels/${input.notificationChannelId}/test-trigger`,
1691-
{
1692-
method: "POST",
1693-
headers: {
1694-
"Content-Type": "application/json",
1695-
},
1696-
body: JSON.stringify({
1697-
status: input.status,
1698-
}),
1699-
},
1700-
);
1701-
if (!res.ok) {
1702-
throw new Error(`Unexpected status ${res.status}: ${await res.text()}`);
1703-
}
1704-
res.body?.cancel();
1705-
},
1706-
onSuccess: () => {
1707-
return queryClient.invalidateQueries({
1708-
queryKey: engineKeys.notificationChannels(engineId),
1709-
});
1710-
},
1711-
});
1712-
}

apps/dashboard/src/components/engine/configuration/engine-wallet-config.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ interface EngineWalletConfigProps {
2121
export const EngineWalletConfig: React.FC<EngineWalletConfigProps> = ({
2222
instance,
2323
}) => {
24-
const { data } = useEngineWalletConfig(instance.url);
24+
const { data: walletConfig } = useEngineWalletConfig(instance.url);
2525

2626
const tabOptions: {
2727
key: EngineBackendWalletType;
@@ -46,8 +46,8 @@ export const EngineWalletConfig: React.FC<EngineWalletConfigProps> = ({
4646
] as const;
4747
const [activeTab, setActiveTab] = useState<EngineBackendWalletType>("local");
4848

49-
const isAwsKmsConfigured = data && "awsAccessKeyId" in data;
50-
const isGcpKmsConfigured = data && "gcpKmsKeyRingId" in data;
49+
const isAwsKmsConfigured = !!walletConfig?.awsAccessKeyId;
50+
const isGcpKmsConfigured = !!walletConfig?.gcpKmsKeyRingId;
5151

5252
return (
5353
<Flex flexDir="column" gap={4}>
@@ -67,8 +67,8 @@ export const EngineWalletConfig: React.FC<EngineWalletConfigProps> = ({
6767
isEnabled: true,
6868
onClick: () => setActiveTab(key),
6969
icon:
70-
(key === "aws-kms" && isAwsKmsConfigured) ||
71-
(key === "gcp-kms" && isGcpKmsConfigured)
70+
(key === "aws-kms" && !isAwsKmsConfigured) ||
71+
(key === "gcp-kms" && !isGcpKmsConfigured)
7272
? ({ className }) => (
7373
<ToolTipLabel label="Not configured">
7474
<CircleAlertIcon className={className} />

apps/dashboard/src/components/engine/configuration/ip-allowlist.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { InlineCode } from "@/components/ui/inline-code";
22
import {
33
useEngineIpAllowlistConfiguration,
44
useEngineSetIpAllowlistConfiguration,
5-
useEngineSystemHealth,
5+
useHasEngineFeature,
66
} from "@3rdweb-sdk/react/hooks/useEngine";
77
import { Flex, Textarea } from "@chakra-ui/react";
88
import { useTxNotifications } from "hooks/useTxNotifications";
@@ -30,8 +30,7 @@ export const EngineIpAllowlistConfig: React.FC<
3030
"IP Allowlist updated successfully.",
3131
"Failed to update IP Allowlist",
3232
);
33-
34-
const { data: engineHealthInfo } = useEngineSystemHealth(instanceUrl);
33+
const isSupported = useHasEngineFeature(instanceUrl, "IP_ALLOWLIST");
3534

3635
const form = useForm<IpForm>({
3736
values: { raw: existingIpAllowlist?.join("\n") ?? "" },
@@ -61,7 +60,7 @@ export const EngineIpAllowlistConfig: React.FC<
6160
}
6261
};
6362

64-
if (!engineHealthInfo?.features?.includes("IP_ALLOWLIST")) {
63+
if (!isSupported) {
6564
return null;
6665
}
6766

apps/dashboard/src/components/engine/overview/create-backend-wallet-button.tsx

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,33 @@ import {
2626
} from "@/components/ui/select";
2727
import {
2828
type CreateBackendWalletInput,
29-
type EngineBackendWalletType,
3029
type EngineInstance,
30+
type WalletConfigResponse,
3131
useEngineCreateBackendWallet,
32-
useEngineWalletConfig,
32+
useHasEngineFeature,
3333
} from "@3rdweb-sdk/react/hooks/useEngine";
3434
import { Dialog } from "@radix-ui/react-dialog";
3535
import { useTrack } from "hooks/analytics/useTrack";
3636
import { useTxNotifications } from "hooks/useTxNotifications";
37+
import { EngineBackendWalletOptions } from "lib/engine";
3738
import { CircleAlertIcon } from "lucide-react";
3839
import Link from "next/link";
3940
import { useState } from "react";
4041
import { useForm } from "react-hook-form";
41-
42-
export const walletTypeOptions: {
43-
key: EngineBackendWalletType;
44-
name: string;
45-
}[] = [
46-
{ key: "local", name: "Local" },
47-
{ key: "aws-kms", name: "AWS KMS" },
48-
{ key: "gcp-kms", name: "Google Cloud KMS" },
49-
] as const;
42+
import invariant from "tiny-invariant";
5043

5144
interface CreateBackendWalletButtonProps {
5245
instance: EngineInstance;
46+
walletConfig: WalletConfigResponse;
5347
}
5448

5549
export const CreateBackendWalletButton: React.FC<
5650
CreateBackendWalletButtonProps
57-
> = ({ instance }) => {
58-
const { data: walletConfig } = useEngineWalletConfig(instance.url);
51+
> = ({ instance, walletConfig }) => {
52+
const supportsMultipleWalletTypes = useHasEngineFeature(
53+
instance.url,
54+
"HETEROGENEOUS_WALLET_TYPES",
55+
);
5956
const { mutate: createBackendWallet, isPending } =
6057
useEngineCreateBackendWallet(instance.url);
6158
const { onSuccess, onError } = useTxNotifications(
@@ -66,9 +63,7 @@ export const CreateBackendWalletButton: React.FC<
6663
const [isModalOpen, setIsModalOpen] = useState(false);
6764

6865
const form = useForm<CreateBackendWalletInput>({
69-
defaultValues: {
70-
type: walletConfig?.type ?? "local",
71-
},
66+
defaultValues: { type: walletConfig.type },
7267
});
7368

7469
const onSubmit = async (data: CreateBackendWalletInput) => {
@@ -96,17 +91,19 @@ export const CreateBackendWalletButton: React.FC<
9691
});
9792
};
9893

99-
const isAwsKmsConfigured =
100-
!!walletConfig &&
101-
"awsAccessKeyId" in walletConfig &&
102-
!!walletConfig.awsAccessKeyId;
103-
const isGcpKmsConfigured =
104-
!!walletConfig &&
105-
"gcpKmsKeyRingId" in walletConfig &&
106-
!!walletConfig.gcpKmsKeyRingId;
107-
10894
const walletType = form.watch("type");
109-
const selected = walletTypeOptions.find((opt) => opt.key === walletType);
95+
const selectedOption = EngineBackendWalletOptions.find(
96+
(opt) => opt.key === walletType,
97+
);
98+
invariant(selectedOption, "Selected a valid backend wallet type.");
99+
100+
// List all wallet types only if Engine is updated to support it.
101+
const walletTypeOptions = supportsMultipleWalletTypes
102+
? EngineBackendWalletOptions
103+
: [selectedOption];
104+
105+
const isAwsKmsConfigured = !!walletConfig.awsAccessKeyId;
106+
const isGcpKmsConfigured = !!walletConfig.gcpKmsKeyRingId;
110107

111108
const isFormValid =
112109
walletType === "local" ||
@@ -127,7 +124,7 @@ export const CreateBackendWalletButton: React.FC<
127124
<div className="p-6">
128125
<DialogHeader className="mb-4">
129126
<DialogTitle className="font-semibold text-2xl tracking-tight">
130-
Create wallet
127+
Create Wallet
131128
</DialogTitle>
132129
</DialogHeader>
133130

@@ -171,7 +168,7 @@ export const CreateBackendWalletButton: React.FC<
171168
<Alert variant="warning">
172169
<CircleAlertIcon className="size-5" />
173170
<AlertTitle>
174-
{selected?.name} is not yet configured
171+
{selectedOption?.name} is not yet configured
175172
</AlertTitle>
176173
<AlertDescription>
177174
Provide your credentials on the{" "}
@@ -181,8 +178,8 @@ export const CreateBackendWalletButton: React.FC<
181178
>
182179
Configuration
183180
</Link>{" "}
184-
tab to enable backend wallets stored on {selected?.name}
185-
.
181+
tab to enable backend wallets stored on{" "}
182+
{selectedOption?.name}.
186183
</AlertDescription>
187184
</Alert>
188185
) : (
@@ -217,7 +214,7 @@ export const CreateBackendWalletButton: React.FC<
217214
disabled={!isFormValid || isPending}
218215
>
219216
{isPending && <Spinner className="size-4" />}
220-
Import
217+
Create
221218
</Button>
222219
</DialogFooter>
223220
</form>

apps/dashboard/src/components/engine/overview/engine-overview.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import {
44
type EngineInstance,
55
useEngineBackendWallets,
66
useEngineTransactions,
7+
useEngineWalletConfig,
78
} from "@3rdweb-sdk/react/hooks/useEngine";
89
import { Flex, FormControl, Switch } from "@chakra-ui/react";
910
import { NetworkSelectorButton } from "components/selects/NetworkSelectorButton";
11+
import Link from "next/link";
1012
import { useState } from "react";
1113
import { FormLabel, Heading, Text } from "tw-components";
1214
import { BackendWalletsTable } from "./backend-wallets-table";
@@ -19,6 +21,7 @@ interface EngineOverviewProps {
1921
}
2022

2123
export const EngineOverview: React.FC<EngineOverviewProps> = ({ instance }) => {
24+
const { data: walletConfig } = useEngineWalletConfig(instance.url);
2225
const backendWallets = useEngineBackendWallets(instance.url);
2326
const [autoUpdate, setAutoUpdate] = useState<boolean>(true);
2427
const transactionsQuery = useEngineTransactions(instance.url, autoUpdate);
@@ -32,27 +35,41 @@ export const EngineOverview: React.FC<EngineOverviewProps> = ({ instance }) => {
3235
<Heading size="title.sm">Backend Wallets</Heading>
3336
<p className="text-sm">
3437
Engine sends blockchain transactions from backend wallets you
35-
own and manage.{" "}
38+
own and manage.
39+
</p>
40+
<p className="text-sm">
41+
Set up other wallet types from the{" "}
42+
<Link
43+
href={`/dashboard/engine/${instance.id}/configuration`}
44+
className="text-link-foreground hover:text-foreground"
45+
>
46+
Configuration
47+
</Link>{" "}
48+
tab, or{" "}
3649
<TrackedLinkTW
3750
target="_blank"
3851
href="https://portal.thirdweb.com/infrastructure/engine/features/backend-wallets"
3952
label="learn-more"
4053
category="engine"
4154
className="text-link-foreground hover:text-foreground"
4255
>
43-
Learn more about backend wallets.
56+
learn more about backend wallets.
4457
</TrackedLinkTW>
4558
</p>
46-
<p className="text-sm">
47-
Set up other wallet types from the{" "}
48-
<strong>Configuration</strong> tab.
49-
</p>
5059
</Flex>
5160

52-
<div className="flex flex-row gap-2">
53-
<ImportBackendWalletButton instance={instance} />
54-
<CreateBackendWalletButton instance={instance} />
55-
</div>
61+
{walletConfig && (
62+
<div className="flex flex-row gap-2">
63+
<ImportBackendWalletButton
64+
instance={instance}
65+
walletConfig={walletConfig}
66+
/>
67+
<CreateBackendWalletButton
68+
instance={instance}
69+
walletConfig={walletConfig}
70+
/>
71+
</div>
72+
)}
5673
</Flex>
5774

5875
<Flex flexDirection="row-reverse">

0 commit comments

Comments
 (0)