Skip to content

Commit

Permalink
feat: support hyperchains and local setup (matter-labs#92)
Browse files Browse the repository at this point in the history
Added support for zkSync Era in-memory node, dockerized node and Hyperchains
Added easy Hyperchain setup with `npm run hyperchain:create` or `npm run hyperchain:migrate <path_to_your_zksync-era_repo>` to migrate config created with ZK Stack.

Co-authored-by: Ramon Canales <[email protected]>
  • Loading branch information
JackHamer09 and githubdoramon authored Aug 7, 2023
1 parent dfbba48 commit c2e89e3
Show file tree
Hide file tree
Showing 60 changed files with 1,223 additions and 166 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ dist
tests/e2e/src/support/extension
tests/e2e/reports
tests/e2e/artifacts
allure-results
.env.local
allure-results
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,48 @@
# zkSync Portal
zkSync Portal is a unique wallet dapp that brings the best of zkSync Era∎ and zkSync Lite under one friendly user interface. Crafted with an emphasis on a seamless user experience, zkSync Portal allows you to easily manage your tokens. It's your go-to interface to interact with both versions of zkSync, ensuring a smooth and efficient process every step of the way.

## Features

* Clear user interface for viewing, sending, bridging zkSync Era and zkSync Lite tokens.
* Possibility to add contacts for easy access.
* Easy setup and connection to local zkSync nodes or ZK Stack Hyperchains.

## Try it out!

Visit [portal.zksync.io](https://portal.zksync.io/) to use the latest version of zkSync Portal.

You can also find zkSync Era Bridge on [bridge.zksync.io](https://bridge.zksync.io)

## Contributing
All contributions are welcome! Feel free to make the codebase better and submit your pull request [here](https://github.com/matter-labs/dapp-portal/pulls).
---
## Connecting to local node
You can use Portal to connect to your [local zkSync Era node](https://era.zksync.io/docs/tools/testing/).

Prerequisites: Node.js version 16+, npm version 7+

1. Follow the [documentation](https://era.zksync.io/docs/tools/testing/) to set up either **in-memory node** or **dockerized local setup**.
2. Clone Portal repository and install the dependencies
```bash
git clone https://github.com/matter-labs/dapp-portal.git
cd dapp-portal
npm install
```
3. In case network ID, RPC URL or other information differs from the default values, edit them in `data/networks.ts` file. You can also customize the list of displayed tokens there.
- You can also use the [configuration form](./hyperchains/README.md#configure-automatically-with-form) to generate the config file with simple prompts.
4. Run the development server:
- For in-memory node:
```bash
npm run dev:node:memory
```
- For dockerized local setup:
```bash
npm run dev:node:docker
```
Check the console output to find started Portal URL and open it in your browser (usually http://localhost:3000)

---
## Connecting to Hyperchain

To use Portal with your ZK Stack Hyperchain, follow the instructions in this [README](./hyperchains/README.md).

---
## Development
Expand Down Expand Up @@ -41,6 +75,9 @@ npm run generate
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.

---
## Contributing
All contributions are welcome! Feel free to make the codebase better and submit your pull request [here](https://github.com/matter-labs/dapp-portal/pulls).

---
## License
Released under the [MIT License](https://github.com/matter-labs/dapp-portal/blob/main/LICENSE).
20 changes: 14 additions & 6 deletions components/modal/NetworkChange.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</div>
<CommonCardWithLineButtons>
<DestinationItem
v-for="item in eraNetworks.filter((e) => e.visible || isNetworkSelected(e))"
v-for="item in eraNetworks.filter((e) => !e.hidden || isNetworkSelected(e))"
:key="item.key"
:label="item.name"
:icon="isNetworkSelected(item) ? CheckIcon : undefined"
Expand All @@ -22,11 +22,16 @@
</CommonCardWithLineButtons>
</template>

<template v-if="networks.includes('lite') && (selectedZkSyncVersion !== 'era' || selectedNetwork.l1Network)">
<template
v-if="
networks.includes('lite') &&
(selectedZkSyncVersion !== 'era' || eraNetwork.displaySettings?.showZkSyncLiteNetworks)
"
>
<DestinationLabel v-if="networks.length > 1" label="zkSync Lite" :icon="IconsZkSyncLite" class="mb-2 mt-4" />
<CommonCardWithLineButtons>
<DestinationItem
v-for="item in zkSyncLiteNetworks.filter((e) => e.visible || isNetworkSelected(e))"
v-for="item in zkSyncLiteNetworks.filter((e) => !e.hidden || isNetworkSelected(e))"
:key="item.key"
:label="item.name"
:icon="isNetworkSelected(item) ? CheckIcon : undefined"
Expand All @@ -48,15 +53,16 @@ import { storeToRefs } from "pinia";
import IconsEra from "@/components/icons/Era.vue";
import IconsZkSyncLite from "@/components/icons/zkSyncLite.vue";
import useNetworks from "@/composables/useNetworks";
import type { L2Network } from "@/data/networks";
import type { Version } from "@/store/preferences";
import type { Version } from "@/store/network";
import type { PropType } from "vue";
import { useRoute, useRouter } from "#app";
import { eraNetworks, zkSyncLiteNetworks } from "@/data/networks";
import { useNetworkStore } from "@/store/network";
import { useEraProviderStore } from "@/store/zksync/era/provider";
import { getNetworkUrl, replaceVersionInString } from "@/utils/helpers";
import { getVersionByNetwork } from "@/utils/helpers";
defineProps({
networks: {
Expand All @@ -72,6 +78,8 @@ const emit = defineEmits<{
const route = useRoute();
const router = useRouter();
const { eraNetworks, zkSyncLiteNetworks, getVersionByNetwork } = useNetworks();
const { eraNetwork } = storeToRefs(useEraProviderStore());
const {
selectedNetwork,
l1Network,
Expand Down
57 changes: 31 additions & 26 deletions components/modal/ViewOnExplorer.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<CommonModal v-bind="$attrs" title="View on explorer">
<TypographyCategoryLabel>Selected network</TypographyCategoryLabel>
<TypographyCategoryLabel v-if="otherNetworks.length">Selected network</TypographyCategoryLabel>
<CommonCardWithLineButtons>
<DestinationItem
v-if="selectedNetworkLink.link"
Expand All @@ -20,27 +20,29 @@
/>
</CommonCardWithLineButtons>

<TypographyCategoryLabel>Other networks</TypographyCategoryLabel>
<CommonCardWithLineButtons>
<template v-for="item in otherNetworks" :key="item.destination.key">
<DestinationItem
v-if="item.link"
v-bind="item.destination"
as="a"
:icon="ArrowUpRightIcon"
:href="item.link"
target="_blank"
/>
<DestinationItem
v-else
disabled
as="button"
v-bind="item.destination"
description="No explorer available"
target="_blank"
/>
</template>
</CommonCardWithLineButtons>
<template v-if="otherNetworks.length">
<TypographyCategoryLabel>Other networks</TypographyCategoryLabel>
<CommonCardWithLineButtons>
<template v-for="item in otherNetworks" :key="item.destination.key">
<DestinationItem
v-if="item.link"
v-bind="item.destination"
as="a"
:icon="ArrowUpRightIcon"
:href="item.link"
target="_blank"
/>
<DestinationItem
v-else
disabled
as="button"
v-bind="item.destination"
description="No explorer available"
target="_blank"
/>
</template>
</CommonCardWithLineButtons>
</template>
</CommonModal>
</template>

Expand All @@ -56,10 +58,10 @@ import { useOnboardStore } from "@/store/onboard";
import { useEraProviderStore } from "@/store/zksync/era/provider";
import { useLiteProviderStore } from "@/store/zksync/lite/provider";
const { l1BlockExplorerUrl, version } = storeToRefs(useNetworkStore());
const { selectedNetwork, l1BlockExplorerUrl, version } = storeToRefs(useNetworkStore());
const { account } = storeToRefs(useOnboardStore());
const { destinations } = storeToRefs(useDestinationsStore());
const { blockExplorerUrl: eraBlockExplorerUrl } = storeToRefs(useEraProviderStore());
const { eraNetwork, blockExplorerUrl: eraBlockExplorerUrl } = storeToRefs(useEraProviderStore());
const { blockExplorerUrl: liteBlockExplorerUrl } = storeToRefs(useLiteProviderStore());
const eraNetworkLink = computed(() => ({
Expand All @@ -82,10 +84,13 @@ const selectedNetworkLink = computed(() => {
return eraNetworkLink.value;
});
const otherNetworks = computed(() => {
const list = [l1NetworkLink.value];
const list = [];
if (selectedNetwork.value.l1Network) {
list.push(l1NetworkLink.value);
}
if (version.value === "lite") {
list.push(eraNetworkLink.value);
} else {
} else if (eraNetwork.value.displaySettings?.showZkSyncLiteNetworks) {
list.push(zkSyncLiteNetworkLink.value);
}
return list;
Expand Down
29 changes: 26 additions & 3 deletions components/sidebar/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,22 @@
<WalletIcon class="navbar-link-icon" aria-hidden="true" />
<span class="navbar-link-label">Assets</span>
</NuxtLink>
<NuxtLink :to="{ name: 'payments' }" class="navbar-link">
<NuxtLink
v-if="version !== 'era' || (version === 'era' && eraNetwork.blockExplorerApi)"
:to="{ name: 'payments' }"
class="navbar-link"
>
<ArrowsRightLeftIcon class="navbar-link-icon" aria-hidden="true" />
<span class="navbar-link-label">Transactions</span>
</NuxtLink>
<NuxtLink
v-else-if="version === 'era' && !eraNetwork.blockExplorerApi"
:to="{ name: 'transaction-zksync-era-send' }"
class="navbar-link desktop-hidden"
>
<PaperAirplaneIcon class="navbar-link-icon" aria-hidden="true" />
<span class="navbar-link-label">Send</span>
</NuxtLink>
<NuxtLink :to="{ name: 'contacts' }" class="navbar-link">
<UserGroupIcon class="navbar-link-icon" aria-hidden="true" />
<span class="navbar-link-label">Contacts</span>
Expand All @@ -38,12 +50,20 @@
<script lang="ts" setup>
import { ref } from "vue";
import { ArrowsRightLeftIcon, ChevronDownIcon, UserGroupIcon, WalletIcon } from "@heroicons/vue/24/outline";
import {
ArrowsRightLeftIcon,
ChevronDownIcon,
PaperAirplaneIcon,
UserGroupIcon,
WalletIcon,
} from "@heroicons/vue/24/outline";
import { storeToRefs } from "pinia";
import { useNetworkStore } from "@/store/network";
import { useEraProviderStore } from "@/store/zksync/era/provider";
const { selectedNetwork, version } = storeToRefs(useNetworkStore());
const { eraNetwork } = storeToRefs(useEraProviderStore());
const networkChangeModalOpened = ref(false);
</script>
Expand Down Expand Up @@ -72,6 +92,9 @@ const networkChangeModalOpened = ref(false);
&.router-link-exact-active {
@apply bg-white text-primary-400 dark:bg-neutral-900 dark:text-white;
}
&.desktop-hidden {
@apply md:hidden;
}
.navbar-link-icon {
@apply h-6 w-6 text-inherit;
Expand All @@ -87,7 +110,7 @@ const networkChangeModalOpened = ref(false);
@apply border bg-gray-100 hover:border-gray-300 dark:border-neutral-900 dark:bg-neutral-900;
.navbar-link-label {
@apply text-sm;
@apply text-sm leading-tight;
}
}
.network-switch {
Expand Down
7 changes: 6 additions & 1 deletion components/transaction/AllowanceModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@
<span class="font-medium">{{ destinations.ethereum.label }}</span
>.
</p>
<a :href="`${l1BlockExplorerUrl}/tx/${transactionHash}`" target="_blank" class="alert-link">
<a
v-if="l1BlockExplorerUrl"
:href="`${l1BlockExplorerUrl}/tx/${transactionHash}`"
target="_blank"
class="alert-link"
>
Track status
<ArrowUpRightIcon class="ml-1 h-3 w-3" />
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
</CommonErrorBlock>
</div>
<CommonButtonTopLink
v-if="destination.key === 'ethereum'"
v-if="destination.key === 'ethereum' && !isCustomNode"
as="a"
:href="ERA_WITHDRAWAL_DELAY"
target="_blank"
Expand Down Expand Up @@ -101,6 +101,7 @@ import { storeToRefs } from "pinia";
import EraTransferSuccessfulModal from "@/components/transaction/zksync/era/EraTransferSuccessfulModal.vue";
import EraWithdrawalSuccessfulModal from "@/components/transaction/zksync/era/EraWithdrawalSuccessfulModal.vue";
import useNetworks from "@/composables/useNetworks";
import useTransaction from "@/composables/zksync/era/useTransaction";
import type { FeeEstimationParams } from "@/composables/zksync/era/useFee";
Expand Down Expand Up @@ -173,6 +174,7 @@ const eraProviderStore = useEraProviderStore();
const { account } = storeToRefs(useOnboardStore());
const { destinations } = storeToRefs(useDestinationsStore());
const { previousTransactionAddress } = storeToRefs(usePreferencesStore());
const { isCustomNode } = useNetworks();
const { status, error, transactionHash, commitTransaction } = useTransaction(
walletEraStore.getSigner,
Expand Down
24 changes: 21 additions & 3 deletions components/transaction/zksync/era/EraWithdrawalSuccessfulModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<EraTransferLineItem :transfer="transfer" />
</CommonCardWithLineButtons>

<CommonAlert class="mt-3" variant="neutral" :icon="InformationCircleIcon">
<CommonAlert v-if="!isCustomNode" class="mt-3" variant="neutral" :icon="InformationCircleIcon">
<p>
Your funds will be available on the <span class="font-medium">{{ destinations.ethereum.label }}</span> after a
<a :href="ERA_WITHDRAWAL_DELAY" target="_blank" class="link">~24-hour delay</a>. During this time, the
Expand All @@ -21,6 +21,16 @@
<ArrowUpRightIcon class="ml-1 h-3 w-3" />
</a>
</CommonAlert>
<CommonAlert v-else class="mt-3" variant="warning" :icon="InformationCircleIcon">
<p>
You might need to finalize this withdrawal manually to receive funds on
<span class="font-medium">{{ destinations.ethereum.label }}</span>
</p>
<a :href="ERA_FINALIZE_WITHDRAWAL" target="_blank" class="alert-link">
Learn more
<ArrowUpRightIcon class="ml-1 h-3 w-3" />
</a>
</CommonAlert>

<TransactionConfirmModalFooter>
<template v-if="layout === 'default'">
Expand All @@ -32,12 +42,14 @@
</CommonButton>
</template>
<template v-else-if="layout === 'bridge'">
<CommonButtonTopLink @click="emit('newTransaction')">Make another transaction</CommonButtonTopLink>
<CommonButtonTopLink v-if="!isCustomNode" @click="emit('newTransaction')">
Make another transaction
</CommonButtonTopLink>
<CommonButton v-if="refererName" class="mx-auto" variant="primary-solid" @click="closeWindow">
Go back to {{ refererName }}
</CommonButton>
<CommonButton
v-else
v-else-if="!isCustomNode"
as="a"
href="https://ecosystem.zksync.io"
target="_blank"
Expand All @@ -47,6 +59,9 @@
Explore ecosystem
<ArrowUpRightIcon class="ml-1 mt-0.5 h-3.5 w-3.5" aria-hidden="true" />
</CommonButton>
<CommonButton v-else class="mx-auto" variant="primary-solid" @click="emit('newTransaction')">
Make another transaction
</CommonButton>
</template>
</TransactionConfirmModalFooter>
</div>
Expand All @@ -60,6 +75,8 @@ import { storeToRefs } from "pinia";
import EraTransferLineItem from "@/components/transaction/zksync/era/EraTransferLineItem.vue";
import useNetworks from "@/composables/useNetworks";
import type { EraTransfer } from "@/utils/zksync/era/mappers";
import type { PropType } from "vue";
Expand All @@ -81,6 +98,7 @@ const emit = defineEmits<{
(eventName: "newTransaction"): void;
}>();
const { isCustomNode } = useNetworks();
const { destinations } = storeToRefs(useDestinationsStore());
const refererName = useRouteQuery("refererName");
Expand Down
Loading

0 comments on commit c2e89e3

Please sign in to comment.