Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-clocks-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

Fallback to eip1193 provider chain when switching chain is not supported
2 changes: 2 additions & 0 deletions apps/playground-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"fix": "eslint ./src --fix"
},
"dependencies": {
"@abstract-foundation/agw-client": "^1.0.1",
"@abstract-foundation/agw-react": "^1.0.1",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-dialog": "1.1.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { abstractWallet } from "@abstract-foundation/agw-react/thirdweb";
import { XIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect, useMemo } from "react";
import { ethereum } from "thirdweb/chains";
import {
arbitrumSepolia,
baseSepolia,
optimismSepolia,
sepolia,
} from "thirdweb/chains";
import {
ConnectButton,
type ConnectButtonProps,
Expand Down Expand Up @@ -108,12 +114,13 @@ export function RightSection(props: {
showThirdwebBranding: connectOptions.ShowThirdwebBranding,
requireApproval: connectOptions.requireApproval,
}}
chains={[sepolia, baseSepolia, optimismSepolia, arbitrumSepolia]}
wallets={wallets}
auth={connectOptions.enableAuth ? playgroundAuth : undefined}
accountAbstraction={
connectOptions.enableAccountAbstraction
? {
chain: ethereum,
chain: sepolia,
sponsorGas: true,
}
: undefined
Expand Down Expand Up @@ -171,10 +178,16 @@ export function RightSection(props: {
}}
locale={connectOptions.localeId}
auth={connectOptions.enableAuth ? playgroundAuth : undefined}
chains={[
sepolia,
baseSepolia,
optimismSepolia,
arbitrumSepolia,
]}
accountAbstraction={
connectOptions.enableAccountAbstraction
? {
chain: ethereum,
chain: sepolia,
sponsorGas: true,
}
: undefined
Expand Down Expand Up @@ -206,7 +219,14 @@ export function RightSection(props: {
* @internal
*/
export function getWallets(connectOptions: ConnectPlaygroundOptions) {
const wallets = [...connectOptions.walletIds.map((id) => createWallet(id))];
const wallets = [
...connectOptions.walletIds.map((id) => {
if (id === "xyz.abs") {
return abstractWallet();
}
return createWallet(id);
}),
];

if (
connectOptions.inAppWallet.enabled &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
"use client";
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
import { useQuery } from "@tanstack/react-query";
import { useCallback, useEffect, useRef, useState } from "react";
import type { Chain } from "../../../../../chains/types.js";
import type { ThirdwebClient } from "../../../../../client/client.js";
import type { Wallet } from "../../../../../wallets/interfaces/wallet.js";
import type { SmartWalletOptions } from "../../../../../wallets/smart/types.js";
import type { WalletInfo } from "../../../../../wallets/wallet-info.js";
import {
fontSize,
iconSize,
spacing,
} from "../../../../core/design-system/index.js";
import { useConnectionManager } from "../../../../core/providers/connection-manager.js";
import { useWalletInfo } from "../../../../core/utils/wallet.js";
import { LoadingScreen } from "../../../wallets/shared/LoadingScreen.js";
import { getSmartWalletLocale } from "../../../wallets/smartWallet/locale/getSmartWalletLocale.js";
import type { SmartWalletLocale } from "../../../wallets/smartWallet/locale/types.js";
import { Spacer } from "../../components/Spacer.js";
import { Spinner } from "../../components/Spinner.js";
import { Container, ModalHeader } from "../../components/basic.js";
import { Button } from "../../components/buttons.js";
import { Container } from "../../components/basic.js";
import { Text } from "../../components/text.js";
import type { LocaleId } from "../../types.js";
import type { ConnectLocale } from "../locale/types.js";
Expand Down Expand Up @@ -109,32 +102,11 @@
queryKey: ["getSmartWalletLocale", props.localeId],
queryFn: () => getSmartWalletLocale(props.localeId),
});
const { chain: smartWalletChain } = props.accountAbstraction;

const { personalWallet } = props;
const { done } = props;

const [personalWalletChainId, setPersonalWalletChainId] = useState<
number | undefined
>(personalWallet.getChain()?.id);

useEffect(() => {
const unsubChainChanged = personalWallet.subscribe(
"chainChanged",
(chain) => setPersonalWalletChainId(chain.id),
);

return () => {
unsubChainChanged();
};
}, [personalWallet]);

const wrongNetwork = personalWalletChainId !== smartWalletChain.id;

const [smartWalletConnectionStatus, setSmartWalletConnectionStatus] =
useState<"connecting" | "connect-error" | "idle">("idle");
const [personalWalletChainSwitchStatus, setPersonalWalletChainSwitchStatus] =
useState<"switching" | "switch-error" | "idle">("idle");
const connectionManager = useConnectionManager();

const handleConnect = useCallback(async () => {
Expand Down Expand Up @@ -168,117 +140,16 @@

const connectStarted = useRef(false);
useEffect(() => {
if (!wrongNetwork && !connectStarted.current) {
if (!connectStarted.current) {

Check warning on line 143 in packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/SmartWalletConnectUI.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/SmartWalletConnectUI.tsx#L143

Added line #L143 was not covered by tests
handleConnect();
connectStarted.current = true;
}
}, [handleConnect, wrongNetwork]);
}, [handleConnect]);

Check warning on line 147 in packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/SmartWalletConnectUI.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/SmartWalletConnectUI.tsx#L147

Added line #L147 was not covered by tests

if (!localeQuery.data) {
return <LoadingScreen />;
}

if (wrongNetwork) {
return (
<Container fullHeight animate="fadein" flex="column">
<Container p="lg">
<ModalHeader
title={props.personalWalletInfo.name}
onBack={props.onBack}
/>
</Container>

{props.size === "compact" && <Spacer y="lg" />}

<Container expand flex="column" center="both" p="lg">
<Container p={props.size === "wide" ? "lg" : undefined}>
<Container flex="row" center="x" color="danger">
<ExclamationTriangleIcon
width={iconSize.lg}
height={iconSize.lg}
/>
</Container>

<Spacer y="md" />

<Text size="lg" color="primaryText" center weight={500}>
{localeQuery.data.wrongNetworkScreen.title}
</Text>

<Spacer y="lg" />

<Text multiline center>
{localeQuery.data.wrongNetworkScreen.subtitle}
</Text>

<Spacer y="xl" />

<Container flex="column" gap="md">
<Button
type="button"
fullWidth
variant="accent"
style={{
display: "flex",
alignItems: "center",
gap: spacing.sm,
}}
onClick={async () => {
if (!personalWallet.switchChain) {
setPersonalWalletChainSwitchStatus("switch-error");
throw new Error("No switchChain method");
}

try {
setPersonalWalletChainSwitchStatus("switching");
await personalWallet.switchChain(smartWalletChain);
const newChain = personalWallet.getChain();
if (newChain) {
setPersonalWalletChainId(newChain.id);
}
setPersonalWalletChainSwitchStatus("idle");
} catch (e) {
console.error(e);
setPersonalWalletChainSwitchStatus("switch-error");
}
}}
>
{personalWalletChainSwitchStatus === "switching"
? "Switching"
: "Switch Network"}
{personalWalletChainSwitchStatus === "switching" && (
<Spinner size="sm" color="accentButtonText" />
)}
</Button>

<Container
flex="row"
gap="sm"
center="both"
color="danger"
style={{
textAlign: "center",
fontSize: fontSize.sm,
opacity:
personalWalletChainSwitchStatus === "switch-error" ? 1 : 0,
transition: "opacity 200ms ease",
}}
>
<ExclamationTriangleIcon
width={iconSize.sm}
height={iconSize.sm}
/>
<span>
{localeQuery.data.wrongNetworkScreen.failedToSwitch}
</span>
</Container>
</Container>
</Container>
</Container>
</Container>
);
}

if (smartWalletConnectionStatus === "connect-error") {
return (
<Container
Expand Down
21 changes: 15 additions & 6 deletions packages/thirdweb/src/wallets/injected/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,25 @@
// get the chainId the provider is on
const chainId = await provider
.request({ method: "eth_chainId" })
.then(normalizeChainId);
.then(normalizeChainId)
.catch((e) => {
throw new Error("Error reading chainId from provider", e);

Check warning on line 84 in packages/thirdweb/src/wallets/injected/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/injected/index.ts#L84

Added line #L84 was not covered by tests
});

let connectedChain =
chain && chain.id === chainId ? chain : getCachedChain(chainId);

// if we want a specific chainId and it is not the same as the provider chainId, trigger switchChain
// we check for undefined chain ID since some chain-specific wallets like Abstract will not send a chain ID on connection
if (chain && typeof chain.id !== "undefined" && chain.id !== chainId) {
await switchChain(provider, chain);
connectedChain = chain;
try {
// if we want a specific chainId and it is not the same as the provider chainId, trigger switchChain
// we check for undefined chain ID since some chain-specific wallets like Abstract will not send a chain ID on connection
if (chain && typeof chain.id !== "undefined" && chain.id !== chainId) {
await switchChain(provider, chain);
connectedChain = chain;
}
} catch {
console.warn(
`Error switching to chain ${chain?.id} - defaulting to wallet chain (${chainId})`,
);

Check warning on line 100 in packages/thirdweb/src/wallets/injected/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/injected/index.ts#L98-L100

Added lines #L98 - L100 were not covered by tests
}

return onConnect({
Expand Down
2 changes: 1 addition & 1 deletion packages/thirdweb/test/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default defineConfig({
setupFiles: [join(__dirname, "./reactSetup.ts")],
globalSetup: [join(__dirname, "./globalSetup.ts")],
testTimeout: 90_000,
retry: process.env.CI ? 3 : 0,
retry: 3,
maxConcurrency: 3,
bail: 1,
// clear any mocks between any tests
Expand Down
Loading
Loading