Skip to content

Commit

Permalink
feat: shared bridge support (#178)
Browse files Browse the repository at this point in the history
Co-authored-by: Ramon "9Tails" Canales <[email protected]>
Co-authored-by: Jack Hamer <[email protected]>
  • Loading branch information
3 people authored Jul 3, 2024
1 parent 8068708 commit fd29357
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 153 deletions.
2 changes: 1 addition & 1 deletion composables/zksync/useTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default (getSigner: () => Promise<Signer | undefined>, getProvider: () =>
const getRequiredBridgeAddress = async () => {
if (transaction.tokenAddress === ETH_TOKEN.address) return undefined;
const bridgeAddresses = await retrieveBridgeAddresses();
return bridgeAddresses.erc20L2;
return bridgeAddresses.sharedL2;
};
const bridgeAddress = transaction.type === "withdrawal" ? await getRequiredBridgeAddress() : undefined;

Expand Down
38 changes: 14 additions & 24 deletions composables/zksync/useWithdrawalFinalization.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useMemoize } from "@vueuse/core";
import { BigNumber, type BigNumberish } from "ethers";
import { Wallet } from "zksync-ethers";
import ZkSyncL1BridgeAbi from "zksync-ethers/abi/IL1Bridge.json";
import ZkSyncContractAbi from "zksync-ethers/abi/IZkSync.json";
import IL1SharedBridge from "zksync-ethers/abi/IL1SharedBridge.json";

import type { Hash } from "@/types";

Expand All @@ -16,13 +15,14 @@ export default (transactionInfo: ComputedRef<TransactionInfo>) => {
const { isCorrectNetworkSet } = storeToRefs(onboardStore);
const { tokens } = storeToRefs(tokensStore);

const retrieveBridgeAddress = useMemoize(() =>
const retrieveBridgeAddresses = useMemoize(() => providerStore.requestProvider().getDefaultBridgeAddresses());

const retrieveChainId = useMemoize(() =>
providerStore
.requestProvider()
.getDefaultBridgeAddresses()
.then((e) => e.erc20L1)
.getNetwork()
.then((network) => network.chainId)
);
const retrieveMainContractAddress = useMemoize(() => providerStore.requestProvider().getMainContractAddress());

const gasLimit = ref<BigNumberish | undefined>();
const gasPrice = ref<BigNumberish | undefined>();
Expand All @@ -44,7 +44,6 @@ export default (transactionInfo: ComputedRef<TransactionInfo>) => {
const feeToken = computed(() => {
return tokens.value?.[ETH_TOKEN.address];
});
const usingMainContract = computed(() => transactionInfo.value.token.address === ETH_TOKEN.address);

const getFinalizationParams = async () => {
const provider = providerStore.requestProvider();
Expand All @@ -58,6 +57,7 @@ export default (transactionInfo: ComputedRef<TransactionInfo>) => {
transactionInfo.value.transactionHash
);
return {
chainId: await retrieveChainId(),
l1BatchNumber,
l2MessageIndex,
l2TxNumberInBlock,
Expand All @@ -68,23 +68,13 @@ export default (transactionInfo: ComputedRef<TransactionInfo>) => {

const getTransactionParams = async () => {
finalizeWithdrawalParams.value = await getFinalizationParams();
if (usingMainContract.value) {
return {
address: (await retrieveMainContractAddress()) as Hash,
abi: ZkSyncContractAbi,
account: onboardStore.account.address!,
functionName: "finalizeEthWithdrawal",
args: Object.values(finalizeWithdrawalParams.value!),
};
} else {
return {
address: (await retrieveBridgeAddress()) as Hash,
abi: ZkSyncL1BridgeAbi,
account: onboardStore.account.address!,
functionName: "finalizeWithdrawal",
args: Object.values(finalizeWithdrawalParams.value!),
};
}
return {
address: (await retrieveBridgeAddresses()).sharedL1 as Hash,
abi: IL1SharedBridge,
account: onboardStore.account.address!,
functionName: "finalizeWithdrawal",
args: Object.values(finalizeWithdrawalParams.value!),
};
};

const {
Expand Down
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
1 change: 1 addition & 0 deletions data/wagmi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const formatZkSyncChain = (network: ZkSyncNetwork) => {
: undefined,
};
};

const getAllChains = () => {
const chains: Chain[] = [];
const addUniqueChain = (chain: Chain) => {
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
11 changes: 7 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions 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 Expand Up @@ -87,7 +86,7 @@
"vite": "^3.0.0",
"vue-tippy": "^6.0.0",
"web3-avatar-vue": "^1.0.0",
"zksync-ethers": "^5.5.0"
"zksync-ethers": "^5.9.0"
},
"overrides": {
"vue": "latest"
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
Loading

0 comments on commit fd29357

Please sign in to comment.