Skip to content

Commit

Permalink
fix: improve hyperchain config creation process
Browse files Browse the repository at this point in the history
  • Loading branch information
JackHamer09 committed Jun 5, 2024
1 parent bccfab9 commit 35b9f7c
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 109 deletions.
25 changes: 21 additions & 4 deletions data/networks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mainnet, sepolia } from "@wagmi/core/chains";

import Hyperchains from "@/hyperchains/config.json";
import { PUBLIC_L1_CHAINS, type Config } from "@/scripts/hyperchains/common";

import type { Token } from "@/types";
import type { Chain } from "@wagmi/core/chains";
Expand Down Expand Up @@ -101,6 +102,25 @@ const publicChains: ZkSyncNetwork[] = [
},
];

const getHyperchains = (): ZkSyncNetwork[] => {
const hyperchains = Hyperchains as Config;
return hyperchains.map((e) => {
const network: ZkSyncNetwork = {
...e.network,
getTokens: () => e.tokens,
};
if (e.network.publicL1NetworkId) {
network.l1Network = PUBLIC_L1_CHAINS.find((chain) => chain.id === e.network.publicL1NetworkId);
if (!network.l1Network) {
throw new Error(
`L1 network with ID ${e.network.publicL1NetworkId} from ${network.name} config wasn't found in the list of public L1 networks.`
);
}
}
return network;
});
};

