Skip to content

Commit f0c3312

Browse files
authored
Merge pull request #2 from segment7/segment7
feat: Reown appkit migration
2 parents c554f08 + 88c4f40 commit f0c3312

File tree

21 files changed

+897
-132
lines changed

21 files changed

+897
-132
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@ node_modules
2020
.idea
2121

2222
# cli
23-
dist
23+
dist
24+
25+
# docs
26+
.doc/

packages/hardhat/eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default defineConfig([
3030
},
3131

3232
rules: {
33-
"@typescript-eslint/no-unused-vars": "error",
33+
"@typescript-eslint/no-unused-vars": "off",
3434
"@typescript-eslint/no-explicit-any": "off",
3535

3636
"prettier/prettier": [

packages/nextjs/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
# You'll need to prefix the variables names with NEXT_PUBLIC_ if you want to access them on the client side.
1111
# More info: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
1212
NEXT_PUBLIC_ALCHEMY_API_KEY=
13-
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
13+
NEXT_PUBLIC_PROJECT_ID=
1414

packages/nextjs/app/layout.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Space_Grotesk } from "next/font/google";
2-
import "@rainbow-me/rainbowkit/styles.css";
2+
// import "@rainbow-me/rainbowkit/styles.css"; // Commented out for Reown migration
33
import { ScaffoldEthAppWithProviders } from "~~/components/ScaffoldEthAppWithProviders";
44
import { ThemeProvider } from "~~/components/ThemeProvider";
55
import "~~/styles/globals.css";
66
import { getMetadata } from "~~/utils/scaffold-eth/getMetadata";
7+
import { headers } from "next/headers"; // Added for Reown SSR support
8+
import ReownContextProvider from "~~/services/web3/Web3Modal"; // Added for Reown
79

810
const spaceGrotesk = Space_Grotesk({
911
subsets: ["latin"],
@@ -15,12 +17,17 @@ export const metadata = getMetadata({
1517
description: "Built with 🏗 Scaffold-ETH 2",
1618
});
1719

18-
const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => {
20+
const ScaffoldEthApp = async ({ children }: { children: React.ReactNode }) => {
21+
const headersData = await headers();
22+
const cookies = headersData.get('cookie');
23+
1924
return (
2025
<html suppressHydrationWarning className={`${spaceGrotesk.variable} font-space-grotesk`}>
2126
<body>
2227
<ThemeProvider enableSystem>
28+
<ReownContextProvider cookies={cookies}>
2329
<ScaffoldEthAppWithProviders>{children}</ScaffoldEthAppWithProviders>
30+
</ReownContextProvider>
2431
</ThemeProvider>
2532
</body>
2633
</html>

packages/nextjs/app/page.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,17 @@ const Home: NextPage = () => {
2020
<span className="block text-xl font-bold">(SpeedRunEthereum Challenge #2 extension)</span>
2121
</h1>
2222
<div className="flex justify-center items-center space-x-2 flex-col">
23-
<p className="my-2 font-medium">Connected Address:</p>
24-
<Address address={connectedAddress} />
23+
{connectedAddress ? (
24+
<>
25+
<p className="my-2 font-medium">Connected Address:</p>
26+
<Address address={connectedAddress} />
27+
</>
28+
) : (
29+
<>
30+
<p className="my-2 font-medium">Connect your wallet to get started:</p>
31+
<appkit-button />
32+
</>
33+
)}
2534
</div>
2635

2736
<div className="flex items-center flex-col flex-grow pt-10">

packages/nextjs/app/token-vendor/page.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState } from "react";
44
import type { NextPage } from "next";
55
import { formatEther } from "viem";
66
import { useAccount } from "wagmi";
7-
import { AddressInput, IntegerInput } from "~~/components/scaffold-eth";
7+
import { Address, AddressInput, IntegerInput } from "~~/components/scaffold-eth";
88
import { useDeployedContractInfo, useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth";
99
import { useWatchBalance } from "~~/hooks/scaffold-eth/useWatchBalance";
1010
import { getTokenPrice, multiplyTo1e18 } from "~~/utils/scaffold-eth/priceInWei";
@@ -32,23 +32,38 @@ const TokenVendor: NextPage = () => {
3232
const { writeContractAsync: writeVendorAsync } = useScaffoldWriteContract({ contractName: "Vendor" });
3333
const { writeContractAsync: writeYourTokenAsync } = useScaffoldWriteContract({ contractName: "YourToken" });
3434

35-
// const { data: vendorTokenBalance } = useScaffoldReadContract({
36-
// contractName: "YourToken",
37-
// functionName: "balanceOf",
38-
// args: [vendorContractData?.address],
39-
// });
35+
const { data: vendorTokenBalance } = useScaffoldReadContract({
36+
contractName: "YourToken",
37+
functionName: "balanceOf",
38+
args: [vendorContractData?.address],
39+
});
4040

41-
// const { data: vendorEthBalance } = useWatchBalance({ address: vendorContractData?.address });
41+
const { data: vendorEthBalance } = useWatchBalance({ address: vendorContractData?.address });
4242

4343
const { data: tokensPerEth } = useScaffoldReadContract({
4444
contractName: "Vendor",
4545
functionName: "tokensPerEth",
4646
});
47+
const { address: connectedAddress } = useAccount();
4748

4849
return (
4950
<>
5051
<div className="flex items-center flex-col flex-grow pt-10">
5152
<div className="flex flex-col items-center bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-24 w-full max-w-lg">
53+
<div className="flex justify-center items-center space-x-2 flex-col">
54+
{connectedAddress ? (
55+
<>
56+
<p className="my-2 font-medium">Connected Address:</p>
57+
<Address address={connectedAddress} />
58+
</>
59+
) : (
60+
<>
61+
<p className="my-2 font-medium">Connect your wallet to get started:</p>
62+
<appkit-button />
63+
</>
64+
)}
65+
</div>
66+
<br/>
5267
<div className="text-xl">
5368
Your token balance:{" "}
5469
<div className="inline-flex items-center justify-center">
@@ -57,7 +72,7 @@ const TokenVendor: NextPage = () => {
5772
</div>
5873
</div>
5974
{/* Vendor Balances */}
60-
{/* <hr className="w-full border-secondary my-3" />
75+
<hr className="w-full border-secondary my-3" />
6176
<div>
6277
Vendor token balance:{" "}
6378
<div className="inline-flex items-center justify-center">
@@ -68,7 +83,7 @@ const TokenVendor: NextPage = () => {
6883
<div>
6984
Vendor eth balance: {Number(formatEther(vendorEthBalance?.value || 0n)).toFixed(4)}
7085
<span className="font-bold ml-1">ETH</span>
71-
</div> */}
86+
</div>
7287
</div>
7388

7489
{/* Buy Tokens */}

packages/nextjs/components/Header.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { usePathname } from "next/navigation";
77
import { hardhat } from "viem/chains";
88
import { Bars3Icon, BugAntIcon } from "@heroicons/react/24/outline";
99
import { BoltIcon, CircleStackIcon } from "@heroicons/react/24/outline";
10-
import { FaucetButton, RainbowKitCustomConnectButton } from "~~/components/scaffold-eth";
10+
import { FaucetButton, ReownCustomConnectButton } from "~~/components/scaffold-eth";
11+
// import { FaucetButton, RainbowKitCustomConnectButton } from "~~/components/scaffold-eth"; // Original import commented for Reown migration
1112
import { useOutsideClick, useTargetNetwork } from "~~/hooks/scaffold-eth";
1213

1314
type HeaderMenuLink = {
@@ -106,7 +107,8 @@ export const Header = () => {
106107
</ul>
107108
</div>
108109
<div className="navbar-end grow mr-4">
109-
<RainbowKitCustomConnectButton />
110+
<ReownCustomConnectButton />
111+
{/* <RainbowKitCustomConnectButton /> */}
110112
{isLocalNetwork && <FaucetButton />}
111113
</div>
112114
</div>

packages/nextjs/components/ScaffoldEthAppWithProviders.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
"use client";
22

33
import { useEffect, useState } from "react";
4-
import { RainbowKitProvider, darkTheme, lightTheme } from "@rainbow-me/rainbowkit";
4+
// import { RainbowKitProvider, darkTheme, lightTheme } from "@rainbow-me/rainbowkit"; // Commented out for Reown migration
55
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
66
import { AppProgressBar as ProgressBar } from "next-nprogress-bar";
77
import { useTheme } from "next-themes";
88
import { Toaster } from "react-hot-toast";
99
import { WagmiProvider } from "wagmi";
1010
import { Footer } from "~~/components/Footer";
1111
import { Header } from "~~/components/Header";
12-
import { BlockieAvatar } from "~~/components/scaffold-eth";
12+
// import { BlockieAvatar } from "~~/components/scaffold-eth"; // Commented out for Reown migration
1313
import { useInitializeNativeCurrencyPrice } from "~~/hooks/scaffold-eth";
14-
import { wagmiConfig } from "~~/services/web3/wagmiConfig";
14+
// import { wagmiConfig } from "~~/services/web3/wagmiConfig"; // Commented out for Reown migration
15+
import { wagmiAdapter } from "~~/services/web3/wagmi"; // Using Reown wagmi adapter
1516

1617
const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => {
1718
useInitializeNativeCurrencyPrice();
@@ -37,24 +38,27 @@ export const queryClient = new QueryClient({
3738
});
3839

3940
export const ScaffoldEthAppWithProviders = ({ children }: { children: React.ReactNode }) => {
40-
const { resolvedTheme } = useTheme();
41-
const isDarkMode = resolvedTheme === "dark";
41+
// const { resolvedTheme } = useTheme(); // Commented out for Reown migration
42+
// const isDarkMode = resolvedTheme === "dark"; // Commented out for Reown migration
4243
const [mounted, setMounted] = useState(false);
4344

4445
useEffect(() => {
4546
setMounted(true);
4647
}, []);
4748

4849
return (
49-
<WagmiProvider config={wagmiConfig}>
50+
<WagmiProvider config={wagmiAdapter.wagmiConfig as any}>
5051
<QueryClientProvider client={queryClient}>
52+
{/* Replaced RainbowKitProvider with Reown AppKit - the modal is initialized in context/Web3Modal.tsx */}
53+
{/*
5154
<RainbowKitProvider
5255
avatar={BlockieAvatar}
5356
theme={mounted ? (isDarkMode ? darkTheme() : lightTheme()) : lightTheme()}
5457
>
58+
*/}
5559
<ProgressBar height="3px" color="#2299dd" />
5660
<ScaffoldEthApp>{children}</ScaffoldEthApp>
57-
</RainbowKitProvider>
61+
{/* </RainbowKitProvider> */}
5862
</QueryClientProvider>
5963
</WagmiProvider>
6064
);
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"use client";
2+
3+
// @refresh reset
4+
import { Balance } from "../Balance";
5+
import { AddressInfoDropdown } from "../RainbowKitCustomConnectButton/AddressInfoDropdown";
6+
import { AddressQRCodeModal } from "../RainbowKitCustomConnectButton/AddressQRCodeModal";
7+
import { WrongNetworkDropdown } from "../RainbowKitCustomConnectButton/WrongNetworkDropdown";
8+
import { useAccount, useConnect, useDisconnect } from "wagmi";
9+
import { Address } from "viem";
10+
import { useNetworkColor } from "~~/hooks/scaffold-eth";
11+
import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork";
12+
import { getBlockExplorerAddressLink } from "~~/utils/scaffold-eth";
13+
14+
/**
15+
* Custom Reown Connect Button (preserving original RainbowKit design)
16+
* Uses Reown AppKit's modal for wallet connection but maintains Scaffold-ETH styling
17+
*/
18+
export const ReownCustomConnectButton = () => {
19+
const networkColor = useNetworkColor();
20+
const { targetNetwork } = useTargetNetwork();
21+
const { address, isConnected } = useAccount();
22+
const { connect, connectors } = useConnect();
23+
const { disconnect } = useDisconnect();
24+
25+
// Open Reown modal function
26+
const openConnectModal = () => {
27+
console.log('Opening Reown modal...');
28+
29+
// Try to access the global modal
30+
if (typeof window !== 'undefined') {
31+
console.log('Window available, checking for modal...');
32+
33+
// First try: access modal directly from global scope
34+
if ((window as any).modal && (window as any).modal.open) {
35+
console.log('Found modal in global scope, opening...');
36+
(window as any).modal.open();
37+
return;
38+
}
39+
40+
// Second try: trigger click on hidden appkit button
41+
const appkitButton = document.querySelector('appkit-button');
42+
if (appkitButton) {
43+
console.log('Found appkit-button, triggering click...');
44+
(appkitButton as any).click();
45+
return;
46+
}
47+
48+
// Third try: use wagmi connect with first available connector
49+
const connector = connectors[0];
50+
if (connector) {
51+
console.log('Using wagmi connector:', connector.name);
52+
connect({ connector });
53+
return;
54+
}
55+
}
56+
57+
// Fallback: show error or use default behavior
58+
console.warn('Reown modal not found, falling back to default connector');
59+
const connector = connectors[0];
60+
if (connector) {
61+
connect({ connector });
62+
}
63+
};
64+
65+
const connected = isConnected && address;
66+
const blockExplorerAddressLink = address
67+
? getBlockExplorerAddressLink(targetNetwork, address)
68+
: undefined;
69+
70+
return (
71+
<>
72+
{(() => {
73+
if (!connected) {
74+
return (
75+
<button className="btn btn-primary btn-sm" onClick={openConnectModal} type="button">
76+
Wallet
77+
</button>
78+
);
79+
}
80+
81+
// Note: We're not implementing chain switching validation here since
82+
// Reown handles this automatically. If needed, chain validation can be added.
83+
84+
return (
85+
<>
86+
<div className="flex flex-col items-center mr-1">
87+
<Balance address={address as Address} className="min-h-0 h-auto" />
88+
<span className="text-xs" style={{ color: networkColor }}>
89+
{targetNetwork.name}
90+
</span>
91+
</div>
92+
<AddressInfoDropdown
93+
address={address as Address}
94+
displayName={address} // Reown doesn't provide ENS resolution in the same way
95+
ensAvatar={undefined} // Will be handled by AddressInfoDropdown internally
96+
blockExplorerAddressLink={blockExplorerAddressLink}
97+
/>
98+
<AddressQRCodeModal address={address as Address} modalId="qrcode-modal" />
99+
</>
100+
);
101+
})()}
102+
</>
103+
);
104+
};
105+
106+
// Note: Not exporting as RainbowKitCustomConnectButton to avoid conflicts
107+
// Use ReownCustomConnectButton directly or update imports to use the new name

packages/nextjs/components/scaffold-eth/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export * from "./BlockieAvatar";
44
export * from "./Faucet";
55
export * from "./FaucetButton";
66
export * from "./Input";
7-
export * from "./RainbowKitCustomConnectButton";
7+
export * from "./RainbowKitCustomConnectButton"; // Original RainbowKit version (preserved)
8+
export * from "./ReownCustomConnectButton"; // New Reown version

0 commit comments

Comments
 (0)