# Introduction

## What is zkLink Nova?

zkLink Nova is the industry’s first aggregated Layer 3 zkEVM Rollup network built on top of Ethereum and Ethereum Layer 2 rollups (L2s). zkLink Nova is an EVM-compatible, open platform for simple and fast smart contract development of any kind. zkLink Nova’s platform allows for scattered assets across Ethereum Layer 2s to be aggregated for interoperable transactions. zkLink Nova is secured by zero-knowledge proof technology, charges extremely low gas costs, offers fast finality, and inherits its security from Ethereum.

<figure><img src="/files/zJVRUKlKeafa1pow4h7n" alt=""><figcaption></figcaption></figure>

Based on zkLink Nova’s aggregated Layer 3, we’re developing Chain Abstraction (CA) solutions, which abstract away the complexity of blockchain technology in the multi-chain world. DApps and liquidity from all connected blockchains would be aggregated onto zkLink Nova. Users would be able to easily interact with any DApps on any connected blockchain, without need to concern which blockchain they are using.&#x20;

## Why do we need an Aggregated Rollup?

The rise of multiple Layer 2s has created a non-interoperable and fragmented blockchain landscape where liquidity is trapped on siloed chains. This reality has caused a significant breakdown in network effects that has hampered adoption, and resulted in a capital-inefficient and security-vulnerable Ethereum ecosystem. Cross-rollup transactions are very costly (via Ethereum L1) or lack security (via trusted bridges). In addition, native assets on Ethereum’s different Layer 2s such as ARB, OP, MANTA, among others, cannot be traded with interoperability.

<br>

<figure><img src="/files/fyJheCqWq0I524sDADqD" alt=""><figcaption></figcaption></figure>