const nodeType = portalRuntimeConfig.nodeType;
const determineChainList = (): ZkSyncNetwork[] => {
switch (nodeType) {
Expand All @@ -109,10 +129,7 @@ const determineChainList = (): ZkSyncNetwork[] => {
case "dockerized":
return [dockerizedNode];
case "hyperchain":
return (Hyperchains as unknown as Array<{ network: ZkSyncNetwork; tokens: Token[] }>).map((e) => ({
...e.network,
getTokens: () => e.tokens,
}));
return getHyperchains();
default:
return [...publicChains];
}
Expand Down
19 changes: 2 additions & 17 deletions hyperchains/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,6 @@ Portal supports custom ZK Stack Hyperchain nodes.

There are a few different ways to configure the application:

### 📁 Configure using ZK Stack configuration files
<details>
<summary>If you're using ZK Stack, just link your zksync-era repo directory to configure Portal.</summary>

1. If you haven't already setup your hyperchain yet, follow the [instructions](https://zkstack.io/quickstart)
2. Make sure to install the dependencies:
```bash
npm install
```
3. 🔄 Pull your hyperchain config files by running:
```bash
npm run hyperchain:configure
```
This will regenerate `/hyperchains/config.json` file. You can edit this file manually if needed.
4. 🚀 Now you can start or build the application. See [Development](#development-server) or [Production](#production) section below for more details.
</details>

### 🖊️ Configure automatically with form
<details>
<summary>Fill out a simple form to configure the application.</summary>
Expand Down Expand Up @@ -61,7 +44,9 @@ Array<{
rpcUrl: string; // L2 RPC URL
name: string;
blockExplorerUrl?: string; // L2 Block Explorer URL
blockExplorerApi?: string; // L2 Block Explorer API
hidden?: boolean; // Hidden in the network selector
publicL1NetworkId?: number; // If you wish to use Ethereum Mainnet or Ethereum Sepolia Testnet with default configuration. Can be provided instead of `l1Network`
l1Network?: { // @wagmi `Chain` structure https://wagmi.sh/core/chains#build-your-own
// minimal required fields shown
id: number;
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"generate:node:hyperchain": "ts-node --transpile-only scripts/hyperchains/empty-check.ts && cross-env NODE_TYPE=hyperchain npm run generate",
"generate-meta": "ts-node --transpile-only scripts/updateBridgeMetaTags.ts",
"hyperchain:create": "ts-node --transpile-only scripts/hyperchains/create.ts",
"hyperchain:configure": "ts-node --transpile-only scripts/hyperchains/configure.ts",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"prepare": "husky install",
Expand Down
3 changes: 1 addition & 2 deletions pages/send-methods.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@
:to="{ name: 'bridge-withdraw', query: $route.query }"
/>
</CommonCardWithLineButtons>
<CommonCardWithLineButtons>
<CommonCardWithLineButtons v-if="eraNetwork.displaySettings?.showPartnerLinks">
<DestinationItem
v-if="eraNetwork.displaySettings?.showPartnerLinks"
:label="`Bridge to other networks`"
:description="`Explore ecosystem of third party bridges`"
:icon="ArrowTopRightOnSquareIcon"
Expand Down
9 changes: 9 additions & 0 deletions scripts/hyperchains/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { mainnet, sepolia } from "viem/chains";

import type { ZkSyncNetwork } from "../../data/networks";
import type { Token } from "../../types";

export type Network = Omit<ZkSyncNetwork & { publicL1NetworkId?: number }, "getTokens">;
export type Config = { network: Network; tokens: Token[] }[];

export const PUBLIC_L1_CHAINS = [mainnet, sepolia];
2 changes: 1 addition & 1 deletion scripts/hyperchains/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { join as pathJoin, parse as pathParse } from "path";

import { generateNetworkConfig, logUserInfo, promptNetworkReplacement } from "./utils";

import type { Network } from "./utils";
import type { Network } from "./common";
import type { Token } from "../../types";

const rootPath = process.env.ZKSYNC_HOME;
Expand Down
182 changes: 108 additions & 74 deletions scripts/hyperchains/create.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { prompt } from "enquirer";
import slugify from "slugify";
import { mainnet, Chain } from "viem/chains";

import { PUBLIC_L1_CHAINS, type Network } from "./common";
import { generateNetworkConfig, logUserInfo, promptNetworkReplacement } from "./utils";

import type { Network } from "./utils";

const promptHyperchainInfo = async (): Promise<Network> => {
const { id, name }: { id: number; name: string } = await prompt([
{
Expand All @@ -25,95 +25,127 @@ const promptHyperchainInfo = async (): Promise<Network> => {
key,
rpcUrl,
blockExplorerUrl,
blockExplorerApi,
connectedToL1,
}: { key: string; rpcUrl: string; blockExplorerUrl: string; connectedToL1: boolean } = await prompt([
{
message: "Hyperchain key",
name: "key",
type: "input",
required: true,
initial: slugify(name, {
lower: true,
replacement: "-",
strict: true,
}),
},
{
message: "Hyperchain RPC URL",
name: "rpcUrl",
type: "input",
required: true,
},
{
message: "Hyperchain Block Explorer URL (optional)",
name: "blockExplorerUrl",
type: "input",
},
{
message: "Is hyperchain connected to L1 network?",
name: "connectedToL1",
type: "confirm",
required: true,
initial: true,
},
]);

let l1Network: Network["l1Network"] | undefined;
if (connectedToL1) {
const {
l1NetworkId,
l1NetworkName,
l1NetworkRpcUrl,
l1NetworkBlockExplorerUrl,
}: {
l1NetworkId: number;
l1NetworkName: string;
l1NetworkRpcUrl: string;
l1NetworkBlockExplorerUrl: string;
} = await prompt([
}: { key: string; rpcUrl: string; blockExplorerUrl: string; blockExplorerApi: string; connectedToL1: boolean } =
await prompt([
{
message: "L1 chain id",
name: "l1NetworkId",
type: "numeral",
message: "Hyperchain key",
name: "key",
type: "input",
required: true,
float: false,
initial: slugify(name, {
lower: true,
replacement: "-",
strict: true,
}),
},
{
message: "Displayed L1 chain name",
name: "l1NetworkName",
message: "Hyperchain RPC URL",
name: "rpcUrl",
type: "input",
required: true,
},
{
message: "L1 chain RPC URL",
name: "l1NetworkRpcUrl",
message: "Hyperchain Block Explorer URL (optional)",
name: "blockExplorerUrl",
type: "input",
required: true,
},
{
message: "L1 chain Block Explorer URL (optional)",
name: "l1NetworkBlockExplorerUrl",
message: "Hyperchain Block Explorer API (optional)",
name: "blockExplorerApi",
type: "input",
},
{
message: "Is hyperchain connected to L1 network?",
name: "connectedToL1",
type: "confirm",
required: true,
initial: true,
},
]);

l1Network = {
id: l1NetworkId,
name: l1NetworkName,
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: {
default: { http: [l1NetworkRpcUrl] },
public: { http: [l1NetworkRpcUrl] },
let l1Network: Network["l1Network"] | undefined;
let publicL1NetworkId: number | undefined;

if (connectedToL1) {
// Ask select from public L1 chains (should list all options) or `+ Add custom L1 chain`
const { selectedOption }: { selectedOption: "add-custom-chain" | Chain } = await prompt({
message: "Select L1 chain",
name: "selectedOption",
type: "select",
required: true,
choices: [
...PUBLIC_L1_CHAINS.map((chain) => ({
name: `${chain.id === mainnet.id ? "Ethereum Mainnet" : "Ethereum " + chain.name}${
chain.testnet ? " Testnet" : ""
}`,
value: chain,
})),
{ name: "+ Add custom L1 chain", value: "add-custom-chain" },
],
result(resultName) {
return this.choices.find((choice: { name: string }) => choice.name === resultName).value;
},
blockExplorers: l1NetworkBlockExplorerUrl
? {
default: {
name: l1NetworkName,
url: l1NetworkBlockExplorerUrl,
},
}
: undefined,
};
});
if (selectedOption === "add-custom-chain") {
const {
l1NetworkId,
l1NetworkName,
l1NetworkRpcUrl,
l1NetworkBlockExplorerUrl,
}: {
l1NetworkId: number;
l1NetworkName: string;
l1NetworkRpcUrl: string;
l1NetworkBlockExplorerUrl: string;
} = await prompt([
{
message: "L1 chain id",
name: "l1NetworkId",
type: "numeral",
required: true,
float: false,
},
{
message: "Displayed L1 chain name",
name: "l1NetworkName",
type: "input",
required: true,
},
{
message: "L1 chain RPC URL",
name: "l1NetworkRpcUrl",
type: "input",
required: true,
},
{
message: "L1 chain Block Explorer URL (optional)",
name: "l1NetworkBlockExplorerUrl",
type: "input",
},
]);

l1Network = {
id: l1NetworkId,
name: l1NetworkName,
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: {
default: { http: [l1NetworkRpcUrl] },
public: { http: [l1NetworkRpcUrl] },
},
blockExplorers: l1NetworkBlockExplorerUrl
? {
default: {
name: l1NetworkName,
url: l1NetworkBlockExplorerUrl,
},
}
: undefined,
};
} else {
publicL1NetworkId = selectedOption.id;
}
}

return {
Expand All @@ -122,7 +154,9 @@ const promptHyperchainInfo = async (): Promise<Network> => {
key,
rpcUrl,
blockExplorerUrl,
blockExplorerApi,
l1Network,
publicL1NetworkId,
};
};

Expand Down
11 changes: 3 additions & 8 deletions scripts/hyperchains/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ import { prompt } from "enquirer";
import { readFileSync, writeFileSync } from "fs";
import { join as pathJoin } from "path";

import { ETH_TOKEN } from "../../utils/constants";

import type { ZkSyncNetwork } from "../../data/networks";
import type { Network, Config } from "./common";
import type { Token } from "../../types";

export type Network = Omit<ZkSyncNetwork, "getTokens">;
export type Config = { network: Network; tokens: Token[] }[];

export const configPath = pathJoin(__dirname, "../../hyperchains/config.json");
const getConfig = (): Config => {
return JSON.parse(readFileSync(configPath).toString());
Expand Down Expand Up @@ -50,10 +45,10 @@ export const promptNetworkReplacement = async (network: Network) => {
export const generateNetworkConfig = (network: Network, tokens: Token[]) => {
const config = getConfig();

// Add ETH token if it's not in the list
/* // Add ETH token if it's not in the list
if (!tokens.some((token: Token) => token.address === ETH_TOKEN.address)) {
tokens.unshift(ETH_TOKEN);
}
} */

config.unshift({ network, tokens });
saveConfig(config);
Expand Down
8 changes: 6 additions & 2 deletions views/transactions/Transfer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
</template>
<template v-else-if="step === 'withdrawal-finalization-warning'">
<CommonAlert variant="warning" :icon="ExclamationTriangleIcon" class="mb-block-padding-1/2 sm:mb-block-gap">
<p>
<p v-if="!isCustomNode">
After a
<a class="underline underline-offset-2" :href="ZKSYNC_WITHDRAWAL_DELAY" target="_blank"
>24-hour withdrawal delay</a
Expand All @@ -122,6 +122,10 @@
>third-party bridges</a
>.
</p>
<p v-else>
After transaction is executed on {{ eraNetwork.l1Network?.name }}, you will need to manually claim your
funds which requires paying another transaction fee on {{ eraNetwork.l1Network?.name }}.
</p>
</CommonAlert>
<CommonButton
as="a"
Expand All @@ -140,7 +144,7 @@
</template>
<template v-else-if="step === 'confirm'">
<CommonAlert
v-if="type === 'withdrawal'"
v-if="type === 'withdrawal' && !isCustomNode"
variant="warning"
:icon="ExclamationTriangleIcon"
class="mb-block-padding-1/2 sm:mb-block-gap"
Expand Down
Loading

0 comments on commit 35b9f7c

Please sign in to comment.