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
48 changes: 35 additions & 13 deletions apps/hyperdrive-trading/src/network/wagmiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,41 @@
import { Chain, http, Transport } from "viem";
import { base, foundry, gnosis, linea, mainnet, sepolia } from "wagmi/chains";

const {
VITE_LOCALHOST_NODE_RPC_URL,
VITE_CUSTOM_CHAIN_NODE_RPC_URL,
VITE_CUSTOM_CHAIN_CHAIN_ID,
VITE_WALLET_CONNECT_PROJECT_ID,
VITE_SEPOLIA_RPC_URL,
VITE_MAINNET_RPC_URL,
VITE_LINEA_RPC_URL,
VITE_BASE_RPC_URL,
VITE_GNOSIS_FORK_NODE_RPC_URL,
VITE_GNOSIS_FORK_CHAIN_ID,
VITE_GNOSIS_NODE_RPC_URL,
} = import.meta.env;
// Allow users to override the default RPC URL by setting it in local storage,
// especially useful for custom networks/chains
const VITE_LOCALHOST_NODE_RPC_URL =
localStorage.getItem("VITE_LOCALHOST_NODE_RPC_URL") ||
import.meta.env.VITE_LOCALHOST_NODE_RPC_URL;
const VITE_CUSTOM_CHAIN_NODE_RPC_URL =
localStorage.getItem("VITE_CUSTOM_CHAIN_NODE_RPC_URL") ||
import.meta.env.VITE_CUSTOM_CHAIN_NODE_RPC_URL;
const VITE_CUSTOM_CHAIN_CHAIN_ID =
localStorage.getItem("VITE_CUSTOM_CHAIN_CHAIN_ID") ||
import.meta.env.VITE_CUSTOM_CHAIN_CHAIN_ID;
const VITE_WALLET_CONNECT_PROJECT_ID =
localStorage.getItem("VITE_WALLET_CONNECT_PROJECT_ID") ||
import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID;
const VITE_SEPOLIA_RPC_URL =
localStorage.getItem("VITE_SEPOLIA_RPC_URL") ||
import.meta.env.VITE_SEPOLIA_RPC_URL;
const VITE_MAINNET_RPC_URL =
localStorage.getItem("VITE_MAINNET_RPC_URL") ||
import.meta.env.VITE_MAINNET_RPC_URL;
const VITE_LINEA_RPC_URL =
localStorage.getItem("VITE_LINEA_RPC_URL") ||
import.meta.env.VITE_LINEA_RPC_URL;
const VITE_BASE_RPC_URL =
localStorage.getItem("VITE_BASE_RPC_URL") ||
import.meta.env.VITE_BASE_RPC_URL;
const VITE_GNOSIS_FORK_NODE_RPC_URL =
localStorage.getItem("VITE_GNOSIS_FORK_NODE_RPC_URL") ||
import.meta.env.VITE_GNOSIS_FORK_NODE_RPC_URL;
const VITE_GNOSIS_FORK_CHAIN_ID =
localStorage.getItem("VITE_GNOSIS_FORK_CHAIN_ID") ||
import.meta.env.VITE_GNOSIS_FORK_CHAIN_ID;
const VITE_GNOSIS_NODE_RPC_URL =
localStorage.getItem("VITE_GNOSIS_NODE_RPC_URL") ||
import.meta.env.VITE_GNOSIS_NODE_RPC_URL;

interface WagmiClientConfig {
rpcUrl: string;
Expand Down Expand Up @@ -107,7 +129,7 @@
},
}).filter(
// Remove configs that don't have a proper RPC URL defined in the .env
([_, config]) => config.rpcUrl !== undefined,

Check warning on line 132 in apps/hyperdrive-trading/src/network/wagmiClient.ts

View workflow job for this annotation

GitHub Actions / verify (lint)

'_' is defined but never used. Allowed unused args must match /^unused/u
),
);

Expand Down
2 changes: 2 additions & 0 deletions apps/hyperdrive-trading/src/ui/app/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ExternalLink } from "src/ui/analytics/ExternalLink";
import { useAnalyticsUrl } from "src/ui/analytics/useMarketAnalyticsUrl";
import { HyperdriveLogo } from "src/ui/app/Navbar/HyperdriveLogo";
import { useIsTailwindSmallScreen } from "src/ui/base/mediaBreakpoints";
import { RpcForm } from "src/ui/chains/RpcForm";

export function Navbar(): ReactElement {
const analyticsUrl = useAnalyticsUrl();
Expand Down Expand Up @@ -40,6 +41,7 @@ export function Navbar(): ReactElement {
<ArrowTopRightOnSquareIcon className="-mt-0.5 inline h-4" />
</ExternalLink>

<RpcForm />
<ConnectButton
accountStatus={isTailwindSmall ? "avatar" : "full"}
showBalance={false}
Expand Down
90 changes: 90 additions & 0 deletions apps/hyperdrive-trading/src/ui/chains/RpcForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { ReactElement, useState } from "react";

// All the RPC endpoints that have been configured and are therefore used in
// this deployment of the UI
const configuredRpcEndpoints = [
["Hardhat", "VITE_LOCALHOST_NODE_RPC_URL"],
["CloudChain", "VITE_CUSTOM_CHAIN_NODE_RPC_URL"],
["Mainnet", "VITE_MAINNET_RPC_URL"],
["Linea", "VITE_LINEA_RPC_URL"],
["Base", "VITE_BASE_RPC_URL"],
["Gnosischain", "VITE_GNOSIS_NODE_RPC_URL"],
["GnosisFork", "VITE_GNOSIS_FORK_NODE_RPC_URL"],
]
.filter(([unusedName, key]) => typeof import.meta.env[key] !== "undefined")
.map(([name, key]) => {
return [name, key, localStorage.getItem(key) || import.meta.env[key]];
});

export function RpcForm(): ReactElement {
return (
<>
{/* Open the modal using document.getElementById('ID').showModal() method */}
<button
className="daisy-btn m-1 rounded-full"
// @ts-expect-error rpcModal is a Dialog element, and React doesn't
// provide the correct types for now
onClick={() => document.getElementById("rpcModal")?.showModal()}
>
Configure RPC
</button>
<dialog id="rpcModal" className="daisy-modal">
<div className="daisy-modal-box w-[600px] max-w-[600px]">
<div className="daisy-card-body">
<h3 className="daisy-card-title">RPC URLs</h3>
<p>Refresh after saving to see changes</p>
{configuredRpcEndpoints.map(([name, key, rpcUrl]) => {
return (
<RpcInput
key={key}
rpcName={name}
rpcKey={key}
rpcUrl={rpcUrl}
/>
);
})}
</div>
<div className="daisy-modal-action">
<form method="dialog">
{/* if there is a button in form, it will close the modal */}
<button className="daisy-btn">Close</button>
</form>
</div>
</div>
</dialog>
</>
);
}

function RpcInput({
rpcName,
rpcUrl,
rpcKey,
}: {
rpcName: string;
rpcUrl: string;
rpcKey: string;
}) {
const [rpcUrlDraft, setRpcUrlDraft] = useState(rpcUrl);
return (
<div className="daisy-join">
<div className="daisy-btn daisy-join-item daisy-btn-neutral">
{rpcName}
</div>
<input
type="text"
value={rpcUrlDraft}
onChange={(e) => setRpcUrlDraft(e.target.value)}
className="daisy-input daisy-join-item w-full"
/>
<button
onClick={() => {
localStorage.setItem(rpcKey, rpcUrlDraft);
}}
className="daisy-btn daisy-btn-primary daisy-join-item"
>
Save
</button>
</div>
);
}
Loading