There are several solutions proposed to solve these issues and unify liquidity across Layer 2 sub-ecosystems, such as by providing a unified bridge or a shared sequencer (e.g. OP's Superchain, Polygon's AggLayer, zkSync's Hyperbridge). While these approaches enable atomic cross-rollup transactions, they are only applicable within their separated sub-ecosystems and specific technology stack choices. Under this scenario, having multiple different technology stacks may exacerbate the liquidity fragmentation and cross-chain interoperability issues at hand and result in an even more divided Ethereum ecosystem.

Therefore, we have created a new paradigm to aggregate fragmented assets on different Layer 2s through an aggregated Layer 3 Rollup. Our solution connects Ethereum and its Layer 2s via a Layer 3 (L3) network, secured by zero-knowledge proofs and multi-chain state synchronization. Assets on any of our connected Layer 2s can be bridged to our Layer 3 network for fast and interoperable transactions on Nova with minimal security assumptions, low cost and highly scalability. Our approach sacrifices the atomic interoperability of cross-rollup transactions, but offers the broadest liquidity that’s able to be aggregated from the entire Ethereum ecosystem.

In addition, to promote mass adoption, we believe the complexity of blockchain technology should be abstracted away from the user experience when navigating in the multi-chain world. Through our Chain Abstraction solutions built on top of zkLink Nova, users will be able to seamlessly access to liquidity and DApps on other connected blockchain networks as well, empowered Nova's powerful multi-chain settlement capability with security inherited from Ethereum. &#x20;

zkLink Nova’s mission is to aggregate and unify the fragmented liquidity across the Ethereum ecosystem, including Ethereum Layer 2 Rollups, thereby fostering a unified and interoperable rollup ecosystem to promote the permissionless mass adoption of DApps.<br>

## Key Features of zkLink Nova

### **Supporting Universal dApps**

zkLink Nova supports the development of all DApps through smart contracts. To facilitate developer migration to zkLink Nova, we aim to be EVM-compatible by utilizing the ZK Stack, which means that all the contracts and tools that work on Ethereum and Ethereum Layer 2s, also work on zkLink Nova with minimal modifications – and developers can also easily reuse the functionality that others have already built.&#x20;

### Native Asset Aggregation

Users can deposit assets from Ethereum’s Layer 1 as well as Ethereum Layer 2s directly to zkLink Nova. These assets will be locked inside the contracts on the source chains and enter the zkLink Nova network via a canonical rollup bridge. This feature allows for applications on Nova to have access to all the connected Layer 2s’ native tokens, including Ethereum, thereby allowing users to trade their multi-chain assets with interoperability. In addition, tokens of the same kind, but bridged to Nova from separate rollups, will be merged into the same token, such as ETH, USDT, USDC, etc., thus fostering unified liquidity on one chain, zkLink Nova’s Layer 3.

### Chain Abstraction

Empowered by Nova's native Account Abstraction (AA), multi-chain smart account is designed to facilitate users to interact with the Dapps deployed on any connected blockchain networks with simple and flexible transaction approval method. Users could see their aggregated assets on multiple chains through a unified interface, and seamlessly use their asset on one chain for the transaction on another chain, without need to concern where the funds locate. Based on Nova's multi-chain settlement infrastructure, fillers in the solver network can safely fulfill users' intent of cross-chain transactions with low cost and high security.&#x20;

### Low Fee and High Scalability

zkLink Nova's modular stack provides unparalleled scalability for dApps building on top of our ecosystem. ZK Stack is used by zkLink Nova as the execution layer, which can dramatically reduce execution costs and provide for a blazing-fast user experience. In Validium mode, an external DA solution will further reduce the data portion of transaction costs on the network for end users.

### Ethereum Equivalent Security

zkLink Nova is the first aggregated rollup network to achieve Ethereum-grade security. To achieve this feat, every transaction on zkLink Nova undergoes verification via zero-knowledge proofs. The issue of deposit fraud for cross-chain asset transfers is prevented through zkLink Nexus’s multi-chain state synchronization mechanism, which inherits the security of Ethereum.


# Connecting to Nova

## Mainnet info

Network Name: zkLink Nova

Explorer: <https://explorer.zklink.io>

ChainID: 810180

Currency Symbol: ETH

Bridge: <https://portal.zklink.io>

RPC:&#x20;

&#x20;    <https://rpc.zklink.io>

&#x20;    <https://rpc.zklink.network>

&#x20;   [ wss://rpc.zklink.io](wss://rpc.zklink.io)

&#x20;   [ wss://rpc.zklink.network](< wss://rpc.zklink.network>)

Multcall Contract: [0x825267E0fA5CAe92F98540828a54198dcB3Eaeb5](https://explorer.zklink.io/address/0x825267E0fA5CAe92F98540828a54198dcB3Eaeb5#contract)

## Testnet info

Network Name: zkLink Nova Testnet

Explorer:  [ https://sepolia.explorer.zklink.io](< https://sepolia.explorer.zklink.io>)

ChainID: 810181&#x20;

Currency Symbol: ETH

Bridge: <https://sepolia.portal.zklink.io>

RPC:&#x20;

&#x20;   HTTPS: <https://sepolia.rpc.zklink.io>

&#x20;   WSS: wss\://sepolia.rpc.zklink.io


# Nova Points

Starting on March 14th, 2024, [Aggregation Parade Online Campaign](https://app.zklink.io/aggregation-parade) was launched to reward early participants of zkLink Nova ecosystem with Nova points, which will be used to recognize and reward individuals with $ZKL.

## How to Earn Points <a href="#how-to-earn-points" id="how-to-earn-points"></a>

### 1. Staking Assets on Nova

Users can earn Nova Points by holding eligible assets on Nova. Nova Points are distributed **every 8 hours** based on the value of the assets held, denominated in ETH, and are adjusted with **token multipliers** that favor assets of high liquidity.

*Nova Point from holding token A = token A balance \* token A price in ETH \* token A multiplier*

Users can view which tokens are eligible to earn Nova Points and their respective multipliers on the campaign's [Asset Dashboard](https://app.zklink.io/aggregation-parade).

{% hint style="info" %}
Note:

Token multipliers are reviewed and adjusted periodically to reflect latest market liquidity conditions and what assets are being promoted on Nova. Currently, ETH and merged wBTC, USDT, USDC, DAI have 5x multiplier, while other eligible tokens have 1x-2x multipliers.&#x20;
{% endhint %}

### 2. Contributing TVL in dApps on Nova

Users can earn more Nova Points by staking their assets in DeFi protocols compared to merely holding them in their wallets. Nova Points are distributed based on the value of token assets held by the user's LP token, valued in ETH, and are enhanced with a dApp's **TVL booster** specific to each asset.&#x20;

*Nova Point from staking token A in dApp X= token A balance held by LP token\* token A price in ETH \** TVL booster for token A in dApp X

Users can view which dApps are eligible to earn Nova Points and detailed information about how Nova Points can be earn on the campaign's[ Eco dApps Dashboard](https://app.zklink.io/aggregation-parade).

{% hint style="info" %}
Note:

1. Within each dApp, TVL boosters vary for different tokens based on liquidity and trading demand. These boosters are reviewed and adjusted periodically to reflect latest market liquidity conditions and what dApps and assets are being promoted on Nova. Currently, in most dApps, ETH and merged wBTC, USDT, USDC, DAI have 10x boost, while other eligible tokens have 2x-4x boost.&#x20;
2. Token balance owned in a dApp is not always equals to the initial amount deposited into the dApp. For the case of providing liquidity to an AMM DEX, token balance owned by a user may alter due to price movements. For the case of depositing into a lending protocol, tokens being borrowed from a lending pool are not counted as the holding of the LP token.&#x20;
3. Extra boosts are provided only for effective liquidity. For AMM DEX, two-sided liquidity provision is required to qualify for the dApp booster.
   {% endhint %}

### 3. Interacting with dApps on Nova

Users can also earn Nova Points by engaging with specific types of dApps. For perpetual DEXs, points are distributed based on the user's trading volume in USD. For bridges, GameFi, and SocialFi dApps, points are awarded based on the number of transactions made.

By participating in these activities, users can significantly contribute to the growth and vitality of the zkLink Nova ecosystem while being rewarded for their involvement.

### 4. Referring Friends

Those who refer new participants will earn 10% of the Nova Points from their direct invitees throughout the campaign’s Epochs. Please note that 10% of the Nova Points earned from a user’s referral will be distributed to the user’s account by sector (per the invitee’s campaign activity).&#x20;

In addition, users who successfully invite a new referee can get 1 Invite Box which equates to a certain amount of Nova Points.

### 5. Others&#x20;

Users can earn Nova Points by playing daily "Roulette" game and open a mystery box they earned through participating certain sub-campaign events.

## Reward Distribution in Season II&#x20;

Aggregation Parade Season II kicked off on May 31st, 2024, immediately following the conclusion of Season I.&#x20;

In order to reward users more frequently, Season II is divided into **at least three epochs**, with each epoch spanning approximately **6 weeks**.

Season II aims to accelerate the growth of eco DApps by distributing a substantial reward pool of 30,000,000 ZKL tokens across various sectors, including:

* Spot DEX
* Perp DEX
* Lending
* GameFi
* Other Protocols
* Native Boost Program
* Staking Asset & Points Reward

The allocation for each sector's prize pool will be contingent on the milestones reached during that epoch. For instance, in the Spot DEX sector, an increase in the total value locked (TVL) will lead to a larger allocation of the ZKL prize pool.

| Milestone   | Prize Pool Size |
| ----------- | --------------- |
| Base Reward | 100,000 ZKL     |
| TVL > $5mn  | 500,000 ZKL     |
| TVL > $25mn | 1,000,000 ZKL   |
| TVL > $50mn | 1,500,000 ZKL   |

{% hint style="info" %}
Note: Please find the latest detailed information about prize pools for all sectors in our campaign page.
{% endhint %}

In each epoch, your Nova Points earned from a sector will be used to determine the share of ZKL token reward you will get from the prize pool of that specific sector:

*Your ZKL reward from Sector A = Your Nova Points gained from Sector A / Total Nova Points distributed for Sector A \* Prize Pool of Sector A*


# Total Value Locked(TVL)

When users bridging their assets from connected networks (base chains) to Nova, the assets will be locked in the smart contracts deployed on base chains.&#x20;

The Total Value Locked(TVL) shown on Nova's [Homepage](https://zklink.io/) and [Explore](https://explorer.zklink.io/) is calculated in real-time by summing up the value of:

* ETH locked in **zkLink contracts** deployed on all base chains
* ERC-20 tokens locked in the **ERC-20 bridge contracts** deployed on all base chains

### zkLink contract addresses deployed on different networks

Ethereum: [0x5fD9F73286b7E8683Bab45019C94553b93e015Cf](https://etherscan.io/address/0x5fD9F73286b7E8683Bab45019C94553b93e015Cf)

Linea: [0x5Cb18b6e4e6F3b46Ce646b0f4704D53724C5Df05](https://lineascan.build/address/0x5Cb18b6e4e6F3b46Ce646b0f4704D53724C5Df05)

Manta: [0xD784d7128B46B60Ca7d8BdC17dCEC94917455657](https://manta.socialscan.io/address/0xd784d7128b46b60ca7d8bdc17dcec94917455657)

Mantle: [0xD784d7128B46B60Ca7d8BdC17dCEC94917455657](https://mantle.socialscan.io/address/0xd784d7128b46b60ca7d8bdc17dcec94917455657)

zkSync Era: [0xaFe8C7Cf33eD0fee179DFF20ae174C660883273A](https://explorer.zksync.io/address/0xaFe8C7Cf33eD0fee179DFF20ae174C660883273A)

Arbitrum: [0xFF73a1a1d27951A005eb23276dc99CB7F8d5420A](https://arbiscan.io/address/0xFF73a1a1d27951A005eb23276dc99CB7F8d5420A)

Blast: [0x29BA92Fe724beD5c5EBfd0099F2F64a6DC5078FD](https://blastscan.io/address/0x29BA92Fe724beD5c5EBfd0099F2F64a6DC5078FD)

Optimism: [0x46C8D02E93d5a03899dFa7Cf8A40A07589A3fA1b](https://optimistic.etherscan.io/address/0x46c8d02e93d5a03899dfa7cf8a40a07589a3fa1b)

Base: [0xE473ce141b1416Fe526eb63Cf7433b7B8d7264Dd](https://basescan.org/address/0xe473ce141b1416fe526eb63cf7433b7b8d7264dd)

Scroll: [0x119B9459D9119D07c23aD06778AeaBec804Fd1a2](https://scrollscan.com/address/0x119B9459D9119D07c23aD06778AeaBec804Fd1a2)

### ERC-20 bridge contract addresses deployed on different networks

Ethereum: [0xAd16eDCF7DEB7e90096A259c81269d811544B6B6](https://etherscan.io/address/0xAd16eDCF7DEB7e90096A259c81269d811544B6B6)

Linea: [0x62cE247f34dc316f93D3830e4Bf10959FCe630f8](https://lineascan.build/address/0x62cE247f34dc316f93D3830e4Bf10959FCe630f8)

Manta: [0x44a65dc12865A1e5249b45b4868f32b0E37168FF](https://manta.socialscan.io/address/0x44a65dc12865a1e5249b45b4868f32b0e37168ff)

Mantle: [0x62351b47e060c61868Ab7E05920Cb42bD9A5f2B2](https://mantle.socialscan.io/address/0x62351b47e060c61868ab7e05920cb42bd9a5f2b2)

zkSync Era: [0xaB3DDB86072a35d74beD49AA0f9210098ebf2D08](https://explorer.zksync.io/address/0xaB3DDB86072a35d74beD49AA0f9210098ebf2D08)

Arbitrum: [0xfB0Ad0B3C2605A7CA33d6badd0C685E11b8F5585](https://arbiscan.io/address/0xfB0Ad0B3C2605A7CA33d6badd0C685E11b8F5585)

Blast: [0x8Df0c2bA3916bF4789c50dEc5A79b2fc719F500b](https://blastscan.io/address/0x8Df0c2bA3916bF4789c50dEc5A79b2fc719F500b)

Optimism: [0x5Bd51296423A9079b931414C1De65e7057326EaA](https://optimistic.etherscan.io/address/0x5Bd51296423A9079b931414C1De65e7057326EaA)

Base: [0x80d12A78EfE7604F00ed07aB2f16F643301674D5](https://basescan.org/address/0x80d12a78efe7604f00ed07ab2f16f643301674d5)

Scroll: [0x3C7c0ebFCD5786ef48df5ed127cdDEb806db976c](https://scrollscan.com/address/0x3C7c0ebFCD5786ef48df5ed127cdDEb806db976c)


# Zero-Knowledge Rollup

zkLink Nova is a zero-knowledge rollup network that uses ZK-SNARK technology.

In zero-knowledge rollups, transactions are processed and validated off-chain by a set of validators. However, instead of publishing the details of each transaction to the main chain, the validators bundle multiple transactions into a single cryptographic proof, known as a zero-knowledge proof. This proof attests to the correctness of the transactions without revealing any sensitive information about them. This way, the main chain only needs to verify the validity of the zero-knowledge proof rather than each individual transaction, significantly reducing the computational load and congestion on the main chain.

The benefits of zero-knowledge rollups include:

1. **Scalability**: By moving transaction processing off-chain and using zero-knowledge proofs to attest to their validity, zero-knowledge rollups can significantly increase the throughput of blockchain networks, allowing them to process more transactions per second.
2. **Reduced Costs**: With fewer transactions being processed on the main chain, the cost per transaction can be significantly reduced, making it more economical for users to interact with the blockchain.
3. **Better Security:** Zero-knowledge proofs ensure correctness of off-chain transactions and prevent operators from executing invalid state transitions. It relies on trustless cryptographic mechanisms for security, not the honesty of incentivized actors as with optimistic rollups.
4. **Faster Finality**: Compared with optimistic rollup, which delays in transaction finality due to potential fraud challenges, zero-knowledge rollups offer faster transaction finality as state updates are approved once validity proofs are verified on L1.

**For more details, we recommend reading:**&#x20;

{% embed url="<https://vitalik.eth.limo/general/2021/01/05/rollup.html>" %}


# zkEVM

zkLink Nova is powered by the zkEVM of [ZK Stack](https://zkstack.io/), a modular, open-source framework that is both free and designed to build custom ZK-powered L2s and L3s, based on the code of zkSync.&#x20;

A zkEVM (zero-knowledge Ethereum Virtual Machine) is a virtual machine that executes smart contract transactions in a way that’s compatible with both zero-knowledge-proof computations and existing Ethereum infrastructure.&#x20;

Being EVM compatible enables zkLink Nova to run programs created for Ethereum environments without modifying the underlying smart contract logic. Developers familiar with Ethereum’s Solidity programming language can build highly scalable applications using the same battle-tested tools they’re used to.

{% hint style="info" %}
According to Vitalik Buterin, EVM compatibility can be segmented into four types. The zkEVM of ZK Stack used by zkLink Nova is categorized as a Type 4 system in the taxonomy of zkEVMs. Its EVM compatibility works by taking smart contract source code written in high-level languages and compiling it to a language designed to be zk-SNARK-friendly.&#x20;
{% endhint %}

**For more details, we recommend reading:**&#x20;

{% embed url="<https://vitalik.eth.limo/general/2022/08/04/zkevm.html>" %}


# Layer 3

Layer 3s are a third layer built on top of Ethereum Layer 2 Rollups that deliver higher scalability, lower gas costs, and greater customizability.

In contrast to most Layer 3 App Rollups that are designed for meeting a specific application’s needs and deployed on a single Layer 2 (e.g., Starknet or Arbitrum), zkLink Nova is a general-purpose Layer 3 rollup network  built on top of Ethereum and multiple Ethereum Layer 2s, which jointly serve as settlement layers.

zkLink Nova’s aggregated Layer 3 zkEVM Rollup makes it a platform for the easy deployment of any decentralized applications that are already built on Ethereum’s Layer 1 and Layer 2 rollups. zkLink Nova DApp users and developers can enjoy having access to aggregated liquidity from the entire Ethereum ecosystem.

<br>


# Modular Blockchain

zkLink Nova is designed with a modular architecture, allowing for various components or modules to be easily interchanged, upgraded, or added as needed. This modular approach provides flexibility and scalability by combining multiple specialized blockchains and technologies.

**The functions that modular blockchains can specialize in are:**

* **Sequencing:** Collect and order transactions.
* **Execution:** Process transactions.
* **Settlement:** Dispute resolution and bridge.
* **Data availability:** Ensure data is available.

**For more details, we recommend reading:**&#x20;

{% embed url="<https://celestia.org/learn/beginners/the-modular-stack/>" %}


# Token Merge

## Why is Token Merge Needed?

Nova’s vision is to aggregate and unify the fragmented liquidity across different Layer 2 rollups, while inheriting Ethereum’s security.&#x20;

Nova has successfully achieved asset aggregation. Native assets from all connected networks can be deposited onto the Nova network, where users can trade assets bridged from different networks with interoperability.&#x20;

In terms of liquidity unification, ETH deposited from different Layer 2s are automatically merged into the same ETH on Nova. However, one issue left here is that the same ERC-20 tokens bridged from different networks cannot be automatically merged without external information or setup, because the same ERC-20 tokens have different token contract addresses on different networks. USDC, for example, bridged from Ethereum and Arbitrum will be two different tokens, USDC.Ethereum and USDC.Arbitrum, and be of different addresses on Nova. This would be detrimental to the liquidity and user experience of using dApps on Nova.

To deal with this problem, we built a contract that could merge multiple **source tokens** of the same value into one same **merged token**. For example, source tokens like USDC.Ethereum, USDC.Arbitrum can be merged into the same USDC on Nova. The merged USDC is of the unified liquidity when being used on Nova.&#x20;

## How does it work?

By locking source tokens into the token merge contract, users will receive the equivalent amount of its merged tokens.&#x20;

By burning merged tokens, users can receive the equivalent amount of available source tokens they need from the token merge contract.

To streamline user experience, when users deposit from Nova’s host chains, they can choose to receive the merged tokens on Nova automatically. And when users withdraw to the host chains, merged tokens will be automatically unwrapped.

To mitigate risk, each source token has a **maximum amount limit** that can be merged. In addition, a source token can be **locked** by the governance bodies of token merge contract,  which suspends users to merge further.

Since Nova is expanding the networks it connects, and there will be new token assets emerging from the connected networks, the token merge contract is upgradable to meet new merge requirements. Any upgrade undergoes decentralized governance discussed below.

## Token Merge Governance

The governance structure is designed to facilitate the upgrade process for token merge contracts while ensuring security and accountability. It consists of two governance bodies: the **Governance Committee** and the **Security Council**.

<figure><img src="/files/nEcLDSf31oxgttLlVj1M" alt=""><figcaption></figcaption></figure>

### Governance Committee

The Governance Committee is responsible for initiating and voting on upgrade proposals related to token merge contracts. It is composed of a group of individuals who collectively control a smart contract that could upgrade token merge contracts with time-lock delay.

### Security Council

The Security Council serves as an added layer of oversight within the governance structure. Composed of a smaller group, the Security Council has the authority to reject any proposal that has been approved by the Governance Committee, and to immediately execute low risk upgrades.

### Proposal Initiation and Approval

Both for the case of the Governance Committee and Security Council,  any member can initiate a proposal for its governance body. For Governance Committee, any decision must receive approval from at least 2/3 of its members through the multi-signature safe wallet. For Security Council, voting threshold of safe wallet is 1/3.

### Execution Process

Any approved proposals made by the Governance Committee has a mandatory 7-day delay before they can be executed. This time-lock mechanism allows for review and mitigation of potential risks. The Security Council has the authority to reject a proposal before it’s executed.

Upgrade proposals may include:

* Upgrading the implementation of token merge contracts.
* Adding a merged token with a source token.
* Adding more source tokens for a merged token.
* Changing the maximum amount limit that a source token can be merged.
* Locking or unlocking a source token.
* Removing a source token for a merged token when its amount locked is zero.

Once the 7-day time-lock period expires for a delayed proposal, it can be executed by either the Governance Committee or the Security Council. The execution also needs at least 2/3 multi-signature approval.

### Immediate Execution

Certain types of low-risk upgrades can be  immediately executed by the Security Council without the 7-day time-lock delay. These include:

* Locking or unlocking a source token.
* Removing a source token for a merged token when its amount locked is zero.

## Contract Addresses

Merge Token Portal: [0x83FD59FD58C6A5E6eA449e5400D02803875e1104](https://explorer.zklink.io/address/0x83FD59FD58C6A5E6eA449e5400D02803875e1104)

Nova Tether USD: [0x2F8A25ac62179B31D62D7F80884AE57464699059](https://explorer.zklink.io/address/0x2F8A25ac62179B31D62D7F80884AE57464699059)

Nova Wrapped BTC: [0xDa4AaEd3A53962c83B35697Cd138cc6df43aF71f](https://explorer.zklink.io/address/0xDa4AaEd3A53962c83B35697Cd138cc6df43aF71f)

Nova USD Coin: [0x1a1A3b2ff016332e866787B311fcB63928464509](https://explorer.zklink.io/address/0x1a1A3b2ff016332e866787B311fcB63928464509)

Nova Dai Stablecoin: [0xF573fA04A73d5AC442F3DEa8741317fEaA3cDeab](https://explorer.zklink.io/address/0xF573fA04A73d5AC442F3DEa8741317fEaA3cDeab)


# Vision

Today, the process of interacting with dApps via browser or mobile wallets remains cumbersome, especially in the multi-chain world. The rise of Layer 2 solutions has brought cheap and fast dApp interactions, but it has also created a confusing experience for users who must navigate bridging, gas fees, and network switching across different blockchains.

To address these challenges, we are introducing an innovative design pattern and a toolkit that enables applications deployed on any Nova's connected blockchain to seamlessly onboard users from any promotion channel: Chain Abstraction.

Our solution abstracts away the complexity of blockchain technology from the user experience. Users won't even realize they are interacting with a blockchain, let alone which blockchain they are using.&#x20;

**Our vision is to bridge Web2 and Web3 seamlessly,** promoting the mass adoption of blockchain technology and the use of dApps in a multi-chain world. We aim to ensure the best user experience and capital efficiency while inheriting the robust security of Ethereum Mainnet, based on Nova's multi-chain aggregated ZK-Rollup technology.

## What can be achieved by Nova's Chain Abstraction

### For Developers

No matter which blockchain your DApp is currently deployed, we make it easy for you to onboard users from zkLink Nova with multi-chain aggregated liquidity. You don't need to redeploy your DApp on zkLink Nova network, but you can keep benefiting from the network effect on the blockchain where you already have great user base and deep liquidity.

We provide a toolkit that allows you to create **actions** that fulfill users' intent of achieving an outcome on any Nova's connected blockchain. An action could consist of multiple transactions on multiple blockchains, interacting with multiple DApps. The complexity of multi-chain transactions is abstract away from user experience, and users don't need to concern if there's enough funds for a transaction on one specific blockchain, as long as they have enough funds on any of our connected blockchains.

Through our toolkit, you could turn your actions into a customizable promotion link, which we call it **MagicLink**. Actions can be easily promoted on a variety of Web 2 social media platforms through  MagicLinks, and easily get approved by users.

### For Users

**Multi-chain Smart Account (SA)** is designed to facilitate users to interact with the DApps deployed on any connected blockchain networks. You could see your aggregated assets on multiple chains through a unified interface, and seamlessly use your crypto assets on one blockchain for the transaction on another blockchain, without need to concern where the assets locate.&#x20;

You can securely authorize your **device’s passkey** to approve actions for your smart account, so that you don't have to rely on a wallet app to sign transactions. You neither need to realize the complex transactions behind an action, nor which blockchain you'll use. All you need to do is to:

* Click the promotion link&#x20;
* Preview the action outcome and revise the input if needed
* Approve the action by your passkey

In this way, we make the user experience in Web3 as simple as in Web2, while still benefit from Web3's freedom and decentralization.&#x20;

### For Promoters

As a KOL, marketing agency, or project team member, you can customize the action you want to promote through an user interface (UI) and generate a **MagicLink** for your audience to execute the action. You can also set the referral rewards you can get from your referees.

The **MagicLink** can be shared on a variety of platforms, for example, Twitter, Telegram, Discord. You no longer need to take times to make tutorial for the users if they only care about the outcome. All they need to do is to click your link and approve.&#x20;

Your performance will be transparent to everyone, so that you can show the value you can create, helping you the seize more promotion opportunities working with your clients.<br>


# Implementation

## Coming soon <a href="#block-88c35468e87b488ba7260b5b6d4db033" id="block-88c35468e87b488ba7260b5b6d4db033"></a>


# Overview

zkLink modular stack provides unparalleled scalability for dApps building on top of our ecosystem. Each module of zkLink Nova can be upgraded independently, allowing us to have the capability to deliver the best performance by flexibly combining the best technologies.

The network can be decomposed into four layers:

* **Sequencing Layer:** Collect and order transactions.
* **Execution Layer:** Process transactions and update states.
* **Settlement Layer:** Finalize transactions on the base chains and execute fund withdrawal.&#x20;
* **Data availability(DA) Layer:** Ensure data is available.

It is worth to note that our innovative multi-chain settlement scheme makes us the first aggregated Layer 3 rollup network connecting to Ethereum and multiple Layer 2 rollup networks (L2s) with Ethereum equivalent security.

##


# Transaction Life Cycle

zkLink Nova network is an aggregated Layer 3 ZK-Rollup network built upon Ethereum(L1) and multiple Layer 2 rollup networks(L2s). Users are allowed to bridge native assets located on divided L2 rollup networks to zkLink Nova to benefit from aggregated liquidity. The system is designed to be super scalable and cost-efficient, while still maintaining Ethereum equivalent security.&#x20;

This section helps you navigate the full transaction life cycle on the zkLink Nova network, which helps you better understand how zkLink Nova works.

<figure><img src="/files/jt4TOHflF2bFn3jsgPxk" alt=""><figcaption></figcaption></figure>

## Transaction submission&#x20;

To interact with the dApps on zkLink Nova(L3), a user signs a transaction and submits it to the zkLink Nova sequencer, which provides fast confirmation and charges an extremely low fee.&#x20;

zkLink Nova also allows users to submit on-chain transactions (which is called priority operations) like fund deposits via the official smart contracts deployed on any connected network (L1 and L2s). Since the sequencer is forced to include the priority operations, zkLink Nova is of great censorship resistance.

## **Block building**&#x20;

The sequencer of zkLink Nova is a collection of services and functions acting in coordination to monitor connected networks (L1 and L2s), order incoming transactions, maintain zkLink Nova network (L3) state, and execute blocks. For each transaction, the sequencer checks its validity, rejecting transactions as necessary. Valid transactions are placed into small blocks every 2 seconds and executed in the zkEVM of ZK Stack. With the transaction executed and state updated, the transaction has reached soft finality.&#x20;

## Generating a ZK-proof <a href="#step-5-generating-a-zk-proof-using-transaction-data" id="step-5-generating-a-zk-proof-using-transaction-data"></a>

In order to spread the cost of interacting with settlement layers, transactions in multiple blocks will be packed into a batch, which serve as the fundamental unit for generating proofs and on-chain settlement. The prover will prove the correct execution of zkEVM by producing a zero-knowledge proof that verifies and validates the transactions in a batch, proving that user transactions were computed correctly and the new state is correct.

## Prove verification

After the prover verifies the correctness of state updates, the zero-knowledge proof will be submitted to the rollup contract on a primary chain (L2, currently Linea is designated as the primary chain). The sequencer also needs to submit data commitment (including compressed transaction data and state root) to the primary chain for proof verification. Based on the ZK-proof and data commitment, the rollup contract on the primary chain could execute ZKP verification.

## Multi-chain Settlement

After completing ZKP verification, it comes to synchronize stage to achieve state synchronization across the connected networks. To prevent the security risk that a bad sequencer may falsely inform the primary chain about fake on-chain transactions, sync hashes of on-chain transaction data will be forwarded to the primary chain via Ethereum canonical rollup bridges, and the contract on the primary chain will check if they're consistent with the on-chain transactions previously relayed by the sequencer.

Upon the successful verification of both zero-knowledge proof and multi-chain transaction consistency, the confirmation information is relayed back to other connected networks. Thereafter, on-chain settlement across all networks is finalized and fund withdrawal requests could be approved.


# Sequencing Layer

The sequencing layer is primarily responsible for monitoring on-chain deposits, maintaining L3 state, sequencing transactions and bundling transactions into blocks and batches.

zkLink Nova provides RPC services for users to interact with the network by sending transactions directly to the zkLink Nova sequencer. zkLink Nova also has a operator module responsible for monitoring the on-chain transactions (i.e. priority operations) on the base layers (i.e. Ethereum and connected Layer 2 rollups), and [relaying priority operations to the sequencer](/architecture/settlement-layer/in-detail-multi-chain-state-synchronization#on-chain-transaction-synchronization) .

The zkLink Nova sequencer takes a list of incoming transactions, making sure each transaction fits within the constraints required by the proving system, and rejecting transactions as necessary. Valid transactions are placed into small blocks every 2 seconds and executed in the zkEVM of ZK Stack. In order to spread the cost of interacting with settlement layers, transactions in multiple blocks will be packed into a batch, which serve as the fundamental unit for generating proofs and on-chain settlement.

Similar to most rollups, zkLink Nova starts with a centralized sequencer model. While this approach offers certain development efficiencies, it also presents challenges and risks, such as potential single point of failure, transaction censorship and issues around miner extractable value (MEV), affecting network fairness and transparency.

To address these concerns, zkLink Nova aims to incorporate decentralized sequencer solutions. These solutions, including platforms like Espresso, Astria, and Fairblock, aim to mitigate centralization risks by processing and validating transactions across a distributed node network. This strategy will not only boost network security and transparency but also strive to offer a more secure, fair, and efficient rollup solution to its users.

<br>


# Execution Layer

The execution layer entails executing transactions that update the state correctly.&#x20;

zkLink Nova utilizes zkEVM (zero-knowledge Ethereum Virtual Machine) of [ZK Stack](https://zkstack.io/) to execute smart contracts and proves the correctness of execution using zero-knowledge. Like the EVM, a zkEVM transitions between states after computation is performed on transactions. The difference is that the zkEVM also creates zero-knowledge proofs to verify the correctness of every step in the program’s execution.

zkEVM allows zkLink Nova to be compatible with existing Ethereum infrastructure. Nova provides an easy way for builders to fork various applications that are already deployed on Ethereum and Layer 2 rollups, thereby laying the foundations for a faster-growing ecosystem.&#x20;


# Settlement Layer

The settlement layer entails an environment for finalizing transactions on the base chain(s).&#x20;

A classic ZK-Rollup network typically selects Ethereum as the base chain to verify proof and settle transactions. By contrast, zkLink Nova has the capability to securely aggregate liquidity and native assets across Ethereum and its L2s by allowing users to deposit funds from connected networks. To achieve that, we apply a new settlement paradigm (i.e. zkLink Nexus) to be able to settle on multiple Ethereum Layer 2 rollup networks.

In the architecture of an aggregated ZK-Rollup, on-chain transactions such as deposit will be relayed to the rollup network in real-time to deliver the best user experience. However, the hard finality of every transaction is achieved by multi-chain settlement, which depends on the result of ZKP verification and multi-chain state synchronization.

<figure><img src="/files/vLVhjS1mTAmWdOnBUu8c" alt=""><figcaption></figcaption></figure>

In order to optimize the on-chain verification cost, one Layer 2 network is designated as the **primary chain**, which is responsible for ZKP verification and checking on-chain transaction consistency. Currently, Linea is chosen to serve as the primary chain since it has the capability to execute zk-SNARKs proofs and has fast settlement finality on Ethereum Mainnet.

While the other chains will act as **secondary chains** that do not need to execute ZKP verification, through multi-chain state synchronization via canonical rollup bridges, it is equivalent to completing the verification on all chains.

The settlement process includes:

1. **Commit:** The sequencer submits the zk-proof and transaction batch to the verifier contract on the primary chain.
2. **Prove verification:** The zkLink contract checks the validity of the zk-proof.
3. **Synchronization:** The transaction sync hashes of secondary chains are forwarded to the primary chain via canonical rollup message bridges. The primary chain verifies if sync hashes are consistent with the on-chain transactions previously relayed by the sequencer. Upon the verification of ZKP and on-chain transaction consistency, transaction batch can be finalized and the batch root will be sent to secondary chains.
4. **Execution:** Upon successfully finalizing a batch of transactions and state change, each chain could proceed users' requests for fund withdrawals. &#x20;


# In-Detail: Multi-Chain State Synchronization

## Overview

zkLink Nova is powered by zkLink Nexus technology for multi-chain settlement. In zkLink's Nexus, users can deposit and withdraw assets on all connected networks (L1 and L2s). Users' assets are locked in smart contracts on the connected networks and enter the Nova network via the canonical rollup bridge. Nexus boasts Ethereum-grade security, achieved through multi-chain state synchronization by transmitting the sync hashes of on-chain transactions via the canonical roll-up message service.

The connected networks (L1 and L2s) of Nova can be classified into two types serving different roles:

* **Primary Chain**: ZK-proofs and data commitments for transaction batches on Nova (L3) are submitted to the primary chain (Linea, L2). The primary chain is responsible for ZKP verification and checking on-chain data consistency by sync hashes.
* **Secondary Chain**: Secondary chains send sync hashes to the primary chain via the canonical roll-up message service. Upon successful verification on the primary chain, the confirmed batch root is relayed back to secondary chains, and withdrawal requests on secondary chains can be executed.

{% hint style="info" %}
Among the secondary chains, **Ethereum (L1)** holds a special position. Message transmission between the primary chain and other L2 secondary chains occurs via Ethereum, where the arbitrator contract facilitates the forwarding of cross-chain messages."
{% endhint %}

## On-Chain Transaction Synchronization

A user could deposit token assets by initiating an on-chain transaction. Additionally, users can submit other types of on-chain transactions via the connected networks, which the sequencer is force to process.

<figure><img src="/files/iAkPuDC1WBDBX7qlZ1sP" alt=""><figcaption></figcaption></figure>

As shown in the figure above, if a user sends a transaction (e.g., depositing ETH) to the zkLink contract on a secondary chain (step 1), the transaction will be forwarded in real-time by the Nova sequencer to the zkLink contract on the primary chain (step 2). A user can also send a transaction directly to the zkLink contract on the primary chain (step 3). The sequencer monitors the transactions received in the zkLink contract on the primary chain and forwards these transactions (in step 4) to the Nova network (L3) for execution.

{% hint style="info" %}
Please note that only the sequencer is authorized to relay transactions from the secondary chains to the primary chain. To achieve low-latency synchronization, this process does not rely on a canonical rollup bridge. However, we have a mechanism in place to prevent the sequencer from sending fake information, which will be discussed in a later part of this article."

Step 2:  &#x20;

<https://github.com/zkLinkProtocol/era-contracts/blob/zklink_testnet/l1-contracts/contracts/zksync/facets/Mailbox.sol>

function forwardRequestL2Transaction( ForwardL2Request calldata \_request )
{% endhint %}

&#x20;

## Multi-Chain State Synchronization

The main challenge of building a rollup network deployed across various networks is the risk of **deposit fraud.** For example, a bad sequencer may falsely inform the primary chain about a fake deposit on one secondary chain that does not exist. In such scenarios, without effective verification mechanisms, it could lead to the loss of user funds.

To prevent this risk, in the state synchronization phase, we add another layer of **transaction consistency verification** in addition to **ZKP verification** in a typical ZK-Rollup. This additional layer ensures that the data relayed to the primary chain in real-time is consistent with the sync hashes periodically transmitted via the canonical rollup message service.

For each transaction on a secondary chain, the zkLink contract will calculate the sync hash of this transaction based on the previous sync hash.

$$
syncHash\_{n} = hash(tx, syncHash\_{n-1})
$$

<figure><img src="/files/WeOMUoukK2chmJFdo7hw" alt=""><figcaption></figcaption></figure>

A relayer will periodically trigger secondary chains to send the latest sync hash to the arbitrator contract on Ethereum via the canonical message service (in steps 1, 2, 3), and the arbitrator contract will forward all sync hashes of secondary chains to the zkLink Contract via the canonical message service (in steps 4, 5, 6).

{% hint style="info" %}
Step 1: Trigger the zkLink contract on secondary chains to send the latest sync hash to the L2 Gateway.&#x20;

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/ZkLink.sol>

function syncL2Requests(uint256 \_newTotalSyncedPriorityTxs)
{% endhint %}

{% hint style="info" %}
Step 2: Transmitting message (sync hash) via canonical rollup bridge.
{% endhint %}

{% hint style="info" %}
Step 3: Receive message (sync hash) from canonical message service and forward it to the arbitrator contract. For example:

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/gateway/zksync/ZkSyncL1Gateway.sol>

function finalizeMessage( uint256 \_l2BatchNumber, uint256 \_l2MessageIndex, uint16 \_l2TxNumberInBatch, bytes memory \_message, bytes32\[] calldata \_merkleProof )&#x20;
{% endhint %}

{% hint style="info" %}
Step 4: Forward message (sync hash) from the arbitrator contract to the L1 gateway of primary chain.

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/Arbitrator.sol>

function forwardMessage( IL1Gateway \_gateway, uint256 \_value, bytes memory \_callData, bytes memory \_adapterParams )&#x20;
{% endhint %}

{% hint style="info" %}
Step 5: Transmitting message (sync hash) via canonical rollup bridge.
{% endhint %}

{% hint style="info" %}
Step 6.1: Receive message (sync hash) from canonical message service of the primary chain and forward it to the zkLink contract on the primary chain.&#x20;

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/gateway/linea/LineaL2Gateway.sol>

function claimMessageCallback( uint256 \_value, bytes calldata \_callData )
{% endhint %}

{% hint style="info" %}
Step 6.2: Once the primary chain receives the sync hash from secondary chains, zkLink contract will verify if it's consistent with the transactions that were previously relayed by the sequencer to the primary chain.&#x20;

<https://github.com/zkLinkProtocol/era-contracts/blob/zklink_testnet/l1-contracts/contracts/zksync/facets/Mailbox.sol>

function syncL2Requests( address \_secondaryChainGateway, uint256 \_newTotalSyncedPriorityTxs, bytes32 \_syncHash, uint256 \_forwardEthAmount )
{% endhint %}

{% hint style="info" %}
Step 7: After the zkLink contract on the primary chain executes ZKP verification for a transaction batch, it checks if all the on-chain transactions in that batch have already been verified based on sync hashes.

<https://github.com/zkLinkProtocol/era-contracts/blob/zklink_testnet/l1-contracts/contracts/zksync/facets/Executor.sol>

function \_collectOperationsFromPriorityQueue(uint256 \_nPriorityOps)
{% endhint %}

> Upon successful verification of ZKP and on-chain transaction consistency, settlement on the primary chain can be approved. At this stage, Nova achieves soft finalization on the primary chain (Linea). Afterward, the batch root will be sent to all secondary chains via the canonical message service (in steps 8-13).

{% hint style="info" %}
Step 8: Trigger the zkLink contract on the primary chain to send the batch root to the gateway.

<https://github.com/zkLinkProtocol/era-contracts/blob/zklink_testnet/l1-contracts/contracts/zksync/facets/Mailbox.sol>

function syncBatchRoot(address \_secondaryChainGateway, uint256 \_batchNumber, uint256 \_forwardEthAmount)
{% endhint %}

{% hint style="info" %}
Step 9: Transmitting message (batch root) via canonical message bridge. Once the message reaches Ethereum, zkLink Nova achieved **hard finalization.**
{% endhint %}

{% hint style="info" %}
Step 10:  Receive message (batch root) from canonical message service and forward it to the arbitrator contract. &#x20;

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/Arbitrator.sol>

function receiveMessage(uint256 \_value, bytes memory \_callData)
{% endhint %}

{% hint style="info" %}
Step 11: Forward message (batch root) from the arbitrator contract to the L1 gateway of secondary chains.&#x20;

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/Arbitrator.sol>

function forwardMessage( IL1Gateway \_gateway, uint256 \_value, bytes memory \_callData, bytes memory \_adapterParams )&#x20;
{% endhint %}

{% hint style="info" %}
Step 12: Transmitting message (batch root) via canonical rollup bridge.
{% endhint %}

{% hint style="info" %}
Step 13:  Receive message from canonical message service of the secondary chain and forward it to the zkLink contract. For example:

<https://github.com/zkLinkProtocol/zklink-evm-contracts/blob/main/contracts/gateway/zksync/ZkSyncL2Gateway.sol>

function claimMessageCallback(uint256 \_value, bytes memory \_callData)
{% endhint %}

After receiving the batch root, withdrawal requests can be executed in the zkLink contract on the secondary chains.

For further detailed information, please refer to our verified [smart contracts](/developer/useful-addresses).

## Bridged Assets Location

**ETH:**

zkLink Nova applies zkLink Nexus technology, which allows users to deposit ETH from and withdraw ETH to any connected network powered by fund auto-rebalancing. ETH will be transferred from and to any connected chains along with deposit and withdraw transactions via Layer 2s' canonically rollup bridges.&#x20;

When users deposits ETH from a secondary Chain onto Nova, it will be temporally locked in the zkLink contract on the source chain. In the [state synchronization process](#multi-chain-state-synchronization) discussed above (step 1-5), along with sync hash, the ETH will be transferred to the primary chain, and finally locked in the zkLink contract on primary chain.

When users withdraw from Nova to a secondary chain, after the batch including the withdrawal transaction has been verified through ZKP and the all the on-chain transactions in that batch have already been verified based on sync hashes (step 6-7), the ETH to be withdrawn will be transferred to the secondary chain along with batch root (step 8-13).

**ERC-20 Tokens:**

As ERC-20 tokens may only exist on a Layer 2 network, which is not bridgeable back to Ethereum via rollup bridge, to make it consistent, an ERC-20 token will be locked in the ERC-20 bridge on the chain where it comes from (see the figure below).

<figure><img src="/files/TEMXpWk6wH7mfnVY2hHl" alt=""><figcaption></figcaption></figure>

## Withdrawal Time Discussion

As discussed [above](#on-chain-transaction-synchronization), to prevent deposit fraud problem, all on-chain transactions prior to a withdrawal request have to be verified via sync hash consistency check. As zkLink Nova connects to Optimistic rollups like Optimism and Arbitrum, it takes around 7 days to forward transaction hashes to the primary chain via canonical rollup bridge to finish the verification. After transaction hash verification and ZKP verification, withdrawal request to the primary chain Linea can be executed. Therefore, withdrawal to Linea takes around 7 days.

For withdrawal requests to a secondary chain, the transaction should be transmitted from Linea to the secondary chain via Ethereum, which could take around additional 1 day. Therefore, it takes around 8 days to finish the execution of a withdrawal transaction to a secondary chain.&#x20;


# In-Detail: Contract System on Primary Chain

<figure><img src="/files/AQ2JCfXpU2SGturlySg4" alt=""><figcaption></figcaption></figure>

In order to create a modular smart contract system that can be extended after deployment, Nova applies a **diamond proxy contract** ([EIP-2535](https://eips.ethereum.org/EIPS/eip-2535))  with functions called facets, which include:

* **zkLink admin facet** that provides the interface for managing gas fee, adding new secondary chains, etc.
* **zkLink mail box facet** that provides the interface for on-chain transactions like deposit and withdraw.
* **zkLink executor facet** that provides the interface to commit, prove and execute batches.&#x20;
* **zkLink getters facet** that provides the interface to read the state of Nova network.

In the stage of proving a batch's validity,  the **verifier contract** will be called by the **executor facet** of the **diamond proxy contract** to validate ZKP.

**Governance contract** is the owner of the **diamond proxy contract**, which is able to upgrade facets in the proxy contract.

**Validator Timelock** controls the operations including committing, proving and executing batches.&#x20;

**L1ERC20Bridge** uses the requestL2Transaction interface of Diamond Proxy to send the ERC20 bridge message to Nova network.

**Linea2Gateway** is in charge of transmitting massage between Linea and Ethereum.


# DA Layer

The DA Layer entails making the transaction and state data available.&#x20;

Nova chooses the **Validium mode** for storing data. Under classic Rollup mode, the majority of Ethereum gas costs go to Data Availability, and not proof verification. This is because it is very gas-intensive to store data on Ethereum. In Validium mode, Nova's data is stored off-chain with a Data Availability Committee (DAC). This Data Availability Committee oversees the correct state update as well as keep a copy of the data that was processed.

In the very near future, Nova will integrate with external DA solutions, for example, Celestia, EigenDA, Avail, etc., so that data will be stored in a more decentralized approach with censorship resistence.

&#x20;&#x20;


# Keep Evolving

zkLink Nova officially launched its Mainnet Alpha in March 11, 2024. Alpha represents the MVP of zkLink Nova–a zkEVM-based aggregated L3 built upon Ethereum and multiple L2 rollup networks. At the same time, Alpha represents only the first of many milestones to be achieved. Alongside zkSync, Celestia and potential decentralized sequencing partners, we are excited to unveil the next chapters for the zkLink Nova journey, one that will result on an aggregated layer of Ethereum L2 ecosystem with unlimited scalability, Ethereum equivalent security, EVM-compatibility, low transaction cost, and decentralization.&#x20;

### **Chapter 1:** zkLink Nova **Alpha (Aggregated L3 Rollup)**[​](https://docs.manta.network/docs/concepts/Roadmap#chapter-1-manta-pacific-alpha-ethereum-l2) <a href="#chapter-1-manta-pacific-alpha-ethereum-l2" id="chapter-1-manta-pacific-alpha-ethereum-l2"></a>

In its current availability, zkLink Nova is an aggregated Layer 3 ZK-Rollup applying Validium mode with a DAC. It leverages the zkEVM of ZK Stack for developers to quickly build, test, and deploy applications with solidity. All existing smart contracts on Ethereum can be seamlessly adopted to zkLink Nova. Based on the multi-chain settlement solution of zkLink Nexus, users can securely depositing their assets from Ethereum and multiple connected Layer 2 rollups without taking any trusted bridge risk. The dApps on zkLink Nova would enjoy aggregated liquidity of assets scattered on different Layer 2 rollup networks.

### **Chapter 2:** zkLink Nova **Alpha II (+External DA)**[​](https://docs.manta.network/docs/concepts/Roadmap#chapter-2-manta-pacific-alpha-ii-celestia-da) <a href="#chapter-2-manta-pacific-alpha-ii-celestia-da" id="chapter-2-manta-pacific-alpha-ii-celestia-da"></a>

In the next chapter, zkLink Nova will achieve data scaling by integrating external modular DA that ensures data accessibility with censorship consistence. In the current Validium mode, Nova's data is stored off-chain with a Data Availability Committee (DAC), which oversees the correct state update as well as keep a copy of the data that was processed. In the very near future, Nova will integrate with external DA solutions, for example, Celestia, EigenDA, Avail, etc., so that data will be stored and accessible with censorship consistence.  By cooperating with DA partners, Nova could cost super low gas fees and facilitate the mass adoption of our network.

### **Chapter 3:** zkLink Nova **Beta (+ Chain Abstraction)**[​](https://docs.manta.network/docs/concepts/Roadmap#chapter-2-manta-pacific-alpha-ii-celestia-da) <a href="#chapter-2-manta-pacific-alpha-ii-celestia-da" id="chapter-2-manta-pacific-alpha-ii-celestia-da"></a>

Today, the process of interacting with dApps via browser or mobile wallets remains cumbersome, especially in the multi-chain world, in which users who must navigate bridging, gas fees, and network switching across different chains. To address these challenges, we will provide a toolkit that enables applications deployed on any Nova's connected chain to seamlessly onboard users from any promotion channel: Chain Abstraction. Our solution abstracts away the complexity of blockchain technology from the user experience. Users won't even realize they are interacting with a blockchain, let alone which blockchain they are using.

### **Chapter 4:** zkLink Nova **Mainnet Production (+Fully Decentralized)**[​](https://docs.manta.network/docs/concepts/Roadmap#chapter-3-manta-pacific-beta-transition-to-zkevm) <a href="#chapter-3-manta-pacific-beta-transition-to-zkevm" id="chapter-3-manta-pacific-beta-transition-to-zkevm"></a>

Similar to other zk-rollups, zkLink Nova starts with a centralized sequencer and prover model for development efficiencies. In order to mitigate the risk of potential single-point failure and to enhance the transparency and fairness of the network, zkLink Nova aims to incorporate decentralized sequencer and prover solutions. In this stage, transactions will be processed and validated across a distributed node network. ZKL (the native token of zkLink) will be used to incentivize validators to collectively secure the network.

## **Looking Forward to the Future of** zkLink Nova

Upon completion of Chapter 3, zkLink Nova will become a fully decentralized network reunifying the fragmented liquidity scattered in different Ethereum ecosystems, with unlimited scalability and Ethereum equivalent security. Meanwhile, as zkLink Nova’s modular architecture continues to evolve, users will find notable improvements in their day-to-day interactions with zkLink Nova ecosystem applications.


# Quick Start

zkLink Nova is EVM compatible. All the contracts and tools that work on Ethereum and L2s also work here, and you can easily fork and re-use functionality others have already built.&#x20;

This guide shows you how to deploy and interact with a smart contract on zkLink Nova Sepolia Testnet in less than 5 minutes.&#x20;

{% hint style="info" %}
The execution layer of zkLink Nova is built on top of [ZK Stack](https://docs.zksync.io/zk-stack), which leverages the underlying technology of zkSync. **Building on zkLink Nova shares the same process of building on zkSync.** We recommend you to refer to the [documentation of zkSync](https://docs.zksync.io/build/) for more detailed information:
{% endhint %}

This is what we're going to do:

* Fund your wallet with Sepolia Testnet ETH.
* Use [zksync-cli](https://docs.zksync.io/build/tooling/zksync-cli/getting-started.html) to scaffold a new project.
* Build a smart contract that stores a greeting message and deploy it to zkLink Nova testnet.
* Run a script to retrieve and update the greeting message using [zksync-ethers](https://docs.zksync.io/build/sdks/js/getting-started.html).

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#prerequisites)Prerequisites <a href="#prerequisites" id="prerequisites"></a>

* Make sure your machine satisfies the [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements).
* Download and install [Node.js](https://nodejs.org/en/download).
* Use the `yarn` or `npm` package manager. We recommend using `yarn`. To install `yarn`, follow the [Yarn installation guide](https://yarnpkg.com/getting-started/install).
* Learn how to [get your private key from your Metamask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key) as we'll use it to deploy a contract.

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#fund-your-wallet)Fund your wallet <a href="#fund-your-wallet" id="fund-your-wallet"></a>

You can get Sepolia ETH from any of the following faucets and bridge it to zkLink Nova Testnet using the [zkLink Nova Bridge](https://sepolia.portal.zklink.io).

* <https://www.alchemy.com/faucets/ethereum-sepolia>
* <https://faucet.quicknode.com/ethereum/sepolia>
* <https://www.infura.io/faucet/sepolia/>
* <https://learnweb3.io/faucets/sepolia/>

You can check the balance of your account in the [zkLink Sepolia Explorer](https://sepolia.explorer.zklink.io).

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#create-the-project)Create the project <a href="#create-the-project" id="create-the-project"></a>

{% hint style="info" %}
**Project available in Atlas IDE**

This entire tutorial can be run in under a minute using Atlas. Atlas is a smart contract IDE that lets you write, deploy, and interact with contracts from your browser.

[Open this project in Atlas](https://app.atlaszk.com/projects?template=https://github.com/matter-labs/zksync-hardhat-template\&open=Greeter.sol\&chainId=300).
{% endhint %}

Run the following command in your terminal to create a new project using zkSync CLI.

```
npx zksync-cli create hello-zksync
```

It will give you options for different types of projects but for this tutorial choose the the following:

```
? What type of project do you want to create? Contracts
? Template: Hardhat + Solidity
? Private key of the wallet responsible for deploying contracts (optional) ***************************************************
? Package manager: yarn
```

The project structure is pretty straight forward:

* `hardhat.config.ts` contains the general configuration for Hardhat and the zkSync plugins, which are already imported and setup.
* `/contracts` contains smart contracts. `zksync-cli` provides common examples like an ERC20, an NFT, and the Greeter contract that we'll use later on.
* `/deploy` contains the deployment scripts.

For this tutorial we'll focus on the `/contracts/Greeter.sol` contract:

```
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }
}
```

As you can see, it a simple Solidity contract with two methods to read a message, `greet()`, and modify it, `setGreeting()`.

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#compile-the-contract)Compile the contract <a href="#compile-the-contract" id="compile-the-contract"></a>

Smart contracts deployed to zkLink Nova must be compiled using our custom compilers:

* `zksolc` for Solidity contracts.
* `zkvyper` for Vyper contracts.

As this is a Solidity project, it already has the `hardhat-zksync-solc` plugin installed and configured so there's nothing you need to setup. To compile the contracts in the project, run the following command:

yarn:

```
yarn compile
```

npm:

```
npm run compile
```

You'll get the following output:

```
Compiling contracts for zkSync Era with zksolc v1.3.21 and solc v0.8.17
Compiling 46 Solidity files
Successfully compiled 46 Solidity files
✨  Done in 21.55s.
```

The compiled artifacts will be located in the `/artifacts-zk` folder. These artifacts are similar to the ones generated by the Solidity compiler. For example, the ABI of the Greeter contract will be located in `/artifacts-zk/contracts/Greeter.sol/Greeter.json`.

The configuration for the `zksolc` compiler is located in the `zksolc` section of the `hardhat.config.ts` file. You can find more info about the compiler settings in the [hardhat-zksync-solc plugin](https://docs.zksync.io/build/tooling/hardhat/hardhat-zksync-solc.html) and the [compiler section](https://docs.zksync.io/zk-stack/components/compiler/specification/overview.html) of the ZK Stack documentation.

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#deploy-and-verify)Deploy and verify <a href="#deploy-and-verify" id="deploy-and-verify"></a>

The project also contains a script to deploy and verify the contract in `/deploy/deploy.ts`. Under the hood, this script uses `hardhat-zksync-deploy` and `hardhat-zksync-verify` for deployment and contract verification.

```
import { deployContract } from "./utils";

// An example of a basic deploy script
// It will deploy a Greeter contract to selected network
// as well as verify it on Block Explorer if possible for the network
export default async function () {
  const contractArtifactName = "Greeter";
  const constructorArguments = ["Hi there!"];
  await deployContract(contractArtifactName, constructorArguments);
}
```

To execute it, just run:

yarn:

```
yarn deploy
```

npm:

```
npm run deploy
```

You'll get the following output:

```
Starting deployment process of "Greeter"...
Estimated deployment cost: 0.0000648863 ETH

"Greeter" was successfully deployed:
 - Contract address: 0x0BaF96A7f137B05d0D35b76d59B16c86C1791D8D
 - Contract source: contracts/Greeter.sol:Greeter
 - Encoded constructor arguments: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000

Requesting contract verification...
Your verification ID is: 1781
```

Congratulations! You just deployed a smart contract to zkLink Nova testnet. You can find it in the  [zkLink Sepolia Explorer ](https://sepolia.explorer.zklink.io)by searching the contract address.

In addition, the deployment script verified the contract automatically so you can see the source code in the contract tab of the block explorer.

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#interact-with-the-contract)Interact with the contract <a href="#interact-with-the-contract" id="interact-with-the-contract"></a>

The project also comes with a script to interact with the contract in `/deploy/interact.ts`. Add the address of the Greeter contract you just deployed in the `CONTRACT_ADDRESS` variable inside the `/deploy/interact.ts` file:

```
import * as hre from "hardhat";
import { getWallet } from "./utils";
import { ethers } from "ethers";

// Address of the contract to interact with
const CONTRACT_ADDRESS = "";
if (!CONTRACT_ADDRESS) throw "⛔️ Provide address of the contract to interact with!";

// An example of a script to interact with the contract
export default async function () {
  console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`);

  // Load compiled contract info
  const contractArtifact = await hre.artifacts.readArtifact("Greeter");

  // Initialize contract instance for interaction
  const contract = new ethers.Contract(
    CONTRACT_ADDRESS,
    contractArtifact.abi,
    getWallet() // Interact with the contract on behalf of this wallet
  );

  // Run contract read function
  const response = await contract.greet();
  console.log(`Current message is: ${response}`);

  // Run contract write function
  const transaction = await contract.setGreeting("Hello people!");
  console.log(`Transaction hash of setting new message: ${transaction.hash}`);

  // Wait until transaction is processed
  await transaction.wait();

  // Read message after transaction
  console.log(`The message now is: ${await contract.greet()}`);
}
```

As you can see, we're simply using `ethers` to interact with our contract. zkSync is EVM compatible so you can use existing tools and libraries like `Hardhat`, `ethers`, `web3.js`, and users can use their existing wallets like Metamask, Rabby or Zerion.

To execute the `/deploy/interact.ts` script, run:

yarn:

```
yarn interact
```

npm:

```
npm run interact
```

You'll get the following output:

```
Running script to interact with contract 0x0BaF96A7f137B05d0D35b76d59B16c86C1791D8D
Current message is: Hi there!
Transaction hash of setting new message: 0x7a534857cfcd6df7e3eaf40a79a2c88f2e36bb60ce6f2399345e5431362b04eb
The message now is: Hello people!
✨  Done in 4.13s.
```

Congratulations! You've retrieved and updated the message on the `Greeter` contract. You can see the transaction in the [block explorer](https://sepolia.explorer.zklink.io) by searching the transaction hash.

### [#](https://docs.zksync.io/build/quick-start/hello-world.html#takeaways)Takeaways <a href="#takeaways" id="takeaways"></a>

* zkLink Nova is EVM compatible and you can write smart contracts in Solidity or Vyper, use Hardhat, libraries like Ethers and Web3.js, or wallets like Metamask and Rabby.
* zkLink Nova is built on top of [ZK Stack](https://docs.zksync.io/zk-stack), which leverages the underlying technology of zkSync. You could use the toolkit of zkSync to build your project.
* zkSync CLI provides a quick way to scaffold different types of projects thanks to its multiple templates.
* Contracts deployed to zkLink Nova are compiled using `zksolc` or `zkvyper` as they generate a special bytecode for zkSync's ZKEVM.
* For more detailed information, you can refer to the [documentation of zkSync](https://docs.zksync.io/build/)&#x20;


# Contract Verification

## User Interface

You can verify your smart contract at the Smart Contract Verification page.

Mainnet:<https://explorer.zklink.io/contracts/verify>

Testnet: <https://sepolia.explorer.zklink.io/contracts/verify>

## Hardhat plugin <a href="#hardhat-plugin" id="hardhat-plugin"></a>

You can also verify your smart contract using the [Hardhat plugin](https://docs.zksync.io/build/tooling/hardhat/hardhat-zksync-verify.html) provided by zkSync. Please use the below URLs for configuration:

Mainnet: <https://explorer.zklink.io/contract_verification>

Testnet: <https://sepolia.explorer.zklink.io/contract_verification><br>

{% hint style="info" %}
Please note the current backend verification system **only** support the following compilers:

zksolc: v1.3.0 \~ v1.3.22

solc:  <= v0.8.22
{% endhint %}


# Migrating Your Project to Nova

The execution layer of zkLink Nova is built on top of [ZK Stack](https://docs.zksync.io/zk-stack), which leverages the underlying technology of zkSync. Building on zkLink Nova shares the same process of building on zkSync.&#x20;

zkSync provides developers with a smooth experience, offering tools for testing locally and compatibility with existing frameworks like Hardhat and Foundry. You can find the user guide for using these tools here.

[Hardhat with zkSync](https://docs.zksync.io/build/tooling/hardhat/getting-started.html)

[Foundry with zkSync](https://docs.zksync.io/build/tooling/foundry/overview.html)

For deploying smart contracts or using unique zkSync features, please use  `zksync-ethers` SDKs. zkSync provides SDKs for different programming languages. Please refer to the user guides in below.

[SDKs-JavaScript Ethers V5](https://docs.zksync.io/build/sdks/js/getting-started.html)

[SDKs-JavaScript Ethers V6](https://docs.zksync.io/build/sdks/js/zksync-ethers/getting-started.html)

[SDKs-Python](https://docs.zksync.io/build/sdks/python/getting-started.html)

[SDKs-Go](https://docs.zksync.io/build/sdks/go/getting-started.html)

[SDKs-Java](https://docs.zksync.io/build/sdks/java/getting-started.html)

[SDKs-Swift](https://docs.zksync.io/build/sdks/swift/getting-started.html)

[SDKs-Rust](https://docs.zksync.io/build/sdks/rust/getting-started.html)


# EVM Compatibility

zkLink Nova achieves EVM compatiblity by leveraging the technology of ZK Stack, a modular, open-source framework based on the code of zkSync Era.&#x20;

According to Vitalik Buterin, EVM compatibility can be segmented into four types. The zkEVM of ZK Stack is categorized as a Type 4 system in the taxonomy of zkEVMs. Its EVM compatibility works by taking smart contract source code written in high-level languages and compiling it to a language designed to be zk-SNARK-friendly.&#x20;

ZK Stack supports smart contracts written in Solidity or Vyper. It uses custom compilers, namely zksolc for Solidity and zkvyper for Vyper, which ensure compatibility and efficient execution of smart contracts. More importantly, zkSync provides developers with a smooth experience, offering tools for testing locally and compatibility with existing frameworks like Hardhat and Foundry.

As a Type 4 system, ZK Stack prioritizes performance by bypassing the need to Zero-Knowledge prove every aspect of EVM execution. Instead, it starts directly from higher-level code. This approach leads to more incompatibility compared to systems that closely replicate the EVM. For instance, contracts may not have the same addresses as they do in the EVM, and handwritten EVM bytecode is more difficult to use.

To sum this up, zkLink Nova based on ZK Stack (zkSync Era) is **EVM compatible**, meaning it supports a significant portion of Ethereum's EVM opcodes, allowing most smart contracts to work seamlessly. However, it's not **EVM equivalent**, as it doesn't support every opcode down to the bytecode level.&#x20;

You can find the differences from Ethereum from the documentation of ZK Stack.

{% embed url="<https://docs.zksync.io/build/developer-reference/differences-with-ethereum.html>" %}

{% hint style="info" %}
Please note some EVM cryptographic precompiles (notably pairings and RSA) aren't currently available.

Ethereum cryptographic primitives like `ecrecover`, `keccak256`, `sha256`, `ecadd` and `ecmul` are supported as precompiles.&#x20;
{% endhint %}


# Useful Addresses

## Mainnet Addresses

### ZKL Token Addresses

Ethereum: [0xfC385A1dF85660a7e041423DB512f779070FCede](https://etherscan.io/address/0xfC385A1dF85660a7e041423DB512f779070FCede)

zkLink Nova: [0xC967dabf591B1f4B86CFc74996EAD065867aF19E](https://explorer.zklink.io/address/0xC967dabf591B1f4B86CFc74996EAD065867aF19E)

### zkLink Nova Contract Addresses

{% hint style="info" %}
The addresses below are listed by the network where a contract is deployed. Linea is designated as the primary chain used for verifying ZKP and checking on-chain transaction consistency.
{% endhint %}

<details>

<summary><strong>zkLink Nova Mainnet (L3, zkLink Nova network)</strong> </summary>

ERC-20 Bridges:

&#x20;    Linea Mainnet: 0x01c3f51294494e350AD69B999Db6B382b3B510b9

&#x20;    Ethereum Mainnet: 0x36CaABbAbfB9C09B722d9C3697C3Cb4A93650ea7

&#x20;    Manta Mainnet: 0xa898E175CfDE9C6ABfCF5948eEfBA1B852eE5B09

&#x20;    Mantle Mainnet: 0x321Ce902eDFC6466B224ce5D9A7Bc16858855272

&#x20;    zkSync Mainnet: 0x7187DB8AB8F65450a74dD40474bE778CF468C44a

&#x20;    Arbitrum Mainnet: 0x6B7551DBbaE2fb728cF851baee5c3A52DF6F60a4

&#x20;    Blast Mainnet: 0x17887788E01A1192a26F636Cfcfc033c7Bb42348

&#x20;    Optimism Mainnet: 0x6aAdaA7Bf9F5283cAF3eb2E40573D1A4d02C8B15

&#x20;    Base Mainnet: 0xa03248B029b4e348F156f4b1d93CB433a4e1361e

&#x20;    Scroll Mainnet: 0xC97c5E43c14D4F524347795410C299db1FA331b3

Merge Token Portal: 0x83FD59FD58C6A5E6eA449e5400D02803875e1104

Official Token Contract Addresses:

&#x20;     WETH: 0x8280a4e7D5B3B658ec4580d3Bc30f5e50454F169     &#x20;

&#x20;     Nova Tether USD: 0x2F8A25ac62179B31D62D7F80884AE57464699059

&#x20;     Nova Wrapped BTC: 0xDa4AaEd3A53962c83B35697Cd138cc6df43aF71f

&#x20;     Nova USD Coin: 0x1a1A3b2ff016332e866787B311fcB63928464509

&#x20;     Nova Dai Stablecoin: 0xF573fA04A73d5AC442F3DEa8741317fEaA3cDeab

Other Token Addresses:

&#x20;      <https://explorer.zklink.io/tokens>

</details>

<details>

<summary><strong>Linea Mainnet (L2, served as primary chain)</strong></summary>

zkLink proxy contract: 0x5Cb18b6e4e6F3b46Ce646b0f4704D53724C5Df05

The proxy contract  ([EIP-2535](https://eips.ethereum.org/EIPS/eip-2535)) includes the below facets：

* zkLink admin facet contract:0xcE8E69a2685c80Eb6bd825d0552f44BB34f35503
* zkLink mail box facet contract:0x11bf5BC6327f7BECB0AE753932A181c8fB5780bA
* zkLink executor facet contract:0x1b19287CE898217D937571EABa97ec50F27d1206
* zkLink getters facet contract:0xb1d0354063527E4426c4bEcbDB75fE0fb112e3CB

zkLink verifier contract: 0x902C3806A84f4e855a8746e92d7F1C9a51400458

zkLink governance contract: 0xeF528a8Ca4B6aFDB6716Ef9f11bCa0c5C47454ec

zkLink validator timelock contract: 0x509ff56c152315EdeE91A2e0f059195519507e01

ERC20 Bridge: 0x62cE247f34dc316f93D3830e4Bf10959FCe630f8

Gateway: 0x7b5780d6df85A7dF96a3e1A019639a1dbDe937dB

Note: Please read the [Contract System on Primary Chain](/architecture/settlement-layer/in-detail-contract-system-on-primary-chain) section for detailed information about the functions of the contracts deployed on the primary chain.

</details>

<details>

<summary><strong>Ethereum Mainnet(L1, served as secondary chain)</strong></summary>

zkLink contract: 0x5fD9F73286b7E8683Bab45019C94553b93e015Cf

Arbitrator: 0x1Ee09A2cAa0813A5183f90F5a6d0E4871f4C6002

ERC20 Bridge: 0xAd16eDCF7DEB7e90096A259c81269d811544B6B6

Ethereum Gateway: 0x83Bc7394738A7A084081aF22EEC0051908c0055c

Linea Gateway: 0x803460416C2682Ac54FccF03eF77b10A12f2809b

Manta Gateway: 0x649Dfa2c4d09D877419fA1eDC4005BfbEF7CD82D

Mantle Gateway: 0xdE1Ce751405Fe6D836349226EEdCDFFE1C3BE269

zkSync Gateway: 0xeCD189e0f390826E137496a4e4a23ACf76c942Ab

Arbitrum Gateway: 0x273D59aed2d793167c162E64b9162154B07583C0

Blast Gateway: 0x41FaF46Ca4Dfd912B65B66D29BdD432782BB1158

Optimism Gateway: 0x668e8F67adB8219e1816C2E5bBEa055A78AF3026

Base Gateway: 0x4eEA93966AA5cd658225E0D43b665A5a491d2b7E

Scroll Gateway: 0x986c905087a663db3C81ad319b94c1E9dd388e92

</details>

<details>

<summary><strong>Manta Mainnet (L2, served as secondary chain)</strong></summary>

zkLink contract: 0xD784d7128B46B60Ca7d8BdC17dCEC94917455657

ERC20 Bridge: 0x44a65dc12865A1e5249b45b4868f32b0E37168FF

Gateway: 0xe946aBB40928326ce5bFF303E7B8f0f253EA39D0

</details>

<details>

<summary><strong>Mantle Mainnet (L2, served as secondary chain)</strong></summary>

zkLink contract: 0xD784d7128B46B60Ca7d8BdC17dCEC94917455657

ERC20 Bridge: 0x62351b47e060c61868Ab7E05920Cb42bD9A5f2B2

Gateway: 0xe946aBB40928326ce5bFF303E7B8f0f253EA39D0

</details>

<details>

<summary><strong>zkSync Era Mainnet (L2, served as secondary chain)</strong></summary>

zkLink contract: 0xaFe8C7Cf33eD0fee179DFF20ae174C660883273A

ERC20 Bridge: 0xaB3DDB86072a35d74beD49AA0f9210098ebf2D08

Gateway: 0xC203a2DF4DDFF9eDE2200F1F02054fD721182535

</details>

<details>

<summary><strong>Arbitrum Mainnet (L2, served as secondary chain)</strong></summary>

zkLink contract: 0xFF73a1a1d27951A005eb23276dc99CB7F8d5420A

ERC20 Bridge: 0xfB0Ad0B3C2605A7CA33d6badd0C685E11b8F5585

Gateway: 0x7bd79DEd935B542fb22c74305a4d2A293C18483a

</details>

<details>

<summary><strong>Blast Mainnet(L2, served as secondary chain)</strong> </summary>

zkLink contract: 0x29BA92Fe724beD5c5EBfd0099F2F64a6DC5078FD

ERC20 Bridge: 0x8Df0c2bA3916bF4789c50dEc5A79b2fc719F500b

Gateway: 0x3f64e2e09732969813904a8473074CFADeE66AF1

</details>

<details>

<summary><strong>Optimism Mainnet(L2, served as secondary chain)</strong> </summary>

zkLink contract: 0x46C8D02E93d5a03899dFa7Cf8A40A07589A3fA1b

ERC20 Bridge: 0x5Bd51296423A9079b931414C1De65e7057326EaA

Gateway: 0xaD5d729291C0d6A299E370814CA6Ce1c8C25b51c

</details>

<details>

<summary><strong>Base Mainnet(L2, served as secondary chain)</strong> </summary>

zkLink contract: 0xE473ce141b1416Fe526eb63Cf7433b7B8d7264Dd

ERC20 Bridge: 0x80d12A78EfE7604F00ed07aB2f16F643301674D5

Gateway: 0x1054Ff8B3B7B9F68d2e55C4A42E8952332c69011

</details>

<details>

<summary><strong>Scroll Mainnet(L2, served as secondary chain)</strong> </summary>

zkLink contract: 0x119B9459D9119D07c23aD06778AeaBec804Fd1a2

ERC20 Bridge: 0x3C7c0ebFCD5786ef48df5ed127cdDEb806db976c

Gateway: 0xd8428A59B60Df2d81514D429D57DF23293f1bCe7

</details>

## Testnet Addresses

<details>

<summary><strong>zkLink Nova Sepolia Testnet (L3, zkLink Nova network)</strong></summary>

ERC-20 Bridges       &#x20;

&#x20;              Linea Sepolia Testnet: 0x6336D1DfE362a84933e526588A0fa20dd87736aE

&#x20;              Sepolia Testnet: 0xcc43208B28B1eC25F000EfC0D2c2aF044715F888    &#x20;

&#x20;              zkSync Sepolia Testnet: 0xEbEAf62E4bCb4FdeC35100838c86c84B8134ADE0

&#x20;              Arbitrum Sepolia Testnet: 0x7e1B152f25D2ff0771026067B5c8B5A1C8457478

&#x20;              Optimism Sepolia Testnet: 0x07476D10A8B3c614DC92a698cCeC34Aa9B844B92

&#x20;              Manta Sepolia Testnet: 0x1F282e46d75622C5B26921094b4ebF7D58D83CE2

&#x20;              Base Sepolia Testnet: 0x7c3c5C8528D55Af0C641846fF4756200DEFDC513

&#x20;              Blast Sepolia Testnet: 0x4E5622E4A41985C29028d92e1Cc2EdF02012c82E

</details>

<details>

<summary><strong>Linea Sepolia Testnet(L2, served as primary chain)</strong></summary>

zkLink contract: 0x16393A77e1d5C2D285BDad9079afC5942f255407

ERC20 Bridge: 0xea05Fad671D93aF9472D747866019991DF183F0f

Gateway: 0xCfD6F51B247021d2737Cb4862Fd5F87032f39724

</details>

<details>

<summary><strong>Ethereum Sepolia Testnet(L1, , served as secondary chain)</strong></summary>

zkLink contract address: 0x9719cD314BBf84B18aAEDEF56DF88E2267aA01e3

Arbitrator: 0x168792C8dAdd403948CBa6a74f069d1bacEBC137

ERC20 Bridge: 0x63e059BDEDeA829c22EfA31CbaDb9bea5E86c3Cd

Sepolia Gateway: 0xc6EbbD78E8f81626Bc62570f3C5949221F87b3Ee

Linea Gateway: 0x521Bcd03D0B6Fe91Cf432CBcf3d8121cdB0035ad

zkSync Gateway: 0x67ba43eD3860D155D16f82D12cA93A7B2e77bF2F

Arbitrum Gateway: 0xd75F08D0E513a072799C510d04D9AddC3a28Bd9A

Optimism Gateway: 0x2f24331ddFB2D582079C200d1c233F168901a4e1

Manta Gatewa&#x79;*:* 0xC8a31aA097c8D1dCF588C425415E4e5A0E250e67

Base Gatewa&#x79;*:* 0x4E2d5bAaF470028fE48a23bd5b680f4EC7A06f85

Blast Gateway: 0x83d3f5Db3eea3dD7a30aAF71A32D244386d00C53

</details>

<details>

<summary>zkSync Sepolia <strong>Testnet (L2, served as secondary chain)</strong></summary>

zkLink contract address: 0x02627EFACfc2B000E77132fE9346C543eB980bAb

ERC20 Bridge Address: 0xBf145DfdE964213246A4fcB8003621E8b0F11ffc

Gateway: 0xc6409aCe43f07dBC8CD0ED2531087822a618CFAE

</details>

<details>

<summary>Arbitrum Sepolia <strong>Testnet (L2, served as secondary chain)</strong></summary>

zkLink contract address: 0xaE1875112Ae010A9fe755418B206AfB33Ee0b1fA

ERC20 Bridge Address: 0xFC31fF38e24901052b813DcEBEF5A9A10EaF25Ec

Gateway: 0x6419a685358E4B04f65D3846bD5d1bc2d7eC3380

</details>

<details>

<summary>Optimism Sepolia <strong>Testnet (L2, served as secondary chain)</strong></summary>

zkLink contract address: 0xbaC8EF345C684B0871dF390f44273160Ba3E6bc1

ERC20 Bridge Address: 0x70194e2400eb89fA22E3bd0DaFa097CA09DAE76C

Gateway: 0xA8D5271093D88b2Cc5AA7bF18828b6E638154B80

</details>

<details>

<summary>Manta Sepolia <strong>Testnet (L2, served as secondary chain)</strong></summary>

zkLink contract address: 0xEe5aFbd53D661968d13315f6960BBb103C2a1eCc

ERC20 Bridge Address: 0x4C58CbF4e9594898e2cC66FdA3F435Cd3622Fe9f

Gateway: 0x16c640b0Db283A4129DcCF087Dbf249bD87BE493

</details>

<details>

<summary>Base Sepolia <strong>Testnet (L2, served as secondary chain)</strong></summary>

zkLink contract address: 0x8c4b80A5D5374Ff2Dc07310EF9Fdbc44e487b6C2

ERC20 Bridge Address: 0xeA6232604C847d14638a30c1D261AF6C321AAB05

Gateway: 0x2D973C644A683d041Ce3c604F8956De589ED2bD2

</details>

<details>

<summary>Blast Sepolia <strong>Testnet (L2, served as secondary chain)</strong></summary>

zkLink contract address: 0x27CBbE82447a0C188eBD7Bc5fd706d140c7B0642

ERC20 Bridge Address: 0xD74c6452Ec4c73E4E2050C6B3f4e675B96dFFC15

Gateway: 0x224E8f9802Da8Dc39C3982698613A0795d03F6d1

</details>


# Run a Node

## Introduction

zkLink Nova self-hosted RPC node is based on zkSync external node. You can find detailed information about zkSync external node [here](https://docs.zksync.io/zksync-node). This section focus on how to build a zkLink Nova self-hosted RPC node.

## Quick Start

### Preferred hardware configuration

This configuration is approximate, expect updates to these specs.

* **Architecture**: AMD64
* **CPU**: 32 core
* **RAM**: 64 GB
* **Storage**:
  * Testnet - \~1 TB (at the time of writing) and will grow over time, so should be constantly monitored
  * Mainnet - \~2 TB (at the time of writing) and will grow over time, so should be constantly monitored
  * NVMe recommended
* **Network**: 100 Mbps network connection.

### Software Prerequisites

You can follow Docker's official [manuals](https://docs.docker.com/engine/install/) to install `docker compose` and `Docker`.

### Running zkLink Nova self-hosted RPC Node locally

We offer a [docker-compose file](https://github.com/zkLinkProtocol/zksync-era/tree/zklink/docs/guides/external-node/docker-compose-examples) to facilitate running a zkLink Nova self-hosted rpc node locally.

#### Create data folder

```
sudo mkdir -p /data/mainnet-postgres
sudo mkdir -p /data/mainnet-rocksdb
sudo mkdir -p /data/mainnet-prometheus-data
sudo mkdir -p /data/mainnet-grafana-data
sudo mkdir -p /data/prometheus
sudo touch /data/prometheus/prometheus.yml
```

#### start pg sevice

```
cd /data && wget https://github.com/zkLinkProtocol/zksync-era/raw/zklink/docs/guides/external-node/docker-compose-examples/docker-compose.yml
docker-compose -f docker-compose.yml up -d postgres
```

#### Import backup data from Snapshot

{% code title="Shell" overflow="wrap" lineNumbers="true" fullWidth="false" %}

```markup
cd /data/mainnet-postgres && wget https://zklink-nova-en-snapshot.s3.ap-east-1.amazonaws.com/zklink_nova_en_snapshot.backup
docker exec -it <postgres container id> bash
psql -U postgres -p 5430 -c "create database zklink_ext_node"
pg_restore -U postgres -p 5430 -d zklink_ext_node -j $(nproc) /var/lib/postgresql/data/zklink_nova_en_snapshot.backup
```

{% endcode %}

#### Start zkLink Nova Self-hosted RPC Node

To start a mainnet instance, run:

```
docker compose -f docker-compose.yml up -d
```

To reset its state, run:

```
docker compose -f docker-compose.yml down --volumes
```

You can see the status of the node (after recovery) in the local Grafana dashboard. Those commands start external node locally inside docker. The HTTP JSON-RPC API can be accessed on port 3060 and WebSocket API can be accessed on port 3061.

{% hint style="info" %}
Tips

After importing the data, the blocks will be scanned to restore the Merkle tree with ​2000 batches per hour speed. Block synchronization will continue only after the recovery is complete. The speed of importing snapshot data into Postgres is 100G/h, the speed of rebuilding the Merkle tree is 2000 batches/h, with the specific time depending on the database snapshot.

**Get local latest block**

curl <http://localhost:3060> -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth\_blockNumber","params":\[],"id":1}'

When first start service, it will take 5 hours to struct Merkle tree.
{% endhint %}

##

## Building External Node from Source Code

This document outlines how to build the External Node from the zkLink Nova source code, supporting three ways:

1. Building the binary file for the External Node directly from the source code.
2. Building the Docker image for the External Node directly from the source code.
3. Customizing the Docker image for the External Node built from the source code.

### Install Dependencies

Run the following commands to install the necessary dependencies.&#x20;

{% hint style="info" %}
Note: If you only wish to build the Docker image for the zkLink Nova External Node from the source code, you only need to install the Docker-related dependencies.
{% endhint %}

#### Rust and Tools

```
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# SQL tools
cargo install sqlx-cli --version 0.7.3
```

#### NVM and Node/Yarn

```
# NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash

# Node & Yarn
nvm install 18
npm install -g yarn
yarn set version 1.22.19
```

#### System Software

```
# All necessary packages
sudo apt-get update
sudo apt-get install build-essential pkg-config cmake clang lldb lld libssl-dev
postgresql ca-certificates curl
```

#### Docker

```
# Docker installation
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o
/etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-compose docker-ce-cli containerd.io docker-
buildx-plugin docker-compose-plugin -y
sudo usermod -aG docker <YOUR_USER>
```

### Pulling Source Code

Use the command below to pull the zkLink Nova source code and fetch the submodules. If you wish to build code related to the zkLink Nova Sepolia testnet, please use the zklink\_testnet branch.

```
git clone -b zklink https://github.com/zkLinkProtocol/zksync-era.git
cd zksync-era
git submodule update --init --recursive
# Initialize build system
zk
# Build contract artifacts
zk compiler system-contracts
zk contract build
```

Run the command below to set up the working directory:

```
echo -e "export ZKSYNC_HOME=$(pwd)\nexport PATH=\$ZKSYNC_HOME/bin:\$PATH" >>
~/.bashrc && source ~/.bashrc
```

### Build the External Node

#### If you only wish to build the binary file for the External Node

Execute the command below; the results will be located in the target/release directory.

```
cargo build --release
```

#### If you want to build the Docker image for the External Node from source

Run the command below:

```
docker build -f docker/external-node/Dockerfile . -t <image name>:<tag>
```

#### If you want to customize the Docker image for the External Node

Refer to all the <mark style="background-color:green;">BUILD</mark> and <mark style="background-color:green;">COPY</mark> commands in the <mark style="background-color:green;">docker/external-node/Dockerfile</mark> file to customize the Docker image for the zkLink Nova External Node.


# Tools


# Bridges

Mainnet Bridge

<https://portal.zklink.io>

## Testnet Bridge

<https://sepolia.portal.zklink.io>

## Third Parity Bridges

{% embed url="<https://free.tech/>" %}

{% embed url="<https://www.orbiter.finance/>" %}

{% embed url="<https://meson.fi/>" %}

{% embed url="<https://app.symbiosis.finance/>" %}


# Blockchain Explorer

## Mainnet Explorer

Explorer:  <https://explorer.zklink.io>

Explorer API: <https://explorer-api.zklink.io>

Contract Verification URL:  <https://explorer.zklink.io/contract_verification>

## Testnet Explorer

Explorer:  <https://sepolia.explorer.zklink.io>

Explorer API: <https://sepolia.explorer-api.zklink.io>

Contract Verification URL:  <https://sepolia.explorer.zklink.io/contract_verification>


# Oracles

Currently, developers on Nova can use [RedStone](https://redstone.finance/) or [APRO](https://apro.com/) oracle to get external information like token price. Please refer to the below doc for more detailed information.

{% embed url="<https://docs.redstone.finance/docs/smart-contract-devs/how-it-works>" %}

{% embed url="<https://docs.apro.com/en>" %}


# MultiSig Wallet

## Safe

Safe is a customizable crypto wallet that requires a predefined number of signatures to confirm transactions to prevent unauthorized access to the assets stored. DeFi apps can be accessed and user funds can be put to work from inside the safe interface. There are currently dozens of billions in funds stored in safes in Ethereum ecosystem.

### Official Safe Website on zkLink Nova

[https://safe.zklink.io/](https://safe.zklink.io/welcome)

### Safe Transaction Service API

[https://transaction.safe.zklink.io/ ](<https://transaction.safe.zklink.io/ >)

### Safe's Contracts (1.3.0) &#x20;

CompatibilityFallbackHandler: [0x2f870a80647BbC554F3a0EBD093f11B4d2a7492A](https://explorer.zklink.io/address/0x2f870a80647BbC554F3a0EBD093f11B4d2a7492A#contract) &#x20;

CreateCall: [0xcB8e5E438c5c2b45FbE17B02Ca9aF91509a8ad56](https://explorer.zklink.io/address/0xcB8e5E438c5c2b45FbE17B02Ca9aF91509a8ad56#contract) &#x20;

DefaultCallbackHandler: [0x08798512808f838a06BCe7c26905f05e94dF6f50](https://explorer.zklink.io/address/0x08798512808f838a06BCe7c26905f05e94dF6f50#contract)&#x20;

GnosisSafe: [0xB00ce5CCcdEf57e539ddcEd01DF43a13855d9910](https://explorer.zklink.io/address/0xB00ce5CCcdEf57e539ddcEd01DF43a13855d9910#contract)&#x20;

GnosisSafeL2: [0x1727c2c531cf966f902E5927b98490fDFb3b2b70](https://explorer.zklink.io/address/0x1727c2c531cf966f902E5927b98490fDFb3b2b70#contract)

GnosisSafeProxyFactory: [0xDAec33641865E4651fB43181C6DB6f7232Ee91c2](https://explorer.zklink.io/address/0xDAec33641865E4651fB43181C6DB6f7232Ee91c2#contract)&#x20;

MultiSend: [0x0dFcccB95225ffB03c6FBB2559B530C2B7C8A912](https://explorer.zklink.io/address/0x0dFcccB95225ffB03c6FBB2559B530C2B7C8A912#contract)&#x20;

MultiSendCallOnly: [0xf220D3b4DFb23C4ade8C88E526C1353AbAcbC38F](https://explorer.zklink.io/address/0xf220D3b4DFb23C4ade8C88E526C1353AbAcbC38F#contract)

SignMessageLib: [0x357147caf9C0cCa67DfA0CF5369318d8193c8407](https://explorer.zklink.io/address/0x357147caf9C0cCa67DfA0CF5369318d8193c8407#contract)

SimulateTxAccessor: [0x4191E2e12E8BC5002424CE0c51f9947b02675a44](https://explorer.zklink.io/address/0x4191E2e12E8BC5002424CE0c51f9947b02675a44#contract)


# Node Providers

### zkLink Nova Official RPC

<https://rpc.zklink.io>

<https://rpc.zklink.network>

wss\://rpc.zklink.io

wss\://rpc.zklink.network

### [Chainnodes](https://www.chainnodes.org/)

You can always get technical support directly from Chainnodes' Blockchain developers, 24/7.

Documentation:

<https://www.chainnodes.org/docs/zklink>

Public RPC:&#x20;

<https://zklink-nova-mainnet-public.chainnodes.org>

\
Private RPC:

<https://zklink-nova-mainnet.chainnodes.org/API\\_KEY>\\

wss\://zklink-nova-mainnet.chainnodes.org/API\_KEY

### [Grove](https://www.grove.city/)

Please go to <https://www.grove.city/> , sign up and create an application, go to the endpoint tab and find the zkLink endpoint.


# Actions & magicLink SDK

{% hint style="info" %}
Note: **Actions** & **magicLink** is in beta and undergoing audit. Please [Contact Us](https://t.me/laniakeiaa) if you plan on going live with it.
{% endhint %}

## Overview

magicLink is a tool provided by zkLink that simplifies blockchain transactions into a shareable short link. With magicLink, users don’t need to understand complex blockchain operations. They can click the link, set a few simple parameters, and generate, preview, and sign the transaction, which can then be sent to various networks. This short link can easily be shared on social media or websites, making the user experience straightforward and smooth.

Key uses of magicLink:

* Simplified Transactions: Wrap complex on-chain operations into a simple link. Users click the link, enter parameters, confirm, and initiate a transaction.
* Cross-chain Support: magicLink handles transactions across multiple EVM-compatible networks. Users don’t need to worry about lacking tokens on a specific chain—this is managed in the background.
* Low Barrier of Entry: Users don’t need to understand the details of transactions; just simple inputs and clicks are enough to complete the process.
* Multiple Use Cases: Supports on-chain activities like token swaps, voting, and sponsorships.

Imagine you're building an on-chain voting dApp or a red packet dApp. Traditionally, beyond deploying smart contracts, you would need to develop and host front-end and back-end services, register domain names, and integrate with Twitter/Telegram for promotion. With magicLink, the development process is greatly simplified. You only need to focus on developing the Action. Once everything is ready, your dApp is essentially complete. Isn't that cool?

For developers, magicLink is created through the Action API, where you can define the business logic and customize the behavior based on the use case. magicLink provides a simple, efficient way to interact with the blockchain while giving users a seamless experience.

## **Key Concepts**

* **Action**: An action is a target implementation for developers and serves as the core functionality behind different magicLinks. Simply put, it’s an abstract class that developers need to implement, which defines a standard interface for Action implementations. Through an Action, developers are required to set some necessary metadata, such as the `id`, `version`, `title`, `logo`, and `description`. Additionally, they need to guide how the magicLink constructs transactions. Actions also allow for defining data validation, displaying information to magicLink users, and more. We will go into further details in the following sections
* **magicLink**: It is a shareable short link that serves as the entry point for executing an action. On the page of this short link, users can set a few parameters using selection boxes or input fields. After clicking confirm, they can generate and preview the transaction. If everything is correct, the user can sign and send it to the different networks. While on a website, a magicLink might immediately initiate a transaction preview in a wallet without redirecting users to a dApp. In Telegram, a bot can be used to expand a magicLink into an interactive set of buttons. In the future iteration, this function will be expanded to Discord.

## Role

magicLink involves three key roles from development to sharing and usage:

* Developer: The role responsible for developing Actions. Developers need to implement the Action specifications and submit the code to the repository. We (zkLink) will register the reviewed Actions.
* Intent Creator: The role responsible for creating magicLinks. They select a registered Action, configure it, and generate a shareable short link.
* User: The person using the magicLink. Users do not need to understand complex transaction details; they can send transactions and participate in activities with simple inputs and clicks.

## How It Works

The image below illustrates the flow from the user's transaction initiation to the core logic call of the **Action** created by the developer. The user initiates a request from the magicLink frontend. Since each magicLink is unique, when the backend service receives the request, it finds the corresponding **Action ID** from our **Action Registry** and retrieves the Action instance. At this point, the core functionality within the Action converts the parameters carried by the magicLink into a constructed transaction, which is then returned to the frontend. The frontend constructs the correct transaction and guides the user to send the transaction.

<figure><img src="/files/rkD9kcLtKKwy7wf1uPhC" alt=""><figcaption></figcaption></figure>

## Create an Action

Next, we will walk you through a real-world example: **Donation**. This will demonstrate, step by step, how to create a fully functional Action from scratch.

In this case, we will describe all the features and functionalities you might need as thoroughly as possible.

### 0. Prepare

We use *npm* as package manager, *postgres* database. We develop using *TypeScript* and have chosen *NestJS*, a Node.js framework, as the foundational framework for our entire system. You will need a basic understanding of TypeScript and a general knowledge of NestJS's dependency injection and IoC (Inversion of Control).

To get started, ensure that Node and Postgres are installed locally. clone the repository:

```
git clone git@github.com:zkLinkProtocol/zklink-intent-url.git
```

Then install the dependencies:

```
npm install
```

Create a .env file from .env.example and make sure all necessary environment variables are correctly assigned. (DATABASE\_\* WITNESS\_PRIVATE\_KEY)

```
cp .env.example .env
```

Create all db tables

```
npm run migration:run 
```

Start the local service.

```
npm run start:debug
```

From now you can start to develop your action.

### 1. Initialize

All Action implementations must be in the `libs` directory as a nest sub-project. So you must initiate your action project here. Run the following command:

```
npx nest g library my-action
```

According to the command line prompt

```
? What prefix would you like to use for the library (default: 
@app or 'defaultLibraryPrefix' setting value)? @action
```

enter **'@action'** and press *Enter*. You will see `nest-cli.json` in repository root is modified, and a new directory named `my-action` in the `libs` directory. This directory contains the basic structure of a nest project.

```
# terminal output
CREATE libs/my-action/tsconfig.lib.json (223 bytes)
CREATE libs/my-action/src/index.ts (73 bytes)
CREATE libs/my-action/src/my-action.module.ts (203 bytes)
CREATE libs/my-action/src/my-action.service.spec.ts (475 bytes)
CREATE libs/my-action/src/my-action.service.ts (92 bytes)
UPDATE nest-cli.json (2000 bytes)
UPDATE package.json (4323 bytes)
UPDATE test/jest-e2e.json (1136 bytes)
UPDATE tsconfig.json (1855 bytes)

# generated files
libs/
│
├── tsconfig.lib.json
└── src/
    ├── index.ts
    ├── my-action.module.ts
    ├── my-action.service.ts
    └── my-action.service.spec.ts
```

Congratulations! You've successfully taken the first step.

### 2. Action Definition

Next, what you need to do next is to complete the development of the `Action` in the `my-action.service.ts` file. We provide an abstract class [`Action`](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/src/common/dto/action.dto.ts) that you must extend to implement your action.

```
import { Injectable } from '@nestjs/common';

import {
  Action,
  GenerateTransactionParams,
  TransactionInfo,
} from 'src/common/dto';

@Injectable()
export class MyActionService extends Action<T> {
  async getMetadata() {}

  async generateTransaction(
    data: GenerateTransactionParams<T>,
  ): Promise<TransactionInfo[]> {}
}
```

There are two abstract methods that must be implemented: `getMetadata` and `generateTransaction`. We'll start by adding placeholders for them. TypeScript will show errors, but don’t worry—we'll implement them later. The generic `T` will also be set to the correct type based on the needs of the action.

#### **2.1 ActionMetadata**

Let's start by implementing `getMetadata`. It returns what appears to be a complex object literal of type `ActionMetadata<T>`. You can check the meaning of each field [here](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/src/common/dto/action-metadata.dto.ts).

```
async getMetadata() {
  return {
    title: 'Action Title',
    description:
      'This action allows you to create a Magic Link... This is an action example description.',
    networks: [
      {
        name: 'Arbitrum',
        chainId: '42161',
      },
      {
        name: 'zkLink Nova',
        chainId: '810180',
      }
    ],
    author: { name: 'Action Author', github: 'https://github.com/zkLinkProtocol' },
    magicLinkMetadata: {
      description:
        'Magic Link Enthusiast | Donate with your love for zkLink magic',
      title: 'This is a magic link'
    },
    intent: {
      components: [
        {
          name: 'token',
          label: 'Token',
          desc: 'The token you want to cost',
          type: 'searchSelect',
          options: [
            {
              label: 'ETH',
              value: '',
              chainId: '42161',
              default: true,
            },
            {
              label: 'USDT',
              value: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
              chainId: '42161',
            },
            {
              label: 'USDC',
              value: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
              chainId: '42161',
            },
            {
              label: 'ETH',
              value: '',
              chainId: '810180',
              default: true,
            },
            {
              label: 'USDT',
              value: '0x2F8A25ac62179B31D62D7F80884AE57464699059',
              chainId: '810180',
            },
            {
              label: 'USDC',
              value: '0x1a1A3b2ff016332e866787B311fcB63928464509',
              chainId: '810180',
            },
            {
              label: 'ETH',
              value: '',
              chainId: '810181',
              default: true,
            },
            {
              label: 'USDT',
              value: '0x0efDC9f3948BE4509e8c57d49Df97660CF038F9a',
              chainId: '810181',
            },
            {
              label: 'USDC',
              value: '0xAC4a95747cB3f291BC4a26630862FfA0A4b01B44',
              chainId: '810181',
            },
            {
              label: 'ETH',
              value: '',
              chainId: '270',
              default: true,
            },
            {
              label: 'USDT',
              value: '0xDBBD57f02DdbC9f1e2B80D8DAcfEC34BC8B287e3',
              chainId: '270',
            },
            {
              label: 'USDC',
              value: '0x09B141F8a41BA6d2A0Ec1d55d67De3C8f3846921',
              chainId: '270',
            },
          ],
        },
        {
          name: 'value',
          label: 'Amount',
          desc: 'The amount to sponsor',
          type: 'input',
          regex: '^\\d+\\.?\\d*$|^\\d*\\.\\d+$',
          regexDesc: 'Must be a number',
        },
        {
          name: 'recipient',
          label: 'Recipient',
          desc: 'The address that is sponsored',
          type: 'input',
          regex: '^0x[a-fA-F0-9]{40}$',
          regexDesc: 'Invalid address',
        },
      ],
      preset: [
        {
          field: 'value',
          title: 'Donate 0.01 ETH',
          type: 'Button',
          value: '0.01',
        },
      ],
    },
  }
};
```

Now, follow along with me as we explore each field in the metadata and understand its meaning in conjunction with the UI.

The left side of this image is the magicLink creation area, and the right side is the magicLink preview area, where creators can create their own magicLink by setting and modifying metadata.

The metadata defined above will be reflected in the corresponding UI controls on the frontend and the highlighted fields correspond to the metadata object literals you defined.

[![](https://github.com/zkLinkProtocol/zklink-intent-url/raw/dev/docs/img/create-action.png)](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/docs/img/create-action.png)

I will provide further explanations for some fields that need clarification.

* *networks*: It is an array, indicating which network the target chain of the created magicLink belongs to. For example, you allow the creation of a donation link, enabling users to donate to you on Ethereum, and also allow the creation of a magicLink for donations on the Arbitrum network

  [![](https://github.com/zkLinkProtocol/zklink-intent-url/raw/dev/docs/img/select-network.png)](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/docs/img/select-network.png)
* *magicLinkMetadata*: You can set the default values for the magicLink's title, main image, and description here, as shown in the image above. You might be curious about where to set this main image. There are two ways to set it: you can explicitly set the 'gallery' field, whose value is a URL of an image accessible over the internet. Alternatively, you can set it implicitly by uploading an image with the same name as the id in the assets/galleries directory. We will help you upload it to S3 and set it as the value for the `gallery`. Therefore, the default image in the preview section of the magicLink above is because there is an image in assets/galleries with the same name as the id.

  ```
  // 1. explicitly
  magicLinkMetadata: {
    description:
      'Magic Link Enthusiast | Donate with your love for zkLink magic',
    title: 'This is a magic link',
    gallery: 'https://zklink-nova-nft.s3.ap-northeast-1.amazonaws.com/cuboimage-test/193.png'
  }

  // 2. implicitly
  magicLinkMetadata: {
    description:
      'Magic Link Enthusiast | Donate with your love for zkLink magic',
    title: 'This is a magic link',
  }
  // main image location
  assets/
  │
  └── galleries/
      ├── my-action.png
      ├── ...
  ```
* *components*: The fields defined here are generally those that you need the **creator** to flexibly fill in. These parameters will eventually be passed in as part of the arguments in `generateTransaction` and used flexibly for constructing transactions or making conditional judgments and etc.

  Among them, it can be of various types such as input (allowing user input), text (fixed display parameters), or select (dropdown menu selection).

  If the type is 'select', it will have `options`, which are the choices in the dropdown menu. There are two required fields: `label` & `value` - label is used for menu display, and value acts as the value for `name`. There are two optional items: `chainId`, which specifies that this option is only selectable when the same chainId is selected in `networks`, and `default : true` indicates that it is the default selected value.

<figure><img src="/files/IVhRovYoWozLU746ELMX" alt=""><figcaption></figcaption></figure>

* preset: This field presets the default trigger for the magicLink. `field` refers to the name of a specific `name`, `value` is the value of `name`, `title` is used for display, and `type` can be set to either 'Button' or 'Input'.

<figure><img src="/files/GTzvrbHgGasXbD4CE2YO" alt=""><figcaption></figcaption></figure>

#### **2.2 generateTransaction**

Another function that must be implemented is `generateTransaction`, whose return data type is [`TransactionInfo[]`](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/src/common/dto/transaction.dto.ts#57). When a user clicks the **0.001ETH** button on the Magic Link page, the `TransactionInfo[]` will be sequentially constructed into on-chain transactions and sent to the network.

It is necessary to delve into the parameters of GenerateTransactionParams here

```
export type GenerateTransactionParams<
  T extends Record<string, any> = Record<string, any>,
> = {
  additionalData: AdditionalParams;
  formData: GenerateFormParams<T>;
};

type AdditionalParams = {
  chainId: string; // Network chain ID
  code?: string; // magic link code, a unique 8-character random string
  account?: string; // the user address that initiates the transaction.
  inviter?: string;
};
```

* code: You can leverage the code with the contract or your external service for deep binding, where each magic link has a unique and unrepeatable code.
* inviter: The inviter is a field used to handle invitation-related information. When users share the magic link, they include their address as the inviter. If your action has a sharing commission feature, you can incorporate the inviter into your contract to implement the logic.
* formData: It is the component you define in the component, and it is the raw form data used to construct the transaction. Next, we will implement a straightforward generateTransaction method

```
async generateTransaction(
    data: GenerateTransactionParams,
): Promise<TransactionInfo[]> {
  // Build and return your transaction
   const { formData } = data;
  const tx = {
    chainId: 810180,
    to: formData.recipient,
    value: formData.value,
    data: '0x',
  }
  return [tx];
}
```

As you can see, the simplest version of `TransactionInfo` only needs to define 4 fields related to the transaction. There are also 3 unused fields here, which are useful in certain scenarios and require further introduction to you.

* *shouldPublishToChain*: In most cases where a user needs to send an on-chain transaction, this field needs to be set to true.
* *customData*: If you are familiar with [paymaster](https://docs.zksync.io/build/start-coding/zksync-101/paymaster), then you will be quite accustomed to this. [Learn how to send a transaction through a paymaster](https://docs.zksync.io/build/start-coding/quick-start/paymasters-introduction#how-to-send-a-transaction-through-a-paymaster)
* *requiredTokenAmount*: Magic Link has the capability to allow developers to implement **Nova cross-chain** functionality with simple configurations. For example, the aforementioned transaction occurs on the Arbitrum chain, but if you want to allow users to attempt a cross-chain transfer of a corresponding amount of tokens from the Nova network when they do not have enough tokens on Arbitrum, you only need to configure this parameter, and it will try to execute the corresponding cross-chain request.

  ```
  async generateTransaction(
      params: GenerateTransactionParams,
  ): Promise<TransactionInfo[]> {
    // Build and return your transaction
    const tx = {
      chainId: 42161, // arbitrum chain ID
      to: params.recipient,
      value: params.value,
      data: '0x',
      requiredTokenAmount: [{
        token: params.token,
        amount: params.value,
      }]
    }
    return [tx];
  }
  ```

#### **2.3 Registry an action**

After the above steps, you have created a simple action. The final, we need to register it in our registry so that the system can properly run this action's functionality.

We provide the `RegistryPlug` decorator, which requires two input parameters: args\[0] is the action ID, and args\[1] is the version number.

The **action ID** should follow the snake-case naming convention and match the name used in the command `npx nest g library my-action`, which is the name of your Action folder. This ensures that it is unique and does not conflict with other actions. This ID will be used as a runtime index throughout the system, guiding the runtime code to load and execute the Action. **Keep the naming consistent and do not allow further modifications.**

The **version** represents the version of your action, and the version number should start from `v1`. Each time you upgrade the action, increment the version by 1. For example, the initial submission of the action should be version `v1`. If you upgrade the action multiple times in the future, the version number should be updated to **v2**, **v3**, **v4**, and so on. For upgrading an action, please refer to the [Action Upgrade](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/docs/develop.md#2-how-do-i-update-or-upgrade-an-action) section.

```
// my-action.module.ts
import { Module } from '@nestjs/common';

import { MyActionService } from './my-action.service';

@Module({
  providers: [MyActionService],
  exports: [MyActionService],
})
export class MyActionModule {}


// my-action.service.ts
@RegistryPlug('my-action', 'v1')
@Injectable()
class MyActionService extends ActionDto<FormName> {
  ...
}
```

In the `libs` folder, we have defined the `RegistryPlug` decorator. Additionally, we have defined the `Registry Module`. This module acts as a registry for all the actions developed by developers. It uses NestJS's IoC to inject all the actions into our application, making them effective.

The application will scan all action classes decorated with **RegistryPlug** in the **registry module**. It will register the action IDs into the application and use the highest version number for each ID as the currently available action for the **intent creator**. Meanwhile, for *already* created magic links, they will continue to use their originally corresponding version number.

```
@Module({
  imports: [
    MyActionModule,
    ... // other actions
  ]
  providers: [RegistryService],
  exports: [RegistryService],
})
export class RegistryModule {}
```

Our framework will register your Action implementation into the routing system. When a request arrives, it will locate your Action implementation based on your ID, pass in the parameters, and execute your business logic, ultimately generating a transaction for the user to sign and send.

### 3. Advanced Methods

* The `validateFormData` method allows developers to create more flexible validation rules. It takes `validateFormData` as input and returns a string containing error messages. When the frontend creates an magicLink, the parameters passed can be validated against custom rules using this hook function. If an error message is returned, the frontend will display it.

  ```
  // amountIn and recipient are parameters input by the intents component
  // pseudocode below: 
  async validateFormData(formData: GenerateFormParams<FormData>): Promise<ErrorMessage> {
    const { amountOfRedEnvelopes } = formData
   if (
      Number(amountOfRedEnvelopes) < 200 ||
      Number(amountOfRedEnvelopes) > 10000
    ) {
      return 'Number of Red Packets should be between 200 and 10000';
    }
    return ''; // no error message

  ```

<figure><img src="/files/Qp3dkYOC0QP2HIlucE6z" alt=""><figcaption></figcaption></figure>

* The `reloadAdvancedInfo` optional function processes real-time contract information that should be displayed to users through the magicLink.

  For example, for a red packet contract, it might show something like *"There are 20 red packets in total, and 3 red packets have been claimed."* Developers can use this method to return a title and a HTML string based on the contract's view function, making it easier for users to refresh and view the information.

  After the developer defines the title and html content, the display in the magicLink will be similar to the part highlighted in red in the image

  ```
  // You can obtain status information from the contract or through other APIs and return the results
  // pseudocode below: 
  async reloadAdvancedInfo(data: BasicAdditionalParams): Promise<{ title: string; content: string }> {
   const price = await fetchApi('price')
   const marketCap = await fetchApi('marketCap')
   return {
     title: 'Token Info'
     content: `<p>price: ${price}<p><p>Market Cap: ${marketCap}</p>`
   }
  }
  ```

  [![](https://github.com/zkLinkProtocol/zklink-intent-url/raw/dev/docs/img/real-time-example.png)](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/docs/img/real-time-example.png)
* **magicLink binds to on-chain transactions**. After creating the magicLink, it may not become active immediately and you need to initiate one or more transactions on-chain before you can create an active magicLink. For example, with a red packet contract, you need to deposit a red packet asset into the contract before the Magic Link can become active. This way, users can claim the red envelope created through your Magic Link.

The `onMagicLinkCreated` provides this capability. It returns `TransactionInfo[]`. Its signature is the same as `generateTransaction`, but it is an on-chain transaction executed immediately after the Magic Link is created.

<figure><img src="/files/RbdGeBfMd6smGIKO2h9y" alt=""><figcaption></figcaption></figure>

In the image above, we can see that after creating a Magic Link, the transaction returned by `onMagicLinkCreated` is constructed and sent as an on-chain transaction.

* `preCheckTransaction`, the magic link is not always available to users. Imagine a scenario where you expect users to participate in a vote only once through the magic link. Therefore, when loading the magic link, you need to query the on-chain information to check if the user has already voted. If they have voted, this function should return a message to inform the user of the reason they cannot vote again.

  ```
  // pseudocode

   public async preCheckTransaction(
    data: GenerateTransactionParams<FieldTypes>,
  ) {
    const { additionalData } = data;
    const { code, account } = additionalData;
    if (!code) {
      throw new Error('missing code');
    }
    const hasVoted = this.contract.queryVotedStatus(code, account);
    if (hasVoted) {
      return 'You has already voted';
    } else {
      return '';
    }
  }
  ```
* `reportTransaction` is similar to preCheckTransaction above, this function also returns a message to politely inform the user of the result of their transaction after it has completed.

  ```
  async reportTransaction(
    data: GenerateTransactionParams<FieldTypes>,
    txHash: string,
  ): Promise<ErrorMessage> {
      const { formData } = data;
      const { distributionToken } = formData;
      const iface = new Interface(RedPacketABI);
      const eventTopic = ethers.id('RedPacketClaimed(uint256,address,uint256)');
      try {
        const receipt = await this.provider.getTransactionReceipt(txHash);
        if (!receipt) {
          throw new Error('wrong transaction hash');
        }
        const log = receipt.logs.find((log) => {
          return log.topics[0] === eventTopic;
        });
        if (!log) {
          throw new Error('parse log error');
        }
        const event = iface.parseLog(log);
        const { amount } = event?.args ?? { amount: 0n };
        const decimals = await this.getDecimals(distributionToken);
        const symbol = this.getTokenNameByAddress(distributionToken);
        const claimedAmount = formatUnits(amount.toString(), decimals);
        return `You have received ${claimedAmount} ${symbol} in red packet amount!`;
      } catch (error) {
        throw new Error(`Failed to fetch transaction receipt: ${error.message}`);
      }
    }
  ```

  The above reportTransaction function politely informs the user of the successful outcome after they have successfully claimed the red envelope through the magic link

### 4. Switch `env`

We offer two environment variables, `dev` and `prod`, that allow you to configure contract addresses or settings for both environments. The env variable for the **dev** branch is set to `dev`, while the env variable for the **main** branch is set to `prod`. In the **dev** branch, you can test with the test-network's magicLink, and once the code is merged into the main branch, it will read the mainnet network's contract configurations.

Here's how you can implement this:

1. Create a config.ts file:

```
export const config = {
  dev: {
    chainId: 810181,
    rpcUrl: 'https://sepolia.rpc.zklink.io',
    quoterContractAddress: '0x86Fc6ab84CFc6a506d51FC722D3aDe959599A98A',
  },
  prod: {
    chainId: 810180,
    rpcUrl: 'https://rpc.zklink.io',
    quoterContractAddress: '0x23Fc6ab84CFc6a506321FC722D3aDe959599A901',
  },
} as const;
```

2. Read the env using NestJS DI:

```
@Injectable()
export class RedEnvelopeService extends ActionDto {
  constructor(readonly configService: ConfigService) {
    const env = configService.get('env', { infer: true })!;
    this.config = config[env];
  }
}
```

This setup ensures that your Actions uses the correct configuration based on the environment it is running in.

### 5. Submit

After implementing your action, you need to submit a PR to the repository. We will review your code and consider whether to accept it.

## Example

The [buy-me-a-coffee](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/libs/buy-me-a-coffee) and [`novaswap`](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/libs/novaswap) Actions are good examples for you to learn how to implement an action.

## How to debug your action

All of the metadata configurations and function implementations mentioned above are designed to build the frontend UI and on-chain transactions.

If you want to conveniently use local actions, create magic links, and initiate transactions through the magic links during the action development process, you can follow these steps.

1. Use the VSCode debug terminal

[![](https://github.com/zkLinkProtocol/zklink-intent-url/raw/dev/docs/img/debug-terminal.png)](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/docs/img/debug-terminal.png)

2. Ensure that the .env file is configured correctly so that the program can run properly, with a focus on the database configuration and run `npm run migration:run`

   ```
   DATABASE_HOST=
   DATABASE_USER=
   DATABASE_PASSWORD=
   DATABASE_NAME=
   ```

   run command

   ```
   npm run migration:run
   npm run start:debug
   ```
3. Set breakpoints in the code area.

[![](https://github.com/zkLinkProtocol/zklink-intent-url/raw/dev/docs/img/debug-breakpoint.png)](https://github.com/zkLinkProtocol/zklink-intent-url/blob/dev/docs/img/debug-breakpoint.png)

4. Access the magic link [dev dashboard](https://zklink.io/dashboard/) page using a browser, open the browser console, and type in the console `localStorage.setItem('baseUrl', 'http://localhost:4101/api')`. After refreshing the browser, all service requests will be directed to <http://localhost:4101/api>. Note that `4101` should match the `PORT` in your local .env file.

   Next, log back into the dashboard using MetaMask or Passkey, create a magicLink, and initiate a transaction using the magicLink. All this data will be stored in your local database.

   Be sure to check the requests in the browser's network tab to see if they are reaching the local port service; if not, set the `localStorage`.

## Tips and Tricks

### Keep it Simple

Our Action interface offers flexibility, allowing you to implement TypeScript business logic according to your requirements. However, please ensure that your logic implementation remains as straightforward as possible.

### Use Industry-Standard Libraries

While you may introduce new dependencies, please ensure that you use industry-standard libraries.

### Minimize External Dependencies

You are permitted to reference external API services with caution. During the code review process, we will consider the impact on our business operations. The preferred approach is to avoid relying on external API services and, if necessary, to only obtain essential data from the zkLink Nova blockchain.

### Prioritize Security

Security is our top priority. Minimizing dependencies and external services enhances the robustness of our service. This will be a key criterion in our evaluation of your Action implementation.

###

### FAQs

#### 1. How to set the logo and main image for the magicLink.

You have two ways to set it. One is to set it directly in the metadata as literals, under `logo` and `magicLinkMetadata.gallery` for the logo and the main image of the magicLink, respectively. The other way is to upload images with the same action id in the 'assets' directory at the root."

#### 2. How do I update or upgrade an action?

Whether you update or upgrade your action depends on which part of the logic you have modified. It is crucial to consider "**whether the changes impact the creation of on-chain transactions**".

If you are making changes such as correcting typos, updating titles, logos, or adding a few options without affecting the core logic of `generateTransaction`, then it is considered an **update**.

However, if the changes affect the core logic of `generateTransaction`—for example, if version 1 requires casting 1 vote per transaction and now version 2 enforces casting 5 votes per transaction—then it constitutes an **upgrade**.

Follow these steps:

1. Modify Your Code: Make the necessary changes to your action implementation. Test Thoroughly: Ensure all changes are thoroughly tested, including unit, integration, and manual tests:

   * **update**: Directly modifying the code logic without changing the version number in the `RegistryPlug` decorator.
   * **upgrade**: Upgrade the version number to the next number. And you can cleverly use TypeScript's inheritance capabilities to override any core methods in the V1 Action class.

   ```
     @RegistryPlug('my-action', 'v1')
     @Injectable()
     class MyActionService extends Action {
       async private getSignature() {
         ...
       }

       async public generateTransaction() {
           const signature = await this.getSignature()
           ...
       }
     }

     @RegistryPlug('my-action', 'v2')
     @Injectable()
     class MyActionServiceV2 extends Action {
       async private getSignature() {
         console.log('enhanced functionality')
         ... // original logic
         console.log('another enhanced functionality')
       }

       async public generateTransaction() {
           const signature = await this.getSignature()
           ...
       }
     }
   ```

   The above `MyActionServiceV2` inherits most of the functionality from `MyActionService`, but overrides the `getSignature` method. It's that simple — just a small amount of code allows you to easily upgrade to a new version of an action.

   Finally, don't forget to register the new version of the action.

   ```
     @Module({
       providers: [
         MyActionService, // KEEP the old version action!!!
         MyActionServiceV2,
         ... // other actions
       ],
       exports: [
         MyActionService,
         MyActionServiceV2,
         ... // other actions
       ],
     })
     export class RegistryModule {}
   ```
2. Submit a Pull Request (PR): Create a PR with a detailed description of the changes and the reasons for the update.
3. Code Review: The zkLink team will review your PR for quality, security, and compliance with standards.
4. Approval and Registration: Once approved, your updated action will be registered and available for use. The action-id cannot be changed arbitrarily; it will remain fixed and unchanged

#### 3. What if my action requires external data?

Minimize reliance on external APIs. If necessary, use them cautiously and ensure they do not impact business operations.

#### 4. What is the submission and review process for new actions?

1. Submit a PR: Follow the repository's guidelines for submitting a pull request.
2. Code Review: Your code will be reviewed for quality, security, and compliance with standards.
3. Approval: Once approved, your action will be registered and available for use.

## Glossary

1. Action: A standardized API implementation for generating transactions.
2. magicLink: A shareable link for executing actions on the zkLink Nova network.
3. Swagger: A tool for testing and verifying APIs.


# Help

In case you have any questions, or if you run into any issues during your development journey, feel free to reach out to us through any of the following channels.

<table><thead><tr><th width="136" align="center">Channel</th><th>Link</th></tr></thead><tbody><tr><td align="center">Discord</td><td><a href="https://discord.com/invite/zklink">https://discord.com/invite/zklink</a></td></tr><tr><td align="center">Telegram</td><td><a href="https://t.me/zkLinkorg">https://t.me/zkLinkorg</a></td></tr></tbody></table>


# Github

zkLink contract deployed on the primary chain:

<https://github.com/zkLinkProtocol/era-contracts>

zkLink contract deployed on the secondary chains:

<https://github.com/zkLinkProtocol/zklink-evm-contracts>


# Audits

## Audited for zkLink Nova

<table><thead><tr><th width="148" align="center">Auditor</th><th width="157" align="center">Time</th><th width="201" align="center">Report</th><th>Description</th></tr></thead><tbody><tr><td align="center"><p>Secure3 </p><p></p><p></p><p></p><p></p><p></p><p></p><p>ABDK</p></td><td align="center"><p>Mar. 8th, 2024 </p><p></p><p></p><p></p><p></p><p></p><p></p><p>Mar. 27th, 2024</p></td><td align="center"><p><a href="https://github.com/zkLinkProtocol/zklink-audit-report/blob/master/zkLink%20Nova/Secure3_zklink_Nova_2024.3.pdf">Secure3_zklink_Nova_2024.3</a></p><p></p><p></p><p></p><p></p><p><a href="https://github.com/zkLinkProtocol/zklink-audit-report/blob/master/zkLink%20Nova/ABDK_zkLink_Nova_2024.3.pdf">ABDK_zkLink_Nova_2024.3</a></p></td><td><p>zkLink Nova is built upon ZK Stack, which uses the same code of zkSync Era. </p><p>For the <a href="https://github.com/zkLinkProtocol/era-contracts">codes </a>deployed on the primary chain used for ZKP verification, the auditors only audited the difference versus zkSync Era's source code.</p><p>The auditors audited all the <a href="https://github.com/zkLinkProtocol/zklink-evm-contracts">codes</a> deployed on the secondary chains used for hosting users' fund and execute on-chain transactions. </p></td></tr><tr><td align="center"><p>Secure3</p><p></p><p></p><p></p><p></p><p></p><p>ABDK</p></td><td align="center"><p>Apr. 8th, 2024</p><p></p><p></p><p></p><p></p><p></p><p>July. 1st, 2024</p></td><td align="center"><p><a href="https://github.com/zkLinkProtocol/zklink-audit-report/blob/master/zkLink%20Nova/Secure3_zkLink_Nova_mergeToken_2024.4.pdf">Secure3_zkLink_Nova_mergeToken &#x26; bridgeUpdate_2024.4</a></p><p></p><p></p><p><a href="https://github.com/zkLinkProtocol/zklink-audit-report/blob/master/zkLink%20Nova/ABDK_zkLink_Mergetoken_2024.7.pdf">ABDK_zkLink_Mergetoken_2024.7.pdf</a></p></td><td>Multiple tokens with the same value can be merged into one token via the <a href="https://github.com/zkLinkProtocol/zklink-l3-contracts">smart contracts </a>deployed on the Nova network. Users can automatically merge and redeem tokens when depositing or withdrawing through the <a href="https://github.com/zkLinkProtocol/era-contracts/compare/zklink_testnet...zkLinkProtocol:era-contracts:zklink_testnet_merge">official rollup bridge. </a></td></tr><tr><td align="center"><p>Secure3</p><p></p><p></p><p></p><p></p><p></p><p>ABDK</p></td><td align="center"><p>Apr. 8th, 2024</p><p></p><p></p><p></p><p></p><p></p><p>June. 28th, 2024</p></td><td align="center"><p><a href="https://github.com/zkLinkProtocol/zklink-audit-report/blob/master/zkLink%20Nova/Secure3_zkLink%20Nova%20Arbitrator%20Upgrade_2024.4.pdf">Secure3_zkLink Nova Arbitrator Upgrade_2024.4</a></p><p></p><p></p><p><a href="https://github.com/zkLinkProtocol/zklink-audit-report/blob/master/zkLink%20Nova/ABDK_zkLink_CostOptimisation_2024.6.pdf">ABDK_zkLink_CostOptimisation_2024.6.pdf</a></p></td><td>This upgrade optimized the cost of synchronizing the batch root hash from the primary chain to the all other secondary chains. Batch root hashes are compressed to a single hash, so that the number of messages that forward via Ethereum can be be greatly reduced.</td></tr></tbody></table>

## Audited for zkSync Era

<table><thead><tr><th width="156" align="center">Auditor</th><th width="155" align="center">Time</th><th width="192" align="center">Report</th><th>Description</th></tr></thead><tbody><tr><td align="center">OpenZeppelin</td><td align="center">Jan. 2024</td><td align="center"><a href="https://blog.openzeppelin.com/december-diff-and-governance-audit">zkSync Era Governance Audit Report</a></td><td>zkLink Nova applies the same <code>Governance</code> contract used by zkSync Era. It is implemented to slow down the execution of protocol changes.</td></tr></tbody></table>


# Bug Bounty

Coming soon.


# Official Links

**Website:** <https://zklink.io/>​

**Twitter:** <https://twitter.com/zkLink_Official>        <https://twitter.com/zkLinkNova>​

**Discord:** <https://discord.gg/zklink>

**Medium:** <https://medium.com/zklinkdefi>​

**Telegram:** <https://t.me/zkLinkorg>​

**GitHub:** <https://github.com/zkLinkProtocol>


