Skip to content

Commit

Permalink
Merge pull request #3 from Scaffold-Stark/bu/fixbug
Browse files Browse the repository at this point in the history
Bu/fixbug
  • Loading branch information
0xquantum3labs authored Oct 12, 2024
2 parents a5c01df + fb56500 commit 031c123
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 60 deletions.
5 changes: 4 additions & 1 deletion packages/nextjs/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"rules": {
"react-hooks/exhaustive-deps": "off"
}
}
2 changes: 1 addition & 1 deletion packages/nextjs/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ThemeProvider } from "~~/components/ThemeProvider";
import "~~/styles/globals.css";

export const metadata: Metadata = {
title: "ETH - STRK - Cross Chain Template",
title: "ETH - STRK - Multichain Template",
description: "Seamlessly interact with Starknet and Ethereum!",
icons: "/logo.ico",
};
Expand Down
30 changes: 15 additions & 15 deletions packages/nextjs/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const Home = () => {
const currentChain = useGlobalState(state => state.currentChain);
const { address } = useDynamicAccount();
const targetNetwork = useDynamicTargetNetwork();

const [isLoading, setIsLoading] = useState(true);
const [greetingState, setGreetingState] = useState("");
const [isLoading, setIsLoading] = useState(false);

const {
data: contractData,
isLoading: contractLoading,
Expand Down Expand Up @@ -98,13 +98,11 @@ const Home = () => {
}, [greeting]);

useEffect(() => {
const checkLoading = () => {
if (!contractLoading && !deployedContractLoading && !eventHistoryLoading && !isGreetingLoading) {
setIsLoading(false);
}
};

checkLoading();
if (contractLoading && deployedContractLoading && eventHistoryLoading && isGreetingLoading) {
setIsLoading(true);
} else {
setIsLoading(false);
}
}, [contractLoading, deployedContractLoading, eventHistoryLoading, isGreetingLoading]);

if (isLoading) {
Expand All @@ -125,29 +123,30 @@ const Home = () => {
<td className="font-bold max-w-[200px]">Current chain</td>
<td className="text-left">{currentChain}</td>
</tr>
<div className="my-5"></div>

<tr className="h-[20px]"></tr>
<tr>
<td className="font-bold max-w-[200px]">Current address</td>
<td className="max-w-[400px] truncate text-left">{address}</td>
</tr>
<div className="my-5"></div>
<tr className="h-[20px]"></tr>
<tr>
<td className="font-bold max-w-[200px]">YourContract greeting</td>
<td className="text-left">{isGreetingLoading ? "Loading..." : String(greeting)}</td>
</tr>
<div className="my-5"></div>
<tr className="h-[20px]"></tr>
<tr>
<td className="font-bold max-w-[200px]">Network</td>
<td className="text-left">{targetNetwork?.name}</td>
</tr>
<div className="my-5"></div>
<tr className="h-[20px]"></tr>
<tr>
<td className="font-bold max-w-[200px]">Contract address</td>
<td>
{!contractError ? <div>{contractLoading ? "Loading..." : contractData?.address}</div> : contractError}
</td>
</tr>
<div className="my-5"></div>
<tr className="h-[20px]"></tr>
<tr>
<td className="font-bold max-w-[200px]">Deployed contract info</td>
<td>
Expand All @@ -158,7 +157,7 @@ const Home = () => {
)}
</td>
</tr>
<div className="my-5"></div>
<tr className="h-[20px]"></tr>
<tr>
<td className="font-bold max-w-[200px]">Events</td>
<td>
Expand All @@ -174,6 +173,7 @@ const Home = () => {
)}
</td>
</tr>
<tr className="h-[20px]"></tr>
</tbody>
</table>

Expand Down
12 changes: 12 additions & 0 deletions packages/nextjs/components/ScaffoldAppWithProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { useEffect, useState } from "react";
import { RainbowKitProvider, darkTheme, lightTheme } from "@rainbow-me/rainbowkit";
import { BlockieAvatar } from "@scaffold-eth-2/components/scaffold-eth";
import { useInitializeNativeCurrencyPrice } from "@scaffold-eth-2/hooks/scaffold-eth";
import { useGlobalState as useEthGlobalState } from "@scaffold-eth-2/services/store/store";
import { wagmiConfig } from "@scaffold-eth-2/services/web3/wagmiConfig";
import { ChainWithAttributes } from "@scaffold-eth-2/utils/scaffold-eth";
import { useNativeCurrencyPrice } from "@scaffold-stark-2/hooks/scaffold-stark/useNativeCurrencyPrice";
import { appChains, connectors } from "@scaffold-stark-2/services/web3/connectors";
import provider from "@scaffold-stark-2/services/web3/provider";
Expand Down Expand Up @@ -47,6 +49,8 @@ export const ScaffoldAppWithProviders = ({ children }: { children: React.ReactNo
const [mounted, setMounted] = useState(false);
const setCurrentChain = useGlobalState(state => state.setCurrentChain);
const [lastSelectedChain, setLastSelectedChain] = useLocalStorage<string>("lastSelectedChain", "");
const [lastEVMChain, setLastEVMChain] = useLocalStorage<ChainWithAttributes | null>("lastEVMChain", null);
const setTargetNetwork = useEthGlobalState(state => state.setTargetNetwork);

useEffect(() => {
setMounted(true);
Expand All @@ -56,6 +60,13 @@ export const ScaffoldAppWithProviders = ({ children }: { children: React.ReactNo
setCurrentChain(ChainType.Ethereum);
setLastSelectedChain(ChainType.Ethereum);
} else {
// check if last selected chain is evm chain, then need to set last evm chain
if (lastSelectedChain == ChainType.Ethereum) {
if (lastEVMChain) {
setTargetNetwork(lastEVMChain);
setLastEVMChain(lastEVMChain);
}
}
setCurrentChain(lastSelectedChain);
}
}
Expand All @@ -68,6 +79,7 @@ export const ScaffoldAppWithProviders = ({ children }: { children: React.ReactNo
<RainbowKitProvider
avatar={BlockieAvatar}
theme={mounted ? (isDarkMode ? darkTheme() : lightTheme()) : lightTheme()}
initialChain={lastEVMChain ? lastEVMChain.id : undefined}
>
<ScaffoldCrossChainApp>{children}</ScaffoldCrossChainApp>
</RainbowKitProvider>
Expand Down
123 changes: 96 additions & 27 deletions packages/nextjs/components/Wallet/SelectNetworkModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { useEffect, useRef, useState } from "react";
import { useEffect, useState } from "react";
import Image from "next/image";
import EthNetwork from "../../public/icons/eth-network-icon.svg";
import StrkNetwork from "../../public/icons/strk-network-icon.svg";
import EthNetwork from "../../public/networks/eth-network-icon.svg";
import StrkNetwork from "../../public/networks/strk-network-icon.svg";
import GenericModal from "./scaffold-stark/CustomConnectButton/GenericModal";
import { useTargetNetwork } from "@scaffold-eth-2/hooks/scaffold-eth";
import { useGlobalState as useEthGlobalState } from "@scaffold-eth-2/services/store/store";
import { ChainWithAttributes, getTargetNetworks } from "@scaffold-eth-2/utils/scaffold-eth";
import { useLocalStorage } from "usehooks-ts";
import { useAccount, useSwitchChain } from "wagmi";
import { useGlobalState } from "~~/dynamic/services/store/global";
import { ChainType } from "~~/dynamic/types/chains";

Expand All @@ -13,20 +17,69 @@ const ArrowDownIcon = ({ color }: { color: string }) => {
<path
d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z"
fill={color}
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
);
};

export default function SelectNetWorkModal() {
const {
switchChain,
isPending: isSwitchingChain,
isError: isSwitchingError,
isSuccess: isSwitchingSuccess,
} = useSwitchChain();
const { isConnected: isEVMConnected } = useAccount();
const { currentChain, setLastEVMChain: setLastEVMChainGlobalState } = useGlobalState(state => state);
const setCurrentChain = useGlobalState(state => state.setCurrentChain);

const [open, setOpen] = useState<boolean>(false);
const [animate, setAnimate] = useState(false);
const [activeNetwork, setActiveNetwork] = useState<string>("");
const currentChain = useGlobalState(state => state.currentChain);
const setCurrentChain = useGlobalState(state => state.setCurrentChain);
const [_, setLastSelectedChain] = useLocalStorage<string>("lastSelectedChain", "");
const [ethActiveNetwork, setEthActiveNetwork] = useState<ChainWithAttributes | null>(null);

const [lastSelectedChain, setLastSelectedChain] = useLocalStorage<string>("lastSelectedChain", "");
const [_, setLastEVMChain] = useLocalStorage<ChainWithAttributes | null>("lastEVMChain", null);

const { targetNetwork: evmTargetNetwork } = useTargetNetwork();
const setTargetNetwork = useEthGlobalState(state => state.setTargetNetwork);

const evmTargetNetworks = getTargetNetworks();

useEffect(() => {
setActiveNetwork(currentChain);

if (lastSelectedChain == ChainType.Starknet && currentChain == ChainType.Ethereum) {
if (!isSwitchingChain) {
if (isSwitchingError) {
setLastSelectedChain(ChainType.Starknet);
setCurrentChain(ChainType.Starknet);
setActiveNetwork(ChainType.Starknet);
} else {
setCurrentChain(ChainType.Ethereum);
setLastSelectedChain(ChainType.Ethereum);
setActiveNetwork(ChainType.Ethereum);
}
}
} else if (lastSelectedChain == ChainType.Ethereum && currentChain == ChainType.Ethereum) {
if (!isSwitchingChain) {
setEthActiveNetwork(evmTargetNetwork);
}
if (isSwitchingError) {
setEthActiveNetwork(evmTargetNetwork);
}
if (isSwitchingSuccess) {
setCurrentChain(ChainType.Ethereum);
setLastSelectedChain(ChainType.Ethereum);
setActiveNetwork(ChainType.Ethereum);
setEthActiveNetwork(evmTargetNetwork);
}
}
}, [currentChain, evmTargetNetwork, isSwitchingError, isSwitchingSuccess]);

useEffect(() => setAnimate(open), [open]);

const closeModal = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
Expand All @@ -36,10 +89,21 @@ export default function SelectNetWorkModal() {
}, 400);
};

useEffect(() => {
setActiveNetwork(currentChain);
}, [currentChain]);
useEffect(() => setAnimate(open), [open]);
const handleEthereumNetworkClick = (network: ChainWithAttributes) => {
setEthActiveNetwork(network);
setCurrentChain(ChainType.Ethereum);
if (isEVMConnected) {
switchChain?.({ chainId: network.id });
}
setTargetNetwork(network);
setLastEVMChain(network);
setLastEVMChainGlobalState(network);
};

const handleStarknetClick = () => {
setLastSelectedChain(ChainType.Starknet);
setCurrentChain(ChainType.Starknet);
};

return (
<>
Expand Down Expand Up @@ -67,23 +131,28 @@ export default function SelectNetWorkModal() {
<p className="text-2xl font-bold text-white">Connect Network</p>
<p className="text-sm text-white">Choose your network to connect wallet</p>
<div className="flex items-center gap-4 mt-4">
<div
onClick={() => {
setActiveNetwork(ChainType.Ethereum);
setLastSelectedChain(ChainType.Ethereum);
setCurrentChain(ChainType.Ethereum);
}}
className={`network ${activeNetwork === ChainType.Ethereum ? "active-network" : "bg-network"}`}
>
<Image src={EthNetwork} alt="Ethereum Network" loading="lazy" width={50} height={50} />
<p className="uppercase mt-2">Ethereum</p>
{/* this side are all ethereum */}
<div className="flex gap-4">
{evmTargetNetworks &&
evmTargetNetworks.map(network => (
<div
key={network.id}
onClick={() => handleEthereumNetworkClick(network)}
className={`network ${
activeNetwork === ChainType.Ethereum
? ethActiveNetwork?.id === network.id
? "active-network"
: "bg-network"
: "bg-network"
}`}
>
<Image src={EthNetwork} alt="Ethereum Network" loading="lazy" width={50} height={50} />
<p className="uppercase mt-2">{network.name}</p>
</div>
))}
</div>
<div
onClick={() => {
setActiveNetwork(ChainType.Starknet);
setLastSelectedChain(ChainType.Starknet);
setCurrentChain(ChainType.Starknet);
}}
onClick={handleStarknetClick}
className={`network ${activeNetwork === ChainType.Starknet ? "active-network" : "bg-network"}`}
>
<Image src={StrkNetwork} alt="StarkNet Network" loading="lazy" width={50} height={50} />
Expand Down
8 changes: 4 additions & 4 deletions packages/nextjs/components/Wallet/scaffold-eth/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ export const Balance = ({ address, className = "", usdMode }: BalanceProps) => {
<div className="w-full flex items-center justify-center">
{displayUsdMode ? (
<>
<span className=" text-[0.8em] font-bold mr-1">$</span>
<span>{(formattedBalance * nativeCurrencyPrice).toFixed(2)}</span>
<span className="text-white text-[0.8em] font-bold mr-1">$</span>
<span className="text-white">{(formattedBalance * nativeCurrencyPrice).toFixed(2)}</span>
</>
) : (
<>
<span>{formattedBalance.toFixed(4)}</span>
<span className="text-[0.8em] font-bold ml-1">{targetNetwork.nativeCurrency.symbol}</span>
<span className="text-white">{formattedBalance.toFixed(4)}</span>
<span className="text-white text-[0.8em] font-bold ml-1">{targetNetwork.nativeCurrency.symbol}</span>
</>
)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions packages/nextjs/components/Wallet/scaffold-stark/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const Balance = ({ address, className = "", usdMode }: BalanceProps) => {
{displayUsdMode ? (
<div className="flex">
<span className="text-[0.8em] font-bold mr-1">$</span>
<span>
<span className="text-white">
{totalBalanceInUsd.toLocaleString("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
Expand All @@ -85,7 +85,7 @@ export const Balance = ({ address, className = "", usdMode }: BalanceProps) => {
<div className="text-gray-500 flex gap-4">
<div className="flex">
<span>{parseFloat(formatted).toFixed(4)}</span>
<span className="text-[0.8em] font-bold ml-1">{targetNetwork.nativeCurrency.symbol}</span>
<span className="text-[0.8em] tex-white font-bold ml-1">{targetNetwork.nativeCurrency.symbol}</span>
</div>

<div className="flex">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,41 @@ import { useTargetNetwork } from "@scaffold-stark-2/hooks/scaffold-stark/useTarg
import { getBlockExplorerAddressLink } from "@scaffold-stark-2/utils/scaffold-stark";
import { Address } from "@starknet-react/chains";
import { useAccount, useNetwork } from "@starknet-react/core";
import { useGlobalState } from "~~/dynamic/services/store/global";
import { ChainType } from "~~/dynamic/types/chains";

/**
* Custom Connect Button (watch balance + custom design)
*/
export const CustomConnectButton = () => {
const currentChain = useGlobalState(state => state.currentChain);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
if (currentChain !== undefined) {
setIsLoading(false);
}
}, [currentChain]);

if (isLoading) {
return (
<div className="btn-connect-wallet">
<p>Connect</p>
<Image src={WalletIcon} alt="wallet-icon" height={15} width={15} />
</div>
); // or return a loading indicator
}

if (currentChain === ChainType.Ethereum || currentChain == "" || currentChain == null || currentChain == undefined) {
return null;
} else {
return <CustomConnectButtonStarknet />;
}
};

export const CustomConnectButtonStarknet = () => {
useAutoConnect();

const networkColor = useNetworkColor();
const { targetNetwork } = useTargetNetwork();
const { account, status, address: accountAddress } = useAccount();
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type SharedConfig = {
const sharedConfig = {
ethereum: {
// The networks on which your DApp is live
targetNetworks: [ethChains.foundry],
targetNetworks: [ethChains.foundry, ethChains.sepolia],

// The interval at which your front-end polls the RPC servers for new data
// it has no effect if you only target the local network (default is 4000)
Expand Down
Loading

0 comments on commit 031c123

Please sign in to comment.