diff --git a/gaztec/src/aztecEnv.ts b/gaztec/src/aztecEnv.ts index c2ef318f3011..b6f225965ded 100644 --- a/gaztec/src/aztecEnv.ts +++ b/gaztec/src/aztecEnv.ts @@ -18,7 +18,7 @@ import { BBWASMLazyPrivateKernelProver } from "@aztec/bb-prover/wasm/lazy"; import { WASMSimulator } from "@aztec/simulator/client"; import { debug } from "debug"; import { createContext } from "react"; -import { WalletDB } from "./utils/storage"; +import { NetworkDB, WalletDB } from "./utils/storage"; import { ContractFunctionInteractionTx } from "./utils/txs"; process.env = Object.keys(import.meta.env).reduce((acc, key) => { @@ -143,6 +143,20 @@ export const AztecContext = createContext<{ }); export class AztecEnv { + static isNetworkStoreInitialized = false; + + static async initNetworkStore() { + if (!AztecEnv.isNetworkStoreInitialized) { + AztecEnv.isNetworkStoreInitialized = true; + const networkStore = await createStore(`network`, { + dataDirectory: "network", + dataStoreMapSizeKB: 1e6, + }); + const networkDB = NetworkDB.getInstance(); + networkDB.init(networkStore); + } + } + static async connectToNode(nodeURL: string): Promise { const aztecNode = await createAztecNodeClient(nodeURL); return aztecNode; diff --git a/gaztec/src/components/home/home.tsx b/gaztec/src/components/home/home.tsx index 53961430e981..52368f25a23d 100644 --- a/gaztec/src/components/home/home.tsx +++ b/gaztec/src/components/home/home.tsx @@ -1,12 +1,12 @@ import { css } from "@emotion/react"; import { ContractComponent } from "../contract/contract"; import { SidebarComponent } from "../sidebar/sidebar"; -import { useState } from "react"; -import { AztecContext } from "../../aztecEnv"; +import { useEffect, useState } from "react"; +import { AztecContext, AztecEnv } from "../../aztecEnv"; import NoSleep from "nosleep.js"; import { LogPanel } from "../logPanel/logPanel"; import logoURL from "../../assets/Aztec_logo.png"; -import { Box, Drawer } from "@mui/material"; +import { CircularProgress, Drawer, LinearProgress } from "@mui/material"; const layout = css({ display: "flex", @@ -26,17 +26,6 @@ const collapsedDrawer = css({ overflow: "hidden", }); -const noSleep = new NoSleep(); - -function enableNoSleep() { - noSleep.enable(); - document.removeEventListener("touchstart", enableNoSleep, false); -} - -// Enable wake lock. -// (must be wrapped in a user input event handler e.g. a mouse or touch handler) -document.addEventListener("touchstart", enableNoSleep, false); - export default function Home() { const [pxe, setPXE] = useState(null); const [wallet, setWallet] = useState(null); @@ -52,6 +41,17 @@ export default function Home() { const [logsOpen, setLogsOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false); + const [isNetworkStoreInitialized, setIsNetworkStoreInitialized] = + useState(false); + + useEffect(() => { + const initNetworkStore = async () => { + await AztecEnv.initNetworkStore(); + setIsNetworkStoreInitialized(true); + }; + initNetworkStore(); + }, []); + const AztecContextInitialValue = { pxe, nodeURL, @@ -94,11 +94,18 @@ export default function Home() { width: "340px", }, }} + ModalProps={{ + keepMounted: true, + }} onClose={() => setDrawerOpen(false)} variant="temporary" open={drawerOpen} > - + {isNetworkStoreInitialized ? ( + + ) : ( + + )} diff --git a/gaztec/src/components/sidebar/components/addNetworkDialog.tsx b/gaztec/src/components/sidebar/components/addNetworkDialog.tsx new file mode 100644 index 000000000000..bc2726d662e3 --- /dev/null +++ b/gaztec/src/components/sidebar/components/addNetworkDialog.tsx @@ -0,0 +1,64 @@ +import DialogTitle from "@mui/material/DialogTitle"; +import Dialog from "@mui/material/Dialog"; +import { Button, TextField, css } from "@mui/material"; +import { useState } from "react"; +import { AztecAddress } from "@aztec/aztec.js"; + +const creationForm = css({ + display: "flex", + flexDirection: "column", + gap: "1rem", + padding: "1rem", + alignItems: "center", +}); + +export function AddNetworksDialog({ + open, + onClose, +}: { + open: boolean; + onClose: (network?: string, alias?: string) => void; +}) { + const [alias, setAlias] = useState(""); + const [network, setNetwork] = useState(""); + + const addNetwork = async () => { + setAlias(""); + setNetwork(""); + onClose(network, alias); + }; + + const handleClose = () => { + setAlias(""); + setNetwork(""); + onClose(); + }; + + return ( + + Add network +
+ { + setNetwork(event.target.value); + }} + /> + { + setAlias(event.target.value); + }} + /> + + +
+
+ ); +} diff --git a/gaztec/src/components/sidebar/components/createAccountDialog.tsx b/gaztec/src/components/sidebar/components/createAccountDialog.tsx index 6ac7c9832517..cae61c9dce8f 100644 --- a/gaztec/src/components/sidebar/components/createAccountDialog.tsx +++ b/gaztec/src/components/sidebar/components/createAccountDialog.tsx @@ -35,10 +35,12 @@ export function CreateAccountDialog({ const [alias, setAlias] = useState(""); const [secretKey] = useState(Fr.random()); const [deployingAccount, setDeployingAccount] = useState(false); - const { pxe } = useContext(AztecContext); + const { pxe, setDrawerOpen, setLogsOpen } = useContext(AztecContext); const createAccount = async () => { setDeployingAccount(true); + setDrawerOpen(false); + setLogsOpen(true); const salt = Fr.random(); const account = await getSchnorrAccount( pxe, diff --git a/gaztec/src/components/sidebar/sidebar.tsx b/gaztec/src/components/sidebar/sidebar.tsx index 71190125e4ab..b5b040b36036 100644 --- a/gaztec/src/components/sidebar/sidebar.tsx +++ b/gaztec/src/components/sidebar/sidebar.tsx @@ -6,7 +6,7 @@ import Select, { SelectChangeEvent } from "@mui/material/Select"; import { AztecEnv, AztecContext, WebLogger } from "../../aztecEnv"; import { createStore } from "@aztec/kv-store/indexeddb"; import { AccountWalletWithSecretKey, Fr, AztecAddress } from "@aztec/aztec.js"; -import { WalletDB } from "../../utils/storage"; +import { NetworkDB, WalletDB } from "../../utils/storage"; import { useContext, useEffect, useState } from "react"; import { CreateAccountDialog } from "./components/createAccountDialog"; import { getSchnorrAccount } from "@aztec/accounts/schnorr"; @@ -21,6 +21,7 @@ import { CopyToClipboardButton } from "../common/copyToClipboardButton"; import { AddSendersDialog } from "./components/addSenderDialog"; import { deriveSigningKey } from "@aztec/circuits.js/keys"; import { TxsPanel } from "./components/txsPanel"; +import { AddNetworksDialog } from "./components/addNetworkDialog"; const container = css({ display: "flex", @@ -49,13 +50,13 @@ const header = css({ marginBottom: "1rem", }); -const NETWORKS = [ +type Network = { nodeURL: string; name: string }; + +const NETWORKS: Network[] = [ { nodeURL: "http://localhost:8080", name: "Local", }, - { nodeURL: "http://34.145.98.34:8080", name: "Devnet" }, - { nodeURL: "http://35.197.121.62:8080", name: "Masternet" }, ]; export function SidebarComponent() { @@ -78,6 +79,8 @@ export function SidebarComponent() { const [changingNetworks, setChangingNetworks] = useState(false); const [accounts, setAccounts] = useState([]); const [contracts, setContracts] = useState([]); + const [networks, setNetworks] = useState(NETWORKS); + const [openAddNetworksDialog, setOpenAddNetworksDialog] = useState(false); const [openCreateAccountDialog, setOpenCreateAccountDialog] = useState(false); const [openAddSendersDialog, setOpenAddSendersDialog] = useState(false); @@ -101,6 +104,22 @@ export function SidebarComponent() { return { ourAccounts, senders }; }; + useEffect(() => { + const refreshNetworks = async () => { + const aliasedBuffers = await NetworkDB.getInstance().listNetworks(); + const aliasedNetworks = parseAliasedBuffersAsString(aliasedBuffers); + const networks = [ + ...NETWORKS, + ...aliasedNetworks.map((network) => ({ + nodeURL: network.value, + name: network.key, + })), + ]; + setNetworks(networks); + }; + refreshNetworks(); + }, []); + const handleNetworkChange = async (event: SelectChangeEvent) => { setChangingNetworks(true); setPXEInitialized(false); @@ -203,6 +222,23 @@ export function SidebarComponent() { setOpenAddSendersDialog(false); }; + const handleNetworkAdded = async (network?: string, alias?: string) => { + if (network && alias) { + await NetworkDB.getInstance().storeNetwork(alias, network); + const aliasedBuffers = await NetworkDB.getInstance().listNetworks(); + const aliasedNetworks = parseAliasedBuffersAsString(aliasedBuffers); + const networks = [ + ...NETWORKS, + ...aliasedNetworks.map((network) => ({ + nodeURL: network.value, + name: network.key, + })), + ]; + setNetworks(networks); + } + setOpenAddNetworksDialog(false); + }; + return (
@@ -223,13 +259,25 @@ export function SidebarComponent() { disabled={changingNetworks} onChange={handleNetworkChange} > - {NETWORKS.map((network) => ( + {networks.map((network) => ( {network.name} ({network.nodeURL}) ))} + setOpenAddNetworksDialog(true)} + > + +  Create + + {pxe && isPXEInitialized ? ( <> diff --git a/gaztec/src/utils/storage.ts b/gaztec/src/utils/storage.ts index 4c8dd437d617..4122222695ff 100644 --- a/gaztec/src/utils/storage.ts +++ b/gaztec/src/utils/storage.ts @@ -380,3 +380,41 @@ export class WalletDB { log(`Data stored in database with alias ${type}:${key}`); } } + +export class NetworkDB { + #networks!: AztecAsyncMap; + + private static instance: NetworkDB; + + static getInstance() { + if (!NetworkDB.instance) { + NetworkDB.instance = new NetworkDB(); + } + + return NetworkDB.instance; + } + + init(store: AztecAsyncKVStore) { + this.#networks = store.openMap("networks"); + } + + async storeNetwork(network: string, alias: string) { + await this.#networks.set(network, Buffer.from(alias)); + } + + async retrieveNetwork(network: string) { + const result = await this.#networks.getAsync(network); + if (!result) { + throw new Error(`Could not find network with alias ${network}`); + } + return result.toString(); + } + + async listNetworks() { + const result = []; + for await (const [key, value] of this.#networks.entriesAsync()) { + result.push({ key, value: value.toString() }); + } + return result; + } +}