# 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="https://4205178306-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFlYByKE7IRS1A10tIyDS%2Fuploads%2F06ot0ekYcqrO6ddKlNW7%2Fimage.png?alt=media&#x26;token=0bc71a91-c252-42c4-9661-3f8e4475f4fe" 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="https://4205178306-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFlYByKE7IRS1A10tIyDS%2Fuploads%2FgNiSwJUzasKSYuKXXzBw%2Fimage.png?alt=media&#x26;token=3d00dc57-bf70-4a5d-801b-8914f677defe" 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](https://docs.zklink.io/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="https://4205178306-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFlYByKE7IRS1A10tIyDS%2Fuploads%2FciqtQA6u49x61GVCOuX9%2Fimage.png?alt=media&#x26;token=30cd813d-4567-4f54-ae6c-5116e3cdd317" 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;
