Skip to content

Commit

Permalink
feat: Add arbitrum support (#250)
Browse files Browse the repository at this point in the history
  • Loading branch information
brunomenezes authored Sep 24, 2024
1 parent c6dc57d commit ca1518d
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 16 deletions.
38 changes: 25 additions & 13 deletions apps/web/src/components/networks/cartesiScanNetworks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import {
useMantineTheme,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { T, cond, includes } from "ramda";
import { FC } from "react";
import { TbCaretUpFilled, TbExternalLink } from "react-icons/tb";
import {
anvil,
arbitrum,
arbitrumSepolia,
base,
baseSepolia,
mainnet,
Expand All @@ -24,6 +25,7 @@ import {
sepolia,
} from "viem/chains";
import { useConfig } from "wagmi";
import ArbitrumIcon from "../icons/Arbitrum";
import BaseIcon from "../icons/Base";
import EthereumIcon from "../icons/Ethereum";
import HardhatIcon from "../icons/Hardhat";
Expand All @@ -37,6 +39,8 @@ const chainIds = [
base.id,
baseSepolia.id,
anvil.id,
arbitrum.id,
arbitrumSepolia.id,
] as const;

type IconType = typeof EthereumIcon;
Expand Down Expand Up @@ -73,6 +77,12 @@ const mainnets: NetworkGroup[] = [
chainId: base.id,
externalLink: "https://base.cartesiscan.io",
},
{
Icon: ArbitrumIcon,
text: arbitrum.name,
chainId: arbitrum.id,
externalLink: "https://arbitrum.cartesiscan.io",
},
];

const testnets: NetworkGroup[] = [
Expand All @@ -95,6 +105,12 @@ const testnets: NetworkGroup[] = [
chainId: baseSepolia.id,
externalLink: "https://base-sepolia.cartesiscan.io",
},
{
Icon: ArbitrumIcon,
text: arbitrumSepolia.name,
chainId: arbitrumSepolia.id,
externalLink: "https://arbitrum-sepolia.cartesiscan.io",
},
];

const NetworkGroup: FC<NetworkGroupProps> = ({
Expand Down Expand Up @@ -141,18 +157,14 @@ const CaretIcon: FC<{ up: boolean }> = ({ up }) => {
return <TbCaretUpFilled style={styles} size={18} />;
};

const getIconByChainId = cond([
[
(id: number) => includes(id, [mainnet.id, sepolia.id]),
() => EthereumIcon,
],
[
(id: number) => includes(id, [optimism.id, optimismSepolia.id]),
() => OptimismIcon,
],
[(id: number) => includes(id, [base.id, baseSepolia.id]), () => BaseIcon],
[T, () => HardhatIcon],
]);
const allNetworks = [...mainnets, ...testnets];

const getIconByChainId = (id: number) => {
const network = allNetworks.find((network) => network.chainId === id);
if (network) return network.Icon;

return HardhatIcon;
};

const MainIcon: FC<{ chainId: number }> = ({ chainId }) => {
const Icon = getIconByChainId(chainId);
Expand Down
19 changes: 19 additions & 0 deletions apps/web/src/providers/walletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { ReactNode } from "react";
import Jazzicon, { jsNumberForAddress } from "react-jazzicon";
import { createConfig, fallback, http, WagmiProvider } from "wagmi";
import {
arbitrum,
arbitrumSepolia,
base,
baseSepolia,
foundry,
Expand All @@ -38,6 +40,8 @@ const chain =
optimismSepolia,
base,
baseSepolia,
arbitrum,
arbitrumSepolia,
].find((c) => c.id == chainId) || foundry;

const projectId = "a6265c875f8a7513ac7c52362abf434b";
Expand Down Expand Up @@ -86,6 +90,8 @@ const [defaultOptimismRpcUrl] = optimism.rpcUrls.default.http;
const [defaultOptimismSepoliaRpcUrl] = optimismSepolia.rpcUrls.default.http;
const [defaultBaseRpcUrl] = base.rpcUrls.default.http;
const [defaultBaseSepoliaRpcUrl] = baseSepolia.rpcUrls.default.http;
const [defaultArbitrumRpcUrl] = arbitrum.rpcUrls.default.http;
const [defaultArbitrumSepoliaRpcUrl] = arbitrumSepolia.rpcUrls.default.http;

const wagmiConfig = createConfig({
ssr: true,
Expand Down Expand Up @@ -133,6 +139,19 @@ const wagmiConfig = createConfig({
http(defaultBaseSepoliaRpcUrl),
])
: http(defaultBaseSepoliaRpcUrl),
[arbitrum.id]: alchemyApiKey
? fallback([
http(`https://arb-mainnet.g.alchemy.com/v2/${alchemyApiKey}`),
http(defaultArbitrumRpcUrl),
])
: http(defaultArbitrumRpcUrl),

[arbitrumSepolia.id]: alchemyApiKey
? fallback([
http(`https://arb-sepolia.g.alchemy.com/v2/${alchemyApiKey}`),
http(defaultArbitrumSepoliaRpcUrl),
])
: http(defaultArbitrumSepoliaRpcUrl),
},
});

Expand Down
4 changes: 3 additions & 1 deletion apps/web/test/components/layout/shell.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,15 @@ describe("Shell component", () => {

const menuEl = await screen.findByRole("menu");

expect(getAllByRole(menuEl, "menuitem")).toHaveLength(6);
expect(getAllByRole(menuEl, "menuitem")).toHaveLength(8);
expect(getByText(menuEl, "Ethereum")).toBeInTheDocument();
expect(getByText(menuEl, "Sepolia")).toBeInTheDocument();
expect(getByText(menuEl, "OP Mainnet")).toBeInTheDocument();
expect(getByText(menuEl, "OP Sepolia")).toBeInTheDocument();
expect(getByText(menuEl, "Base")).toBeInTheDocument();
expect(getByText(menuEl, "Base Sepolia")).toBeInTheDocument();
expect(getByText(menuEl, "Arbitrum One")).toBeInTheDocument();
expect(getByText(menuEl, "Arbitrum Sepolia")).toBeInTheDocument();
});
});

Expand Down
62 changes: 60 additions & 2 deletions apps/web/test/components/networks/cartesiScanNetworks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import {
} from "@testing-library/react";
import {
anvil,
arbitrum,
arbitrumSepolia,
base,
baseSepolia,
mainnet,
optimism,
optimismSepolia,
Expand Down Expand Up @@ -83,7 +87,7 @@ describe("CartesiScanNetworks component", () => {
);
});

it("Should display the Optimism network icon when chain set is Optimism Sepolia", () => {
it("Should display the Hardhat icon when chain set is anvil", () => {
useConfigMock.mockReturnValue({
chains: [anvil],
});
Expand All @@ -96,6 +100,58 @@ describe("CartesiScanNetworks component", () => {
);
});

it("Should display the Base network icon when chain set is Base Mainnet", () => {
useConfigMock.mockReturnValue({
chains: [base],
});

render(<Component />);

expect(screen.getByText("Base")).toBeInTheDocument();
expect(screen.getByRole("img").getAttribute("alt")).toEqual(
"The Base icon",
);
});

it("Should display the Base network icon when chain set is Base Sepolia", () => {
useConfigMock.mockReturnValue({
chains: [baseSepolia],
});

render(<Component />);

expect(screen.getByText("Base Sepolia")).toBeInTheDocument();
expect(screen.getByRole("img").getAttribute("alt")).toEqual(
"The Base icon",
);
});

it("Should display the Arbitrum network icon when chain set is Arbitrum Mainnet", () => {
useConfigMock.mockReturnValue({
chains: [arbitrum],
});

render(<Component />);

expect(screen.getByText("Arbitrum One")).toBeInTheDocument();
expect(screen.getByRole("img").getAttribute("alt")).toEqual(
"The Arbitrum icon",
);
});

it("Should display the Arbitrum network icon when chain set is Arbitrum Sepolia", () => {
useConfigMock.mockReturnValue({
chains: [arbitrumSepolia],
});

render(<Component />);

expect(screen.getByText("Arbitrum Sepolia")).toBeInTheDocument();
expect(screen.getByRole("img").getAttribute("alt")).toEqual(
"The Arbitrum icon",
);
});

it("should list the networks cartesiscan supports as links to the live sites", async () => {
const { container } = render(<Component />);

Expand All @@ -112,7 +168,7 @@ describe("CartesiScanNetworks component", () => {

expect(getByText(menuEl, "Mainnets")).toBeVisible();
expect(getByText(menuEl, "Testnets")).toBeVisible();
expect(menuItems).toHaveLength(6);
expect(menuItems).toHaveLength(8);

[
["Ethereum", "https://cartesiscan.io"],
Expand All @@ -121,6 +177,8 @@ describe("CartesiScanNetworks component", () => {
["OP Mainnet", "https://optimism.cartesiscan.io"],
["OP Sepolia", "https://optimism-sepolia.cartesiscan.io"],
["Base Sepolia", "https://base-sepolia.cartesiscan.io"],
["Arbitrum One", "https://arbitrum.cartesiscan.io"],
["Arbitrum Sepolia", "https://arbitrum-sepolia.cartesiscan.io"],
].forEach(([expectedName, expectedLink]) => {
expect(
getByText(menuEl, expectedName)
Expand Down

0 comments on commit ca1518d

Please sign in to comment.