Skip to content

Commit

Permalink
fix: improve config and error messages (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
JackHamer09 authored May 23, 2024
1 parent acd2eda commit 6f61a48
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 72 deletions.
18 changes: 18 additions & 0 deletions composables/usePortalRuntimeConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const usePortalRuntimeConfig = () => {
const runtimeConfig = window && window["##runtimeConfig"];

return {
nodeType: runtimeConfig?.nodeType || (process.env.NODE_TYPE as undefined | "memory" | "dockerized" | "hyperchain"),
walletConnectProjectId: runtimeConfig?.walletConnectProjectId || process.env.WALLET_CONNECT_PROJECT_ID,
ankrToken: runtimeConfig?.ankrToken || process.env.ANKR_TOKEN,
screeningApiUrl: runtimeConfig?.screeningApiUrl || process.env.SCREENING_API_URL,
analytics: {
rudder: runtimeConfig?.analytics?.rudder
? {
key: (runtimeConfig.analytics.rudder.key || process.env.RUDDER_KEY)!,
dataplaneUrl: (runtimeConfig.analytics.rudder.dataplaneUrl || process.env.DATAPLANE_URL)!,
}
: undefined,
},
};
};
9 changes: 4 additions & 5 deletions composables/useScreening.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import { $fetch } from "ofetch";
/* Returns void if address screening was successful */
/* Fails if address screening was unsuccessful */
const validateAddress = useMemoize(async (address: string) => {
const runtimeConfig = useRuntimeConfig();
if (!runtimeConfig.public.screeningApiUrl) {
return;
}
const url = new URL(runtimeConfig.public.screeningApiUrl);
const portalRuntimeConfig = usePortalRuntimeConfig();
if (!portalRuntimeConfig.screeningApiUrl) return;

const url = new URL(portalRuntimeConfig.screeningApiUrl);
url.searchParams.append("address", address);
const response = await $fetch(url.toString()).catch(() => ({ result: true }));
if (!response.result) {
Expand Down
47 changes: 25 additions & 22 deletions composables/zksync/deposit/useFee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,12 @@ export default (tokens: Ref<Token[]>, balances: Ref<TokenAmount[] | undefined>)
const signer = getL1VoidSigner();
if (!signer) throw new Error("Signer is not available");

return await retry(async () => {
try {
return await signer.getFullRequiredDepositFee({
token: ETH_TOKEN.l1Address!,
to: params.to,
});
} catch (err) {
if (err instanceof Error && err.message.startsWith("Not enough balance for deposit!")) {
const match = err.message.match(/([\d\\.]+) ETH/);
if (feeToken.value && match?.length) {
const ethAmount = match[1].split(" ")?.[0];
recommendedBalance.value = parseEther(ethAmount);
return;
}
}
throw err;
}
});
return await retry(() =>
signer.getFullRequiredDepositFee({
token: ETH_TOKEN.l1Address!,
to: params.to,
})
);
};
const getERC20TransactionFee = () => {
return {
Expand All @@ -98,10 +86,25 @@ export default (tokens: Ref<Token[]>, balances: Ref<TokenAmount[] | undefined>)
recommendedBalance.value = undefined;
if (!feeToken.value) throw new Error("Fee tokens is not available");

if (params.tokenAddress === feeToken.value?.address) {
fee.value = await getEthTransactionFee();
} else {
fee.value = getERC20TransactionFee();
try {
if (params.tokenAddress === feeToken.value?.address) {
fee.value = await getEthTransactionFee();
} else {
fee.value = getERC20TransactionFee();
}
} catch (err) {
const message = (err as any)?.message;
if (message?.startsWith("Not enough balance for deposit!")) {
const match = message.match(/([\d\\.]+) ETH/);
if (feeToken.value && match?.length) {
const ethAmount = match[1].split(" ")?.[0];
recommendedBalance.value = parseEther(ethAmount);
return;
}
} else if (message?.includes("insufficient funds for gas * price + value")) {
throw new Error("Insufficient funds to cover deposit fee! Please, top up your account with ETH.");
}
throw err;
}
/* It can be either maxFeePerGas or gasPrice */
if (fee.value && !fee.value?.maxFeePerGas) {
Expand Down
4 changes: 3 additions & 1 deletion data/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import Hyperchains from "@/hyperchains/config.json";
import type { Token } from "@/types";
import type { Chain } from "@wagmi/core/chains";

const portalRuntimeConfig = usePortalRuntimeConfig();

export const l1Networks = {
mainnet: {
...mainnet,
Expand Down Expand Up @@ -99,6 +101,7 @@ const publicChains: ZkSyncNetwork[] = [
},
];

const nodeType = portalRuntimeConfig.nodeType;
const determineChainList = (): ZkSyncNetwork[] => {
switch (nodeType) {
case "memory":
Expand All @@ -114,7 +117,6 @@ const determineChainList = (): ZkSyncNetwork[] => {
return [...publicChains];
}
};
const nodeType = process.env.NODE_TYPE as undefined | "memory" | "dockerized" | "hyperchain";
export const isCustomNode = !!nodeType;
export const chainList: ZkSyncNetwork[] = determineChainList();
export const defaultNetwork = chainList[0];
18 changes: 14 additions & 4 deletions data/wagmi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ import { defaultWagmiConfig } from "@web3modal/wagmi";

import { chainList, type ZkSyncNetwork } from "@/data/networks";

const portalRuntimeConfig = usePortalRuntimeConfig();

const metadata = {
name: "zkSync Portal",
description: "zkSync Portal - view balances, transfer and bridge tokens",
url: "https://portal.zksync.io",
icons: ["https://portal.zksync.io/icon.png"],
};

if (!process.env.WALLET_CONNECT_PROJECT_ID) {
if (!portalRuntimeConfig.walletConnectProjectId) {
throw new Error("WALLET_CONNECT_PROJECT_ID is not set. Please set it in .env file");
}

const useExistingEraChain = (network: ZkSyncNetwork) => {
const existingNetworks = [zkSync, zkSyncSepoliaTestnet, zkSyncTestnet];
return existingNetworks.find((existingNetwork) => existingNetwork.id === network.id);
};
const createEraChain = (network: ZkSyncNetwork) => {
const formatZkSyncChain = (network: ZkSyncNetwork) => {
return {
id: network.id,
name: network.name,
Expand All @@ -29,6 +31,14 @@ const createEraChain = (network: ZkSyncNetwork) => {
default: { http: [network.rpcUrl] },
public: { http: [network.rpcUrl] },
},
blockExplorers: network.blockExplorerUrl
? {
default: {
name: "Explorer",
url: network.blockExplorerUrl,
},
}
: undefined,
};
};
const getAllChains = () => {
Expand All @@ -39,10 +49,10 @@ const getAllChains = () => {
}
};
for (const network of chainList) {
addUniqueChain(useExistingEraChain(network) ?? formatZkSyncChain(network));
if (network.l1Network) {
addUniqueChain(network.l1Network);
}
addUniqueChain(useExistingEraChain(network) ?? createEraChain(network));
}

return chains;
Expand All @@ -54,7 +64,7 @@ export const wagmiConfig = defaultWagmiConfig({
transports: Object.fromEntries(
chains.map((chain) => [chain.id, fallback(chain.rpcUrls.default.http.map((e) => http(e)))])
),
projectId: process.env.WALLET_CONNECT_PROJECT_ID,
projectId: portalRuntimeConfig.walletConnectProjectId,
metadata,
enableCoinbase: false,
});
23 changes: 8 additions & 15 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ export default defineNuxtConfig({
],
script: [
{
hid: "Rudder-JS",
src: "https://cdn.rudderlabs.com/v1.1/rudder-analytics.min.js",
defer: true,
src: "/config.js",
},
process.env.RUDDER_KEY
? {
hid: "Rudder-JS",
src: "https://cdn.rudderlabs.com/v1.1/rudder-analytics.min.js",
defer: true,
}
: undefined,
],
},
},
Expand Down Expand Up @@ -72,18 +77,6 @@ export default defineNuxtConfig({
autoprefixer: {},
},
},
runtimeConfig: {
public: {
ankrToken: process.env.ANKR_TOKEN,
screeningApiUrl: process.env.SCREENING_API_URL,
analytics: {
rudder: {
key: process.env.RUDDER_KEY,
dataplaneUrl: process.env.DATAPLANE_URL,
},
},
},
},
vite: {
define: {
// make these env available even outside of the Nuxt context
Expand Down
Empty file added public/config.js
Empty file.
12 changes: 5 additions & 7 deletions scripts/create-release-assets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
# Ensure the script stops if any command fails
set -e

# Run the final npm command
npm run generate

# Run the first npm command and move folder
npm run generate:node:memory
mv .output/public ./dist-node-memory
cp -r .output/public/ ./dist-node-memory/

# Run the second npm command and move folder
npm run generate:node:docker
mv .output/public ./dist-node-docker

# Run the final npm command
npm run generate
cp -r .output/public/ ./dist-node-docker/
7 changes: 4 additions & 3 deletions store/ethereumBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import type { TokenAmount } from "@/types";
import type { Blockchain as AnkrSupportedChains } from "@ankr.com/ankr.js";

export const useEthereumBalanceStore = defineStore("ethereumBalance", () => {
const runtimeConfig = useRuntimeConfig();
const portalRuntimeConfig = usePortalRuntimeConfig();

const onboardStore = useOnboardStore();
const { account } = storeToRefs(onboardStore);
const { eraNetwork } = storeToRefs(useZkSyncProviderStore());
Expand All @@ -22,9 +23,9 @@ export const useEthereumBalanceStore = defineStore("ethereumBalance", () => {
async () => {
if (!account.value.address) throw new Error("Account is not available");
if (!eraNetwork.value.l1Network) throw new Error(`L1 network is not available on ${eraNetwork.value.name}`);
if (!runtimeConfig.public.ankrToken) throw new Error("Ankr token is not available");
if (!portalRuntimeConfig.ankrToken) throw new Error("Ankr token is not available");

const ankrProvider = new AnkrProvider(`https://rpc.ankr.com/multichain/${runtimeConfig.public.ankrToken}`);
const ankrProvider = new AnkrProvider(`https://rpc.ankr.com/multichain/${portalRuntimeConfig.ankrToken}`);
const networkIdToAnkr = new Map<number, AnkrSupportedChains>([[l1Networks.mainnet.id, "eth"]]);
if (!networkIdToAnkr.has(eraNetwork.value.l1Network.id)) {
throw new Error(`Ankr does not support ${eraNetwork.value.l1Network.name}`);
Expand Down
3 changes: 2 additions & 1 deletion store/onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { wagmiConfig } from "@/data/wagmi";
import { confirmedSupportedWallets, disabledWallets } from "@/data/wallets";

export const useOnboardStore = defineStore("onboard", () => {
const portalRuntimeConfig = usePortalRuntimeConfig();
const { selectedColorMode } = useColorMode();
const { selectedNetwork, l1Network } = storeToRefs(useNetworkStore());

Expand Down Expand Up @@ -49,7 +50,7 @@ export const useOnboardStore = defineStore("onboard", () => {

const web3modal = createWeb3Modal({
wagmiConfig,
projectId: process.env.WALLET_CONNECT_PROJECT_ID!,
projectId: portalRuntimeConfig.walletConnectProjectId!,
termsConditionsUrl: "https://zksync.io/terms",
privacyPolicyUrl: "https://zksync.io/privacy",
themeMode: selectedColorMode.value,
Expand Down
5 changes: 3 additions & 2 deletions store/zksync/ethereumBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { wagmiConfig } from "@/data/wagmi";
import type { Hash, TokenAmount } from "@/types";

export const useZkSyncEthereumBalanceStore = defineStore("zkSyncEthereumBalances", () => {
const runtimeConfig = useRuntimeConfig();
const portalRuntimeConfig = usePortalRuntimeConfig();

const onboardStore = useOnboardStore();
const ethereumBalancesStore = useEthereumBalanceStore();
const tokensStore = useZkSyncTokensStore();
Expand Down Expand Up @@ -73,7 +74,7 @@ export const useZkSyncEthereumBalanceStore = defineStore("zkSyncEthereumBalances
async () => {
if (!l1Network.value) throw new Error(`L1 network is not available on ${selectedNetwork.value.name}`);

if (([l1Networks.mainnet.id] as number[]).includes(l1Network.value?.id) && runtimeConfig.public.ankrToken) {
if (([l1Networks.mainnet.id] as number[]).includes(l1Network.value?.id) && portalRuntimeConfig.ankrToken) {
return await getBalancesFromApi();
} else {
return await getBalancesFromRPC();
Expand Down
12 changes: 12 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,17 @@ declare global {
track: (eventName: string, params?: unknown) => void;
initialized: boolean;
};
'##runtimeConfig'?: {
nodeType?: string;
walletConnectProjectId?: string;
ankrToken?: string;
screeningApiUrl?: string;
analytics?: {
rudder?: {
key: string;
dataplaneUrl: string;
}
}
}
}
}
17 changes: 5 additions & 12 deletions utils/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
const portalRuntimeConfig = usePortalRuntimeConfig();
let analyticsLoaded = false;

async function loadRudder() {
if (!window.rudderanalytics) {
await new Promise((resolve) => setTimeout(resolve, 250));
throw new Error("Rudder not loaded");
}
const runtimeConfig = useRuntimeConfig();
window.rudderanalytics.load(
runtimeConfig.public.analytics.rudder.key,
runtimeConfig.public.analytics.rudder.dataplaneUrl
portalRuntimeConfig.analytics.rudder!.key,
portalRuntimeConfig.analytics.rudder!.dataplaneUrl
);
}

export async function initAnalytics(): Promise<boolean> {
if (analyticsLoaded) return true;

const runtimeConfig = useRuntimeConfig();
const useRudder = Boolean(
runtimeConfig.public.analytics.rudder.key && runtimeConfig.public.analytics.rudder.dataplaneUrl
);

const useRudder = Boolean(portalRuntimeConfig.analytics.rudder);
if (!useRudder || analyticsLoaded) {
return false;
}

const services = [];
if (useRudder) services.push(loadRudder());

await Promise.all(services);
await loadRudder();
analyticsLoaded = true;
return true;
}
Expand Down
9 changes: 9 additions & 0 deletions utils/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ export function formatError(error?: Error) {
(error instanceof BaseError && error?.details?.startsWith("Failed to fetch"))
) {
return new Error("Network error. Check your internet connection and try again.");
} else if (message.includes("missing response")) {
return new Error("Server error. Please try again later.");
} else if (
// eslint-disable-next-line prettier/prettier
message.includes("\"finalizeEthWithdrawal\" reverted with the following reason: xx") ||
// eslint-disable-next-line prettier/prettier
message.includes("\"finalizeWithdrawal\" reverted with the following reason: xx")
) {
return new Error("Withdrawal is already finalized!");
}
}
return error;
Expand Down

0 comments on commit 6f61a48

Please sign in to comment.