# Introduction

zkLink X: The App-Specific Aggregated Rollup Infrastructure Built for High Performance ZK Applications.

As the blockchain space undergoes rapid advancement, there is an increasing number of layer 1 blockchains such as Ethereum, Solana, Avalanche, and Ethereum layer 2 scaling solutions including ZK-Rollups and Optimistic Rollups, where users navigate between the different L1 chains and L2 rollups to satisfy their particular requirements, utilizing a diverse range of crypto tokens.

Despite this multi-chain, multi-layer landscape creating considerable value for crypto users worldwide, it has brought unforeseen challenges. These challenges include liquidity silos that are isolated to specific chains, increased trading costs for multi-chain assets, fragmented user experience, and a complex application development environment.

1. **Liquidity fragmentation.**

   The rise of various new blockchain and rollup networks has led to fragmented liquidity. As a result, this situation of liquidity fragmentation makes it difficult for users to manage their assets and carry out transactions across chains, resulting in lower capital use rates.
2. **Multi-chain product deployment challenge**.

   As the Ethereum Layer 2 ecosystems and alternative Layer 1 chains continue to grow, they form liquidity silos. Developers, therefore, need to deploy their products on various networks in order to attract users and liquidity. However, different programming languages and tools, such as EVM, CairoVM, and Solana VM, present notable challenges to developers. Even entirely compatible protocols like multiple EVM compatible chains (Rollups) have many subtle differences.
3. **Navigation complexity and high cost.**

   Previously, users found it difficult and expensive to navigate between blockchains, for example, to swap tokenA on chainA for tokenB on chainB through a DEX. This procedure turned out to be quite intricate and involves multiple fees.

   * First, it requires the installation of a wallet and purchase of the gas token for chainB.
   * Next, users need to trade tokenA for a stablecoin or another intermediary token which can be bridged to chainB.
   * Then, users need to purchase tokenB on a local DEX.

   The emergence of numerous cross-chain asset bridge applications has improved this experience to an extent. However, the cost of cross-chain token exchange remains high, and users still struggle with conducting affordable and seamless token interactions across different chains.
4. **Security risks during inter-chain transactions.**

   Preserving asset security poses a formidable technical challenge in cross-chain transactions. For example, in recent years, cross-chain asset bridges have been one of the most susceptible components to hacks in the crypts ecosystem.

zkLink X addresses the above challenges of blockchain interoperability and standardization by building an aggregated rollup infrastructure to simplify multi-chain dApp deployment, and resolve liquidity fragmentation. It leverages zero-knowledge proof technology to provide an App Rollup deployment solution with high throughput, low-cost, and robust security.

By harnessing the potential of zero-knowledge proof technology, the zkLink X features key functionalities such as:

* Multi-chain liquidity aggregation across L1 blockchains and L2 rollups.
* Quick multi-chain product deployment with SDK and APIs.
* A trading-specific-zkVM, empowering high-throughput, low-cost App Rollup solution for high performance financial applications such as Order Book DEX.

## Key Features of zkLink X

### Native Asset Aggregation

Applications using zkLink X App-Rollup infra solution will be able to access and list the native tokens across the connected L1s and L2s, including FTs and NFTs, allowing users to trade multi-chain assets on a unified user interface. Cross-chain asset bridges are not needed in the process, thus avoiding cross-chain asset bridging risks and bridging fees.

At the same time, multi-chain token portfolios can be managed with a single wallet. For instance, Alice deposits 2 UNI from her Metamask wallet to zkLink on Ethereum, and then deposits 3 BNB from BNB Chain to zkLink from the same wallet address — as a result, Alice will receive 2 UNI + 3 BNB under the same wallet address on the zkLink rollup network. This hypothetical example applies the same to tokens from Polygon, Starknet, zkSync, Linea, Arbitrum, Optimism, Scroll, and Solana, etc. Therefore, users can easily manage their multi-chain token portfolios using a single wallet with a simplified user experience.

### Liquidity Unification

Tokens issued on different L1 chains and L2 rollups by the same entity, for instance, USDT ERC20, USDT BEP20, USDT ARB, etc — will be merged into a single USDT token in the zkLink App Rollups.

The same applies for ETH. As ETH is the native asset for Ethereum and all the Ethereum layer 2 networks, ETH from Ethereum, zkSync, and Starknet, etc., will be merged into a single ETH token, thus eliminating chain disparities.

In summary, tokens of the same kind but issued on various chains will be merged into one single token, fostering unified and aggregated liquidity.

### Customizable App Rollup Deployment

zkLink X decouples the four layers of the rollup framework and provides fast and customized rollup deployment solution. zkLink is focused on the development of execution layer plus settlement layer, and will integrate third party modular solutions for DA layer and sequencing layer, allowing developers to customize the key components to meet diverse demands of different use cases.

* **Network Collections and Settlement Layer Solution:** Developers can choose which chains the App Rollup can access to. Two settlement schemes (i.e. Nexus and Origin) are available to meet specific requirements on chain selection, finality speed, and security.
* **Execution Environment**: TS-zkVM.
* **Decentralized Sequencer**: Espresso, Astria, Fairblock, etc.
* **Modular DA Solutions**: In addition to Ethereum, developers can choose Celestia, EigenDA, Polygon Avail, DAC organized by zkLink, etc.


# Overview

<figure><img src="/files/59OPxJcctGqDreUtrCiq" alt="zkLink Protocol Architecture Overview"><figcaption><p>zkLink X Architecture Overview</p></figcaption></figure>

As shown in the figure above, zkLink X is a multi-chain ZK-Rollup Infrastructure composed of four layers: the settlement layer, the execution layer, the sequencing layer, and the DA layer. These four layers are decoupled for customizable App Rollup deployment.

The following sections will introduce zkLink X from the perspective of the four layers. It is important to note that the core value proposition and most innovations of the zkLink X are related to the execution layer solutions and the settlement layer solutions.

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Settlement Layer</strong></td><td><a href="/pages/94LDkvRVEjXVAILcsUm1">/pages/94LDkvRVEjXVAILcsUm1</a></td></tr><tr><td align="center"><strong>Execution Layer</strong></td><td><a href="/pages/BCjU6A8Z4TCid3MrOqOU">/pages/BCjU6A8Z4TCid3MrOqOU</a></td></tr><tr><td align="center"><strong>Sequencing Layer</strong></td><td><a href="/pages/dm8uUCOlaDSN7nD9QDQo">/pages/dm8uUCOlaDSN7nD9QDQo</a></td></tr><tr><td align="center"><strong>DA Layer</strong></td><td><a href="/pages/L3FEdFnIw6oCrS3aeoky">/pages/L3FEdFnIw6oCrS3aeoky</a></td></tr></tbody></table>


# TransactionFlow

This section explains the end-to-end lifecycle of a transaction in zkLink X–based applications such as ApeX Omni, from when a user initiates it to when it is finally settled on Layer 1.\
You can read this together with the diagram (User Wallet / APEX / zkLink Validator / Prover / zkLink Contract).

<figure><img src="/files/AW4bem0Tdhf8sWdzaZRb" alt="zkLink-x Protocol transaction flow"><figcaption><p>zkLink-x Protocol transaction flow</p></figcaption></figure>

***

## 1. Participants

* **User Wallet**\
  The address that holds the private key, signs requests, and receives funds.
* **APEX (Application / Matching Engine Layer)**\
  A trading application built on zkLink X, responsible for:
  * Receiving user instructions (place order, cancel order, etc.);
  * Managing the order book and matching orders;
  * Sending transaction requests to the zkLink Validator.
* **zkLink Validator (Validator / Sequencer)**\
  A component of the zkLink X protocol layer, responsible for:
  * Receiving and ordering transactions from applications;
  * Executing transactions and updating Layer 2 state;
  * Requesting zero-knowledge proofs from the Prover;
  * Submitting proven state updates to the zkLink contract.
* **Prover**\
  Generates zero-knowledge proofs (ZKPs) to attest to the correctness of a batch of transactions.
* **zkLink Contract (Layer 1 Contract)**\
  The zkLink smart contracts deployed on public chains such as Ethereum, responsible for:
  * Custody of user funds (deposits/withdrawals);
  * Verifying zero-knowledge proofs;
  * Recording the latest state root.

***

## 2. Overview of the Three Main Flows

In the diagram you can see three main types of interactions (labeled with letters):

* **Series a: Transaction requests and status feedback (Application Layer ⬄ Protocol Layer)**
* **Series b: Proof generation and submission (Protocol Layer ⬄ Prover ⬄ Contract)**
* **Series c: Deposits and withdrawals (User Wallet ⬄ zkLink Contract)**

We’ll explain each in turn.

***

## 3. Transaction Requests and Feedback (a1–a3)

### a1. User Wallet → APEX: Request

1. The user performs an action in the ApeX frontend (e.g., place order, cancel order, adjust position).
2. The frontend asks the user to sign the request with their wallet:
   * To prove that this operation is authorized by that address;
   * To prevent the application from forging user instructions.
3. The signed request is sent to the APEX backend.

### a2. APEX → zkLink Validator: Send Transaction

1. APEX packages the user’s request into the zkLink X Layer 2 transaction format.
2. It submits these transactions to the zkLink Validator:
   * The Validator performs basic checks (signature, format, balance, etc.);
   * Valid transactions are added to the current pending batch.

### a3. zkLink Validator → APEX: Return Transaction Status

1. The Validator executes the transactions on Layer 2 and updates its internal state:
   * Updates balances, positions, order statuses, etc.;
   * Temporarily records them in an off-chain state tree.
2. After execution, the Validator returns the result to APEX:
   * Success: includes fill details, latest positions, etc.;
   * Failure: returns the error reason (insufficient balance, abnormal price, etc.).
3. APEX updates the UI based on the result and shows the latest state to the user.

> Note: At this point, the state still only exists on Layer 2. Final security is guaranteed later by the **series b ZK proofs + Layer 1 submission**.

***

## 4. Zero-Knowledge Proofs and Block Synchronization (b1–b4)

### b1. zkLink Validator → Prover: Proof Request

When a sufficient number of transactions has accumulated:

1. The Validator bundles the execution trace of this batch and the corresponding state changes;
2. It sends a proof request to the Prover, asking it to generate the relevant zero-knowledge proof.

### b2. Prover → zkLink Validator: Return Proof

1. The Prover generates a ZKP based on the batched transactions and execution results:
   * Proving that all transactions follow the protocol rules;
   * Proving that no coins are created out of thin air, and balances never go negative;
   * Proving that the overall state transition is correct.
2. Once generated, the proof is returned to the Validator.

### b3. zkLink Validator → zkLink Contract: Send Proof

1. The Validator submits the following for this batch to the Layer 1 zkLink Contract:
   * The new state root;
   * Relevant public data (such as transaction digests);
   * The corresponding ZK proof.
2. The contract verifies the ZKP on-chain:
   * If verification succeeds → it accepts the new state root, which is treated as final;
   * If verification fails → it rejects the batch and the funds’ state remains unchanged.

### b4. zkLink Validator → zkLink Contract: Sync Block Status

After the proof is accepted:

1. The contract records the new state root and block information;
2. All transactions in this batch are “settled” at once from the Layer 1 perspective;
3. Subsequent withdrawals, forced exits, and similar operations will be based on this state root.

> Only at this point has a transaction completed the full loop from **Layer 2 execution** to **final settlement on Layer 1**.

***

## 5. Deposit and Withdrawal Flows (c1–c2)

### c1. User Wallet → zkLink Contract: Deposit

1. The user chooses to deposit via the ApeX frontend or a generic zkLink frontend;
2. The user’s wallet sends an on-chain transaction directly to the zkLink Contract:
   * For example, transferring USDC, ETH, or other tokens to the contract;
3. After the deposit succeeds:
   * The funds are locked in the zkLink Contract;
   * In a later batch, the zkLink Validator syncs this deposit into the user’s Layer 2 balance.

### c2. zkLink Contract → User Wallet: Withdrawal

Withdrawals typically fall into two categories:

1. **Normal Withdrawal (Standard Path)**
   * The user submits a withdrawal request in the frontend;
   * The Validator deducts the funds from the user’s Layer 2 balance and updates the state in the next batch;
   * After the batch proof is verified, the contract sends the actual transfer to the user’s wallet based on the confirmed state.
2. **Forced Withdrawal / Priority Queue**
   * If the application layer is unavailable or the user wants to bypass it,\
     they can call the zkLink contract’s priority exit interface on Layer 1 directly (such as `requestFullExit`);
   * The Validator must handle this within a specified time; otherwise, the system enters Emergency Mode (Exodus Mode),\
     and users can withdraw their funds directly from the contract using a Merkle proof (see the security section for details).

In both cases, **the actual movement of funds is always executed by the zkLink Contract on Layer 1**.\
The Validator only maintains state on Layer 2 and submits proofs; it cannot directly move user funds.

***

## 6. Summary: A Secure Loop from Trading to Settlement

To summarize, the zkLink X transaction flow can be described as:

1. **User-signed authorization → Application sends transaction → Validator executes and returns result** (a1–a3);
2. **Validator requests the Prover to generate a ZK proof and submits the proven state to Layer 1** (b1–b4);
3. **User funds are always held in the zkLink Contract and linked to Layer 2 state via deposits/withdrawals** (c1–c2).

Thanks to Layer 1 contract custody and ZK proofs:

* Even if an individual application (such as ApeX) goes down or shuts down, funds remain safe;
* The zkLink Validator cannot forge state or misappropriate user assets;
* Users can always retrieve their assets from zkLink X back to Layer 1 through the contract mechanisms.


# Settlement Layer

A classic ZK-Rollup network typically selects a single chain, i.e, Ethereum as the settlement layer to verify the proofs and settles the transactions. The settlement layer maintains the security and integrity of off-chain transactions.

In order to securely aggregate liquidity and native assets across L1s and L2s, zkLink introduces two new paradigms of settlement layer deployment solutions to its rollup infra framework - zkLink Nexus and zkLink Origin.

<table data-view="cards"><thead><tr><th></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>Working Principal of A Multi-Chain ZK-Rollup</td><td></td><td></td><td><a href="/pages/FlfDWZTmNXnuFzrVbPhc">/pages/FlfDWZTmNXnuFzrVbPhc</a></td></tr><tr><td>Nexus: Settlement on ETH ZK-L2s</td><td></td><td></td><td><a href="/pages/QH3dnFvk31IMA3ftvZhU">/pages/QH3dnFvk31IMA3ftvZhU</a></td></tr><tr><td>Origin: Settlement on ETH and Alt-L1s</td><td></td><td></td><td><a href="/pages/TgxKIrnoFbqXGElBkOJf">/pages/TgxKIrnoFbqXGElBkOJf</a></td></tr></tbody></table>


# Working Principal of A Multi-Chain ZK-Rollup

<figure><img src="/files/Y4vl9AL95w1wIKoNWIBH" alt=""><figcaption><p>Working principal of a multi-chain ZK-Rollup</p></figcaption></figure>

In comparison to a classic ZK-Rollup architecture, zkLink proposes a new type of ZK-Rollup architecture which requires to deploy the rollup contracts on multiple L1 blockchains and L2 networks at the same time, thus is called a multi-chain ZK-Rollup.

In the architecture of a multi-chain ZK-Rollup, in order to optimize the verification cost, one chain among the connected chains will be designated as the **primary chain**, which is responsible for ZKP verification. While the other chains will act as **secondary chains** that do not need to execute ZKP verification, through **multi-chain state synchronization**, it is equivalent to completing the verification on all chains.

The working principal of a classic ZK-Rollup settlement typically contains three stages: the Commit stage, Prove stage, and Execute stage. zkLink multi-chain ZK-Rollup architecture adds a Synchronize stage after the Prove stage.

The 4 stages are briefly described as below:

**1. Commit:** The sequencer submits the rollup data (excluding off-chain transaction data in Validium mode) to the primary chain, where the contract on the primary chain processes zero knowledge proof verification. Transactions related to secondary chains will be submitted to the primary chain as well.

**2. Prove:** ZKPs are submitted to the primary chain and verified by the smart contract. This process occurs only on the primary chain (Please note the primary chain is required to have the capability to verify zk-SNARKs proofs). For multi-chain ZK-Rollup, the transaction information related to all secondary chains will also be used by the smart contract for proof verification.

**3. Synchronize:** The purpose of the Synchronize stage is to achieve states synchronization across the connected chains. After completing ZKP verification, the primary chain calculates the sync hashes for the different secondary chains, based on their transaction information received from the sequencer. Each secondary chain also calculates its own sync hash. If the sync hashes calculated from different sources are consistent, all connected chains will be notified that they can proceed with transaction settlement and asset withdrawal.

**4.Execute:** This step aligns with the typical process found in a classic ZK-Rollup, which involves approving requests for fund withdrawals.


# Nexus: Settlement on ETH L2s

A zkLink Nexus L3 rollup settles the transactions and transition of states on Ethereum's L2s, and the L2s settle on Ethereum. The smart contract on Ethereum plays the key role to check if sync hashes from different rollups are consistent.

<figure><img src="/files/l8PnnJcRgMoyaWokjvUW" alt=""><figcaption><p>Security inheritance of zkLink Nexus</p></figcaption></figure>

The settlement process of a Nexus L3 rollup is shown above. Nexus rollup posts data and ZKP to the connected L2s, where the correctness of the states and transactions is verified via the verifier contract.

Since the correctness of the states and transactions of L2s will be finalized on Ethereum via validity proof (for ZK-Rollup L2s) & fraud proof (for Optimistic-Rollup L2s), and multi-chain state synchronization is finalized via Ethereum, it could be stated that a zkLink Nexus L3 rollup inherits the security of Ethereum.


# Origin: Settlement on ETH and Alt-L1s

In contrast to Nexus, zkLink Origin's architecture allows for the integration with Alt-L1s.

A zkLink Origin rollup will settle the transactions and transition of states on all the chains connected, as long as one of the networks (designated as primary chain) supports zk-SNARKs proof verification, and there is a secure and fast way to achieve states synchronization across the networks.

To establish a fast and secure communication mechanism between different chains, zkLink introduces a Light Oracle Network for cross-chain message transfer. The security assumption of zkLink Origin mode is that the rollup sequencers, responsible for packaging transactions, cannot collude with all nodes of the Light Oracle Network for malicious activities.


# Multi-Chain State Synchronization

## 1. Deposit fraud prevention: Multi-chain infra security challenge

The main challenge of building a App-Rollup deployed across various networks is the risk of **deposit fraud**. When having multiple chains or rollups in the same setup, each network is isolated – they are not able to perceive the states of the others because they can not directly access external information.

A bad sequencer may falsely inform the primary chain about a fake deposit on one secondary chain, e.g, the sequencer may inform the primary chain about a 100 USDT deposit on a secondary chain which may not exist. In such scenarios, without effective verification mechanisms, it could lead to loss of user funds.

The challenge centers on guaranteeing the states consistency between the primary chain and the secondary chains. To address this issue, we need a verification mechanism that is both fast and secure, ensuring all chains stay synchronized, and no one can alter or falsify information.

## 2. Nexus solution: multi-chain state synchronization via Ethereum

The network connected with zkLink Nexus have to be Ethereum or its Layer 2 rollups, which communicates with Ethereum through the official rollup bridges that are trustless.

Firstly, zkLink Nexus L3 sequencer will commit state and proof to the primary chain(assuming Linea is the primary chain) and secondary chains in step 1, 2, 3, as is shown in the figure below.

Secondly, the primary chain Linea computes the sync hash of Starknet and zkSync (secondary chains) through the transactions it received, and posts it to the Ethereum contract in step 4. In the meantime, the secondary chains, Starknet and zkSync will compute and post their sync hashes representing their transaction history to the Ethereum contract in steps 5 and 6.

Thirdly, the Ethereum contract will compare the sync hash from Linea with the sync hashes from Starknet and zkSync. If they match, confirmation messages will be sent to the contract on the three L2s through their official Ethereum rollup bridges in steps 7, 8, and 9.

This messaging mechanism allows for a secure and effective synchronization of states cross-L2s, ensuring that deposit fraud issues on the secondary chains are prevented.

<figure><img src="/files/osD6XFvl8eNjRIZfHkwG" alt=""><figcaption><p>zkLink Nexus cross-rollup states synchronization process</p></figcaption></figure>

## 3. Origin solution: cross-chain state synchronization via Light Oracle Network

zkLink Origin introduces a light oracle network to facilitate the cross-chain transfer of sync hashes. The light oracle network consists of independent cross-chain general message service providers such as LayerZero, zkBridge, Chainlink, etc., which ensures decentralization of the message transfer process.

As shown in the figure below, the zkLink Origin Rollup sequencer will firstly commit state and proof to the primary chain and secondary chains in steps 1, 2, and 3.

Secondly, the secondary chains will post their sync hash to Linea through the light oracle network service in steps 4, 5, and 6.

Thirdly, the Primary contract computes the sync hash of all other secondary chains and compares them with the sync hashes from the secondary chains. If they match, confirmation messages will be sent back to all secondary chains through the light oracle network in steps 7, 8, and 9.

Through the process described above, the cross-chain states are synchronized fast and secure.

In addition, a user that deploys significant capital to a zkLink Orgin Rollup could apply to run a node service of the light oracle network, which will completely eliminate the risk of multi-chain deposit fraud.

<figure><img src="/files/YhUuPCEcwetvMalRlil3" alt=""><figcaption><p>zkLink Origin cross-chain state synchronization process</p></figcaption></figure>


# In-Detail: Nexus Multi-Chain State Synchronization

In zkLink's Nexus mode, multi-chain state synchronization is achieved by transmitting sync hashes. This process is facilitated by an official message bridge, also known as a canonical message service, which is deployed by the Layer2 Network team. Once these sync hashes from various chains are received on the Ethereum mainnet, they undergo a consistency check. Upon successful verification, the confirmation information is relayed back to the Layer2 network via the same official message bridge.

<figure><img src="/files/UzjOHiGxnJRQBPOW9kg3" alt="Nexus Multi-Chain State Synchronization"><figcaption><p>Nexus Multi-Chain State Synchronization</p></figcaption></figure>

{% hint style="warning" %}
For simplicity and ease of understanding, the above diagram uses only two zkRollup Layer2s as examples and does not represent the actual network deployment scenario.
{% endhint %}

### Contracts deployed by zkLink Protocol

The zkLink Protocol deploys several contracts, as featured in the image above, which include:

* **zkLink Main Contract:** This is the principal contract of zkLink, encompassing functions for user deposits, zk verification, and sync hash.
* **Linea L1 Gateway, zkSync Era L1 Gateway :** These gateway contracts which are deployed on the Ethereum Mainnet, are tasked with comparing the sync hash and forwarding the results to the zkLink Main Contract on Layer2 Network via the official message bridge.
* **Linea L2 Gateway, zkSync Era L2 Gateway:** These gateway contracts which are deployed on the Layer2 Network are responsible for sending the sync hashes to the Arbitrator contract on Ethereum through the official message bridge.
* **Arbitrator:** This contract receives and stores zkLink's sync hashes from various zk Layer2 Networks, performs consistency verification, and then uses the `confirmBlock` method to transmit the comparison results to each Layer2 Network's zkLink Main contract."

### Contracts deployed by Layer2 Network

* **Linea Canonical Message Service**
* **zkSync Era Canonical Message Service**

These are the official message bridges, deployed respectively by the zkSync Team and Linea Team, that are responsible for facilitating message transmission between the Layer2 and Ethereum.

### zkLink Sequencer

The zkLink Sequencer is responsible for executing transactions, submitting blocks, and zk proofs. During the multi-chain state synchronization phase, it is in charge of invoking contracts on different chains to drive state synchronization.

### Sync Process

The process of multi-chain state synchronization is divided into two steps:

1. **Sending Sync Hash:** The zkLink Sequencer triggers the zkLink main contracts on both zkSync Era and Linea to dispatch their respective chain's sync hash to the Arbitrator.
2. **Confirming Blocks:** After receiving the sync hashes from the different chains, the zkLink Sequencer uses the Arbitrator's ConfirmBlock method to perform consistency verification of the sync hashes. If this verification is successful, the Arbitrator transmits a confirmation message via the L1 gateway to the zkLink contracts on the various zk Rollups.

{% hint style="info" %}
The table below is the Nexus Beta Network Information.
{% endhint %}

| Deployment Chain   | Module Name           | Contract Address                           |
| ------------------ | --------------------- | ------------------------------------------ |
| Ethereum Mainnet   | Arbitrator            | 0x683669E5B6cDc6636673a5f7ddB68E20812216F5 |
| Ethereum Mainnet   | Linea L1 Gateway      | 0xaD5d729291C0d6A299E370814CA6Ce1c8C25b51c |
| Ethereum Mainnet   | zkSync Era L1 Gateway | 0x98CEDA04E4a1FDc0fd025FB73e48e609AD00673B |
| Linea Mainnet      | zkLink Main Contract  | 0xdE1Ce751405Fe6D836349226EEdCDFFE1C3BE269 |
| Linea Mainnet      | Linea L2 Gateway      | 0xb6B96964633F558980e454953474cc7435c3D78B |
| zkSync Era Mainnet | zkLink Main Contract  | 0x0669ef7718376591AE0756A56255c75D2e712d87 |
| zkSync Era Mainnet | zkSync L2 Gateway     | 0xF180DD47ad7681335c82a592EA62Fdb92446F300 |


# Supported Networks of zkLink Nexus and Origin

<table><thead><tr><th width="194"></th><th></th><th>zkLink Nexus</th><th>zkLink Origin</th></tr></thead><tbody><tr><td></td><td>Ethereum</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td>Ethereum zkRollup</td><td>zkSync Era</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>StarkNet</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>Scroll</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>Linea</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>Taiko</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>Polygon zkEVM</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>...</td><td></td><td></td></tr><tr><td>Ethereum OpRollup</td><td>Arbitrum One</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>Optimism</td><td><em>✓</em></td><td><em>✓</em></td></tr><tr><td></td><td>...</td><td></td><td></td></tr><tr><td>EVM-compatible Alt L1s</td><td>BNB Chain</td><td></td><td><em>✓</em></td></tr><tr><td></td><td>Polygon POS</td><td></td><td><em>✓</em></td></tr><tr><td></td><td>Avalanche</td><td></td><td><em>✓</em></td></tr><tr><td></td><td>...</td><td></td><td></td></tr></tbody></table>


# Security Assumptions of zkLink Nexus and Origin

|                      | Solutions                                                   | Security Assumption                                                                             |
| -------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Classic zkRollup     | zkSync Era, StarkNet, Scroll, Polygon zkEVM, Linea,Taiko... | Ethereum Equivalent                                                                             |
| Multi-chain zkRollup | zkLink Nexus                                                | Ethereum Equivalent                                                                             |
| Multi-chain zkRollup | zkLink Origin                                               | <p>The Sequencer and the Light Oracle Network</p><p>cannot collude for malicious activities</p> |

###


# Execution Layer

Execution entails executing transactions that update the state correctly. Thus, execution must ensure that only valid transactions are executed, i.e., transactions that result in valid state machine transitions.

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>TS-zkVM for App Rollup</strong></td><td><a href="/pages/b0fxzOzA4DvQ6ouCnc50">/pages/b0fxzOzA4DvQ6ouCnc50</a></td></tr></tbody></table>


# TS-zkVM for App Rollup

The TS-zkVM is a high-efficiency ZKP execution environment specifically designed for high-performance financial products such as CLOBs, and it is constructed by zkLink.

zkLink Trading-Specific-zkVM (TS-zkVM) is based on tailored core ZK circuits and Risc0 zkVM extension ZK circuits. The TS-zkVM offers high-throughput and low-cost execution for App Rollup developers. It supports various order book product features, including but not limited to spot trading, derivatives trading, NFT trading, etc.

Different developers and applications may have varying requirements for cost and security, zkLink App Rollup developers are able to compose the key components including DA, Sequencer, and Settlement layer.

<figure><img src="/files/ltkAjEhvP5Vc9mcwYoAJ" alt=""><figcaption><p>TS-zkVM architecture</p></figcaption></figure>

The diagram in the figure above shows a high-level overview of the TS-zkVM architecture, which is divided into three sub-layers.

#### 4.1.1 Storage sub-layer of TS-zkVM

The storage of zkLink protocol utilizes a Sparse Merkle Tree (SMT) to store the state. This data structure provides the system with an efficient and secure way to maintain and verify changes in the state. Compared to the SMT in the EVM, the customized and optimized SMT of zkLink TS-zkVM is more streamlined and better adapted to the needs of high-frequency financial transaction scenarios. With in-depth customization, the SMT has been specifically tailored to suit particular business needs, thereby achieving exceptional zero-knowledge proof performance.

#### 4.1.2 Execution sub-layer of TS-zkVM

The execution sub-layer of TS-zkVM is divided into two parts, each designed for different performance and scalability requirements:

* **Precompiled circuit**: Requires high performance and includes various transaction-related circuits, such as:

  * Fund Related Circuits (Deposit, Withdrawal, Transfer)
  * Spot Trading Circuits
  * Derivatives Trading Circuits
  * Derivatives Management Circuits (Liquidation, ADL, Funding)
  * Oracle Verification Circuits
  * Authorization Circuits (Passkey Verification, Social Login Verification)

  These circuits are specifically optimized to handle corresponding financial transactions, ensuring efficiency and high response speed when the system processes transactions. Each sub-circuit corresponds to different types of transaction operations or financial instruments and handles the most performance-intensive tasks.
* **Extension circuit:** The extension circuit is built using risc0 zkVM on the same Sparse Merkle Tree (SMT), and the proofs generated by the zkVM are subsequently verified by the plonk aggregation circuit in the aggregation layer. Developers can perform custom operations using risc0 zkVM, such as:

  * Grid Trading Circuits
  * Option Trading Circuits
  * Broker Trading Circuits
  * …

  A SDK based on risc0 zkVM will be provided, which includes common operations on the TS-zkVM SMT, such as: verifying a Merkle Tree Proof for a specific account, checking if the balance change of an account complies with certain patterns, etc.

  Of course, for common features like Grid Trading and Broker Trading, zkLink will have prepared corresponding circuit templates in advance to enable developers to build quickly.

#### 4.1.3 ZK Proof Aggregation sub-layer of TS-zkVM

The aggregation sub-layer is responsible for aggregating the different transaction proofs and producing a proof to verify the correctness of the entire batch of transactions, which achieves increased efficiency in proof verification and reduced on-chain costs for transactions.

<figure><img src="/files/0xWiDdfjEWjZvONcBpM7" alt=""><figcaption><p>Aggregation Detail of TS-zkVM</p></figcaption></figure>

The aggregation sub-layer is composed of the following modules:

* **Precompile Module**: This module includes trading-specified precompiled circuits, which need to be compiled into verification keys (vk). This provides the system with a flexible way to generate customized circuits for specific types of transactions and integrate them into the entire verification system.
* **SMT State Transition Circuit**: The state transition circuit uses an SMT to record states, with changes in the root representing all users' ledger changes, ensuring the correctness and consistency of the system state. Each state transition (S1, S2, S3, ..., Sn) is constrained by the circuit to generate a transition proof.
* **zkVM**: This section demonstrates how to deploy zkLink Trading-DSL contracts using risc0 zkVM to generate custom trading operations (op). This mechanism allows users to customize trading logic and ensures that these logics are correctly executed and verified.
* **PLONK Aggregator**: The PLONK aggregator is responsible for checking the consistency of state transitions and the execution layer. It integrates proofs from different sources and generates an aggregated proof. This process enhances verification efficiency and reduces the costs required for on-chain verification.
* **Proofs**: The architecture includes various types of proofs:
  * **Precompile Proof**: Ensures the correctness of the precompile layer.
  * **Transition Proof**: Ensures the correctness of state transitions.
  * **zkVM Proof**: Ensures the correctness of custom trading operations.

**Interactions Between Modules:**

* Application Specific Circuits are eventually compiled into **verification keys**, and these verification keys are stored in the root node of the vk tree.
* zkVM allows for the deployment of **Trading-DSL** contracts, generating custom trading operations.
* Precompiled circuits, risc0 zkVM, and SMT State Transition Circuits are interconnected, ensuring the correctness of each state change.
* All proofs are collected by the Aggregator and verified in the aggregation circuit — to check if the transition set commitment in the transition proof is included in the **(Algorithm id, Input, Output)** tuple vector of the precompile proof and zkVM proof, a membership proof verification is also needed in the aggregation circuit. This ultimately produces an Aggregation Proof for on-chain verification.


# Sequencing Layer

The sequencing layer is a pivotal component in rollup systems, primarily responsible for receiving user transactions, sequencing the transactions and bundling them into batches. These batches are then committed to the settlement layer. Additionally, in scenarios where the system employs an external DA layer, the sequencer also ensures efficient transmission of transaction data to the DA layer.

Similar to other rollups, App Rollups will start with a centralized sequencer model. While this approach offered 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 X 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, equitable, and efficient rollup solution to its users.


# DA Layer

> Data Availability (DA) entails making the transaction data available. DA layer is a critical component for rollups to ensure the capability to reconstruct the the rollup states when the rollup service halts unexpectedly.

Both zkLink Nexus and zkLink Origin by default support the **primary chain** as the DA layer.

Secondly, both Nexus and Origin support **Validium**, which involves an **external DA** solution. zkLink will integrate various third party modular DA solutions, such as Celestia, EigenDA, Avail, etc., to meet diverse demands from developers.

Furthermore, zkLink DAO will have the option to organize a **Data Availability Committee** (DAC). This DAC serves as another option for developers, providing an additional choice for data availability assurance.


# Developer Overview

This section is designed for dApp developers, offering a concise overview of zkLink's infra to streamline the understanding of zkLink's features for efficient dApp development and integration.

### Glossary

The Difference Between zkLink Origin and zkLink Nexus.\[go to zkLink Origin and zkLink Nexus.]

{% tabs %}
{% tab title="L1 and Layer1" %}
zkLink Origin can be deployed on top of different Layer 1s such as Ethereum, Polygon, and BSC, among others. In addition, when referring to Layer 1 (L1) in this article, we’re referring to the chain of which zkLink’s contract is deployed.

In addition, when mentioning “onChain Tx”, we’re specifically referring to transactions made by users (developers) on the Layer 1 base chain.

The chain zkLink is deployed upon and it’s subsequent native token can also be deployed to the zkLink Layer. However, this scenario isn’t a cross-chain bridge, but rather a Rollup Bridge.
{% endtab %}

{% tab title="L2 and Layer2" %}
The deployment networks for both zkLink Origin and zkLink Nexus include Layer 2 networks such as StarkNet, zkSync, Linea, and Arbitrum, among others.

When mentioning Layer2 (L2) in this article, we’re referring to the Rollup Network deployed by the zkLink contract and the onChain Tx specifically refers to transactions made by users (developers) on the Layer 2 network.

The Rollup to which zkLink is connected and its token can be natively deposited to the zkLink Layer.
{% endtab %}

{% tab title="L3 and zkLink Layer3" %}
Because zkLink’s deployment scenarios are mostly Layer2 networks, we define zkLink as a Layer 3. Therefore, in this article, when the term zkLink Layer is mentioned, it’s the same meaning as Layer 3.
{% endtab %}
{% endtabs %}

## Integrate Architecture

<figure><img src="/files/9bcZ7w03VQY4M8tE8aDr" alt=""><figcaption><p>figure. 1</p></figcaption></figure>

zkLink X's Multi-Chain ZK-Rollup technology is composed of both on-chain and off-chain components.

The off-chain component is termed the Off-chain State Tree, and all account states are stored in the Offchain State Tree. The zkLink Validator plays the role of maintaining the Offchain State Tree. Any change that occurs in the account state, a corresponding zero-knowledge proof (zk-proof) must be generated. A Prover is responsible for generating the zk-proof.

The on-chain component is the smart contract that’s deployed on the different chains, which is referred to as the zkLink Contract. In addition to being responsible for verifying the zero-knowledge proof, the on-chain smart contract also needs to coordinate the user’s Deposit and Withdraw actions.

Different from the zkEVM rollup, zkLink X is an application-specific Rollup. So under normal circumstances, users will not directly interact with a zkLink Validator.

### OnChain Component

There are two on-chain protocols that are currently supported by zkLink: EVM and Cairo VM.

* Processing logic related to deposits and withdrawals
* Verifying zero-knowledge proofs
* Processing interaction logic related to Data Availability (DA)
* Processing the logic of multi-chain state synchronization
  * The multi-chain state synchronization logic of zkLink Origin and zkLink Nexus are different.

### OffChain Component

* **DApp Back-end Service**: Depending on the DApp’s business type, the functions of this module will vary. For example, regarding commonly used Central Limited Order Book (CLOB) exchange, the most critical function of the DApp’s back-end service is to maintain the order book and the matching engine.
* **zkLink Validator**: The zkLink Validator is responsible for receiving and processing transactions from the DApp, and checking whether the transactions comply with the rules defined by the Circuit. The Validator is also responsible for organizing the Prover to generate a zk-proof and submit the zk-proof to the zkLink Contract. When in development, the developer does not need to care about the details of how the Validator operates, instead, the developer only needs to refer to the SDK provided by zkLink in order to quickly integrate the services provided by the Validator. In the end, this saves the developer tremendous effort.
* **Prover**: The Prover is responsible for generating the zero-knowledge proof.

***

## Quickly Understand Interaction Flows

In the following section we’ll describe the basic development process for building on zkLink Infra for users and DApp developers.

### User Interaction

In order to provide developers with the ability to quickly understand the development process on zkLink, we’ll select a sample of common operations as case examples.

#### **1. Account Creation and Activation**

The Offchain State Tree maintained by the Validator records all account and asset information. When a user makes a deposit for the first time from on-chain (whether a Layer 1 or a Layer 2) to the zkLink Layer, the Offchain State Tree will create a new Account record unit, which we refer to as an L3 Account (zkLink Account).

After creating a zkLink Account, the next step is the activation process.

Activate means that a user generate a zkLink key to operate the zkLink Account. The operation of specifying the zkLink key is called `ChangePubkey` . The user generates a pubkey hash based on the zkLink key and signs a `ChangePubkey` transaction by controlling the zkLink Account wallet (EOA or Passkey). The signature states: “the zkLink key corresponding to this pubkey hash can control my account.”

After a zkLink Validator receives the `ChangePubKey` transaction, the Circuit will verify and record the pubkey hash in the Offchain State Tree.

#### 2. User Deposit Token to Dapp

Users can directly call the zkLink Contract to perform deposit operations (generally speaking, the front-end page for user operations is provided by the DApp, and hence, from the user’s perspective, the entire process is interacting with the DApp directly).

The zkLink Validator will continue to synchronize with the Layer1 block, and after obtaining the Deposit Event, if it’s the first time the user deposits, a default account will be created. After the account and account balance are updated, the DApp will be notified through websocket (or kafka).

Since users interact directly with the chain, they will need to pay gas fees. However, if the user is using a AA Wallet, they may not need to pay the gas fee directly.

In addition, zkLink supports Passkey-based account solutions.

#### 3. User Withdraw Asset to Layer1 (Layer2)

The user is required to personally sign Withdraw Transaction (note: this is not an onChain tx, and there is no need for the user to consider gas fee issues). The user submits the Signature to the DApp, and after the DApps confirms the Signature, it is sent to the zkLink Validator.

Under normal circumstances, one would need to wait until the zkLink Validator completes steps b1/b2/b3 to implement the zero-knowledge proof and upload it to the chain before the deposit can be received. Users can also select Fast Withdraw, and after signing, the acceptor (broker) will immediately submit the payment to the user on the Layer 1 (or Layer 2). However, the user needs to pay a fee to the acceptor.

The DApp can customize the rules for the Withdrawal Fee.

#### 4. User Place Order

Taking a trading DApp as an example. The DApp maintains the Order book and the user can sign a maker (or taker) order. The DApp’s Matching Engine then is responsible for matching orders from different users. Once the matching is successful, the DApp will initiate a `ContractMatching Transaction` based on the order information from the taker and maker, and send it to the zkLink Validator.

User Place Order does not need to interact with the chain, which means that similar to Withdraw, users do not need to consider issues related to gas costs. Moreover, DApps can customize their trading fee rules and ration (zkLink Circuit will constrain the upper limit of handling fees).

### Developer Interaction

In this section, we have chosen a few scenarios that developers most care about to help quickly understand zkLink’s interaction process.

#### 1. User Deposit Token to Dapp

Users can directly call the zkLink Contract to perform deposit operations (generally speaking, the front-end for users is provided by the DApp, and hence, the entire process is the user interacting with the DApp directly).

The zkLink Validator will sustain synchronization with the Layer 1 block. After obtaining the Deposit Event, if it is the first time the user deposits, a default account will be created. After the account and balance are updated, the DApp will be notified through websocket (kafka).

Generally speaking, after receiving notification from the zkLink Validator, the DApp should maintain a copy of the user account balance data locally in the DApp.

#### 2. Matching Engine

The Matching Engine saves the order information signed by the different users. Once the matching is successful, the DApp makes a `ContractMatching Transaction` (for Spot trades, it is `Order Matching Transaction`), and sends it to the zkLink Validator. After receiving the Transaction, the zkLink Validator will immediately return it to the DApp with a message indicating whether the execution was successful.

After the DApp receives the receipt from the zkLink Validator, the transaction can be considered as settled. The DApp’s front-end page should inform the user that the transaction was successful.

For users, zkLink’s Validator process of generating proofs (b1/b2/b3) does not affect the user’s transaction speed, but only affects the execution speed of the user’s Standard Withdraw transaction. Because Standard Withdraw must wait for the transactions inside the batch to complete the zero-knowledge proof verification before it can be executed on-chain. Of course, users can also choose Fast Withdraw and complete the process promptly.

#### 3. Interact with zkLink validator

In order to give the DApp authority, zkLink defines the Submitter role where all transactions sent by the DApp to the zkLink Validator require the Submitter’s signature. Send to zklink validator via rpc call with submitter signature (L3 signature of EdDSA private key, see Private key & Signature for details)

The zkLink Validator will verify the user’s Transaction signature as well as the Submitter signature. The Transaction can only be processed after the signature verification is valid.

Note that the zkLink Validator has a whitelist of Submitter public keys in the background. Therefore, before forwarding user Transactions, one needs to provide the Submitter public key to zkLink Validator to join the whitelist. At the same time, keep the private key used as a Submitter signature appropriately.

#### 4. Transactions Users Do Not Partake In

In certain circumstances, the DApps needs to change the user status and settings, but this does not need to be initiated by the user, for example, liquidation, ADL (auto-deleveraging), funding rate, and other operations. zkLink provides the corresponding Transaction types for these operations. The operation method also requires the Submitter to sign and submit Transaction to the zkLink Validator.

### What Does The zkLink Validator Do？

#### 1. Generate Layer 3 Block

After the zkLink Validator receives a sufficient number of Transactions, it will generate a new Layer 3 block.

#### 2. Prove Layer 3 Block

The zkLink Validator will send the Layer3 Block and the witness required for generating the zk proof to the Prover. (b1/b2 in Figure 1).

#### 3. Aggregate Proofs

The zkLink Validator will recursively aggregate the zk-proofs that correspond to multiple Layer 3 Blocks to generate recursive zk-proofs. The purpose of this is to reduce the number of zk-verifications on-chain and to reduce gas costs.

#### 4. Send Proof to Layer1（Layer2）

Send the aggregated zero-knowledge proof to the chain to complete the verification of the zero-knowledge proof (b3 in Figure 1).

#### 5. Monitor onChain Event

The zkLink Validator monitors contract events on-chain, obtains the on-chain status of the signature, and changes the status of the corresponding Transaction.


# Get Started

## Quick Start

In this quick start, you'll lean how to create a DEX and take a short tour through the zkLink SDK. It is essential to follow the suggested order of topics and make sure to have a solid understanding of zkLink's architecture by reading the [overview](/developer/overview) beforehand. Additionally, to receive notifications from zkLink server, you will need to prepare the WebSocket.

Assuming there are two traders, Alice and Bob, the steps to be covered include:

* Creating accounts for Bob and Alice
* Alice deposits coin1 and Bob deposit coin2
* Alice using coin1(id=18) to buy coin2(id=19) from Bob
* Alice withdrawing half of the coin2 she just acquired

## Create Account and Deposit

zkLink will create a user account when the user makes their first deposit. The DEX will not take any action except for receiving the user account creation event and the user balance update event from the websocket. For instance, when Alice makes her first deposit, you will receive the following data:

```json
{
  "type":"TxExecuteResult",
  "txHash":"0x05f2cf78d7b7a4a6b9f3c7e0c78d0c3a97438b9806e21834ee36530eb62d30fd",
  "tx":{
    "type":"Deposit",
    "from":"0x76ed7d63d9266f07ec86d44237daca3637a6650d",
    "to":"0xd81418a80a0df6feaea04467f908bc1cb1fc5be7",
    "fromChainId":7,
    "subAccountId":2,
    "l1SourceToken":17,
    "l2TargetToken":17,
    "amount":"1000000000000000000000000000",
    "serialId":26,
    "l2Hash":"0xa0f46cc2c2ee1480350c4b1c2a3b1b70a55f799078ae1a248ed6cf71431e0270",
    "ethHash":null
  },
  "receipt":{
    "executed":true,
    "executedTimestamp":1702099337833969,
    "success":true,
    "failReason":null,
    "block":null,
    "index":null
  },
  "updates":[
    // As the to_account (accountId is 1) does not exist, an AccountCreate is involved
    {
      "type":"AccountCreate",
      "updateId":0,
      "accountId":11,
      "address":"0xd81418a80a0df6feaea04467f908bc1cb1fc5be7"
    },
    // The balance of the to_account increased, depositAmount=newBalance-oldBalance
    {
      "type":"BalanceUpdate",
      "updateId":1,
      "accountId":11,
      "subAccountId":0,
      "coinId":18,
      "oldBalance":"0",
      "newBalance":"1000000000000000000000000000",
      "oldNonce":0,
      "newNonce":0
    },
    // The 'global asset' account records the increase of on-chain asset reserves
    {
      "type": "BalanceUpdate",
      "updateId": 17,
      "accountId": 1,
      "subAccountId": 2,
      "coinId": 18,
      "oldBalance": "3030000000000000000000",
      "newBalance": "3040000000000000000000",
      "oldNonce": 0,
      "newNonce": 0
    }
  ]
}
```

Now, you can maintain a new account with the account ID '31' with a balance '1000000000000000000000000000' of a coin ID (or token ID) of '18'. Similarly, and also same of Bob’s account information. For example:

| name  | accountId | subAccountId | coin id | balance              |
| ----- | --------- | ------------ | ------- | -------------------- |
| Alice | 31        | 0            | 18      | 10000000000000000000 |
| Bob   | 32        | 0            | 19      | 10000000             |

To obtain the token ID information, you will need to query the RPC [getSupportTokens](/developer/json-rpc-and-websocket-and-kafka/json-rpc-api#getsupporttokens). For instance, you can retrieve the 'ZKL' token information from the RPC response.

```json
{
    "jsonrpc": "2.0",
    "result": {
        "1": {
            "id": 1,
            "symbol": "ZKL",
          	"usdPrice": "12.1",
            "chains": {
                "1": {
                    "chainId": 1,
                    "address": "0x1aef2b4c06b83cdb2783d3458cdbf3886a6ae7d4",
                  	"decimals": 18,
                    "fastWithdraw": false
                },
                "2": {
                    "chainId": 2,
                    "address": "0xa684f63605ccdedbce7e2e7e3fa06441758da6d1",
                  	"decimals": 10,
                    "fastWithdraw": true
                }
            }
        }
    },
    "id": 1
}
```

## Place Order

| name  | accountId | subAccountId | coin id | balance              |
| ----- | --------- | ------------ | ------- | -------------------- |
| Alice | 31        | 0            | 18      | 10000000000000000000 |
| Bob   | 32        | 0            | 19      | 10000000             |

Next, Alice and Bob place orders, and the DEX will match them and send them to zkLink. Prior to users placing orders, you need to ensure the trade pair price is prepared. You can accomplish this by obtaining oracle.

Afterward, Alice and Bob need to create an order and sign the order with the BitKeep wallet or Metamask wallet, and then send it to the DEX server.

Bob, as the maker, will create the maker order:

```js
import init, *  as wasm  from "./web-dist/zklink-sdk-web.js";

async create_maker_order() {
    await init();
    //use stand window.ethereum as metamask ..
    //await window.ethereum.request({ method: 'eth_requestAccounts' });
    //const provider = window.ethereum;
    const provider = window.bitkeep && window.bitkeep.ethereum;
    await provider.request({ method: 'eth_requestAccounts' });
    const signer = new wasm.JsonRpcSigner(provider);
    await signer.initZklinkSigner(null);
    console.log(signer);
    let account_id = 31;
    let sub_account_id = 0;
    // get the user nonce from rpc `getUser`
    let nonce = 1;
    // get the slot id from rpc `getAccountOrderSlots`
    let slot_id = 1;
    let base_token_id = 18;
    let quote_token_id = 19;
    let amount = "5000000";
    let price = "1000000000000";
    let is_sell = true;
    let maker_fee_ratio = 5;
    let taker_fee_ratio = 1;
    let maker_order = new wasm.Order(account_id, sub_account_id, slot_id, nocne, base_token_id,quote_token_id, amount, price, is_sell, maker_fee_ratio, taker_fee_ratio);
    let signed_order = signer.createSignedOrder(maker_order);
    console.log(signed_order);
}        
```

And Alice, as the taker, will create the taker order:

```js
    let account_id = 32;
    let sub_account_id = 0;
    // get the user nonce from rpc `getUser`
    let nonce = 1;
    // get the slot id from rpc `getAccountOrderSlots`
    let slot_id = 1;
    let base_token_id = 18;
    let quote_token_id = 19;
    let amount = "5000000";
    let price = "1000000000000";
    let is_sell = false;
    let maker_fee_ratio = 5;
    let taker_fee_ratio = 1;
    let taker_order = new wasm.Order(account_id, sub_account_id, slot_id, nocne, base_token_id,quote_token_id, amount, price, is_sell, maker_fee_ratio, taker_fee_ratio);
    let signed_order = signer.createSignedOrder(maker_order);
    let taker = signer.createSignedOrder(taker_order);
    console.log(taker);
```

You can obtain the user's Nonce and SlotId by using the RPC [getUser](/developer/json-rpc-and-websocket-and-kafka/json-rpc-api#getaccount) and [getAccountOrderSlots](/developer/json-rpc-and-websocket-and-kafka/json-rpc-api#getaccountorderslots) respectively.

## Prepare submitter private key

Before creating the order matching transaction, you will need to generate a submitter private key. This key will allow you to sign the OrderMatching transaction. Additionally, it's essential to notify zkLink to add the submitter public key to the whitelist. By doing so, zkLink will be able to verify the transactions' signatures from the DEX and reject those whose submitter public keys are not on the whitelist.

## Create OrderMatching Transaction

Once the taker order and the maker order are matched in the order matching engine, you can create the OrderMatching transaction. Sign the transaction with the submitter private key and then send it to zkLink using the [sendTransaction](/developer/json-rpc-and-websocket-and-kafka/json-rpc-api#sendtransaction) RPC interface.

```go
    var contractPrices = make([]sdk.ContractPrice,2)
    contractPrices[0] = sdk.ContractPrice{
        sdk.PairId(1),
        *big.NewInt(1000000000000),
    }
    contractPrices[1] = sdk.ContractPrice{
        sdk.PairId(3),
        *big.NewInt(52552131),
    }

    var marginPrices = make([]sdk.SpotPriceInfo,2)
    marginPrices[0] = sdk.SpotPriceInfo {
       sdk.TokenId(18),
       *big.NewInt(10000000),
    }
    marginPrices[1] = sdk.SpotPriceInfo {
      sdk.TokenId(19),
      *big.NewInt(10000000),
    }

    builder := sdk.OrderMatchingBuilder {
        sdk.AccountId(0),
        sdk.SubAccountId(1),
        taker,
        maker,
        
        *big.NewInt(1000),
        sdk.TokenId(18),
        *big.NewInt(808077878),
        *big.NewInt(5479779),
    }
    tx := sdk.NewOrderMatching(builder)
    signer, err := sdk.NewSigner(privateKey, sdk.L1TypeEth)
    if err != nil {
        return
    }
    txSignature, err := signer.SignOrderMatching(tx)
    if err != nil {
        return
    }
    fmt.Println("tx signature: %s", txSignature)

    // get submitter signature
    zklinkTx := tx.ToZklinkTx()
    submitterSignature, err := signer.SubmitterSignature(zklinkTx)
    submitterSignature2, err := json.Marshal(SubmiterSignature {
        PubKey: submitterSignature.PubKey,
        Signature: submitterSignature.Signature,
    })
	request := RPCTransaction {
		Id:      1,
		JsonRpc: "2.0",
		Method:  "sendTransaction",
		Params: []json.RawMessage{
		    []byte(txSignature.Tx),
		    nil,
		    submitterSignature2,
		},
    }
	JsonTx, err := json.Marshal(request)
	fmt.Println("ChangePubKey rpc request:",  string(JsonTx))
	zklinkUrl := sdk.ZklinkTestNetUrl()
	response, err := http.Post(zklinkUrl, "application/json", bytes.NewBuffer(JsonTx))
	if err != nil {
        fmt.Println(err)
    }
    defer response.Body.Close()
    body, _ := ioutil.ReadAll(response.Body)
    fmt.Println(string(body))
```

After sending the transaction to zkLink, you can receive the transaction state updates through the [WebSocket](/developer/json-rpc-and-websocket-and-kafka/websocket).

```js
"updates": [
    // Orderslot of the maker
    {
        "type": "OrderUpdate",
        "updateId": 0,
        "accountId": 31,
        "subAccountId": 0,
        "slotId": 1,
        "oldTidyOrder": {
            "nonce": 1,
            "residue": "54800000000000000"
        },
        "newTidyOrder": {
            "nonce": 2,
            "residue": "0"
        }
    },
    // The balance of token0 in the maker account decreased
    {
        "type": "BalanceUpdate",
        "updateId": 1,
        "accountId": 31,
        "subAccountId": 0,
        "coinId": 18,
        "oldBalance": "10000000000000000000",
        "newBalance": "5000000000000000000",
        "oldNonce": 1,
        "newNonce": 1
    },
    // The balance of token1 in the maker account increased
    {
        "type": "BalanceUpdate",
        "updateId": 2,
        "accountId": 31,
        "subAccountId": 1,
        "coinId": 19,
        "oldBalance": "0",
        "newBalance": "5000000",
        "oldNonce": 1,
        "newNonce": 1
    },
    // Orderslot of the taker
    {
        "type": "OrderUpdate",
        "updateId": 3,
        "accountId": 32,
        "subAccountId": 0,
        "slotId": 163,
        "oldTidyOrder": {
            "nonce": 0,
            "residue": "1467400000000000000"
        },
        "newTidyOrder": {
            "nonce": 0,
            "residue": "1412600000000000000"
        }
    },
    // The balance of token1 in the taker account decreased
    {
        "type": "BalanceUpdate",
        "updateId": 4,
        "accountId": 32,
        "subAccountId": 1,
        "coinId": 19,
        "oldBalance": "10000000",
        "newBalance": "5000000",
        "oldNonce": 1,
        "newNonce": 1
    },
    // The balance of token0 in the taker account increased
    {
        "type": "BalanceUpdate",
        "updateId": 5,
        "accountId": 32,
        "subAccountId": 0,
        "coinId": 18,
        "oldBalance": "0",
        "newBalance": "10000000000000000000",
        "oldNonce": 1,
        "newNonce": 1
    },
    // The submitter balance of token0 decreased due to transaction fees
    {
        "type": "BalanceUpdate",
        "updateId": 6,
        "accountId": 6,
        "subAccountId": 1,
        "coinId": 18,
        "oldBalance": "9999680162000000000000",
        "newBalance": "9999679771000000000000",
        "oldNonce": 224,
        "newNonce": 224
    },
    // The submitter collect token0 as transaction fee
    {
        "type": "BalanceUpdate",
        "updateId": 7,
        "accountId": 6,
        "subAccountId": 0,
        "coinId": 18,
        "oldBalance": "3529001244641983488661500000",
        "newBalance": "3529001244727972908661500000",
        "oldNonce": 224,
        "newNonce": 224
    },
    // The submitter collect token1 as transaction fee
    {
        "type": "BalanceUpdate",
        "updateId": 8,
        "accountId": 6,
        "subAccountId": 0,
        "coinId": 19,
        "oldBalance": "1594000000063937300000000000",
        "newBalance": "1594000000063964700000000000",
        "oldNonce": 224,
        "newNonce": 224
    },
    // The balance of the fee account increased
    {
        "type": "BalanceUpdate",
        "updateId": 9,
        "accountId": 0,
        "subAccountId": 0,
        "coinId": 18,
        "oldBalance": "483683000000000000",
        "newBalance": "484074000000000000",
        "oldNonce": 0,
        "newNonce": 0
    }
]
```

From the state updates, you can verify that the transaction has been successfully executed. Subsequently, you can check the users' updated balance:

| name  | accountId | subAccountId | coin id | balance             |
| ----- | --------- | ------------ | ------- | ------------------- |
| Alice | 31        | 0            | 18      | 5000000000000000000 |
| Alice | 32        | 0            | 19      | 5000000             |
| Bob   | 31        | 0            | 18      | 5000000000000000000 |
| Bob   | 32        | 0            | 19      | 5000000             |


# Examples


# Base Demo

{% embed url="<https://github.com/zkLinkProtocol/dex-simple-demo>" %}


# JSON RPC & Websocket & Kafka

Developers can send all the layer3 transactions to the zkLink and get the associated information from zkLink. zkLink also push the transaction state update via websocket to dApp.


# JSON-RPC API

dApps can get account status, send transactions, and call other functions via zkLink API.

The zkLink API follows the JSON-RPC standard and is accessed via POST.

## API OVERVIEW

{% tabs %}
{% tab title="Networks" %}

* [getSupportChains](#getsupportchains): get the configuration of all supported chains.
* [getSupportTokens](#getsupporttokens): get the data of all tokens with on-chain contract addresses.
* [getLatestBlockNumber](#getlatestblocknumber): get the latest block height info.
* [getTokenReserve](#gettokenreserve): get the withdrawable limit of a token on a certain L1 chain.
  {% endtab %}

{% tab title="SubAccount" %}

* [getSubAccountGlobalVars](#getsubaccountglobalvars): get the params of the subaccount.
  {% endtab %}

{% tab title="Block" %}

* [getBlockByNumber](#getblockbynumber): get the block info by block height.
* [getBlockOnChainByNumber](#getblockonchainbynumber): get the transaction information in a block that is executed on L1 blockchains.
  {% endtab %}

{% tab title="Account" %}

* [getAccount](#getaccount): get account info by address or account id.
* [getAccountBalances](#getaccountbalances): get the balance info of an account.
* [getAccountOrderSlots](#getaccountorderslots): get the order slot of an account.
* [getAccountSnapshot](#getaccountsnapshot): get the account states of a certain block height, including the basic info, balance info, and order slot info.
  {% endtab %}

{% tab title="Transaction" %}

* [getTransactionByHash](#gettransactionbyhash): get transaction info.
* [getAccountTransactionHistory](#getaccounttransactionhistory): get account history in descending order of the transaction id in the database.
* [getWithdrawTxs](#getwithdrawtxs): get transaction info of fast\_withdraw transactions.
* [sendTransaction](#sendtransaction): submit L2 transaction and return transaction hash.
  {% endtab %}
  {% endtabs %}

## JSON-RPC API METHODS <a href="#json-rpc-methods" id="json-rpc-methods"></a>

### getSupportChains

Get the configuration of all supported chains.

{% tabs %}
{% tab title="Request" %}
**Parameters**

None

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getSupportChains",
    "params": []
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`ChainResp`

```json
{
    "jsonrpc": "2.0",
    "result": [
      {
        "chainId":1,
        "chainType": 0,
        "layerOneChainId":1001,
        "mainContract":"0x03855e8120691526f82085453AEefac3f6A484F1",
        "layerZeroContract": "0xcb45b54BA16fBdc7092E56938225a11799eb1124",
        "web3Url": "https://rpc-mumbai.maticvigil.com",
        "feeCap": 1000000000000000000,
        "gasTokenId": 33,
        "validator": "0x526212fbd41080b455ae81014b5b6bf859c30094"
      }
    ],
    "id": 1
}
```

{% endtab %}
{% endtabs %}

**ChainResp**

<table><thead><tr><th width="225.21167883211677">Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>chainId</td><td>uint32</td><td>Defined by zkLink</td></tr><tr><td>chainType</td><td>uint8</td><td>Defined by zkLink {0:"EVM", 1:"STARKNET"}</td></tr><tr><td>layerOneChainId</td><td>uint32</td><td>The chain ID of L1 blockchains</td></tr><tr><td>mainContract</td><td>address(EVM|StarkNet)</td><td>The address of zkLink main contract that interacts with the rest module contracts</td></tr><tr><td>layerZeroContract</td><td>address(EVM|StarkNet)</td><td>The address of layerZero bridge that syncs L1 states</td></tr><tr><td>web3Url</td><td>string</td><td>The url of L1 RPC</td></tr><tr><td>feeCap</td><td>unit</td><td>The max transaction fee when L1 RPC send the transaction</td></tr><tr><td>gasTokenId</td><td>uint32</td><td>The id of the gas token, defined by zkLink</td></tr><tr><td>validator</td><td>address(EVM|StarkNet)</td><td>Validator address</td></tr></tbody></table>

### getSupportTokens

Get the data of all tokens with on-chain contract addresses.

{% tabs %}
{% tab title="Request" %}
**Parameters**

None

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getSupportTokens",
    "params": []
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`HashMap<TokenId,TokenResp>`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "1": {
            "id": 1,
            "symbol": "ZKL",
          	"usdPrice": "12.1",
            "chains": {
                "1": {
                    "chainId": 1,
                    "address": "0x1aef2b4c06b83cdb2783d3458cdbf3886a6ae7d4",
                  	"decimals": 18,
                    "fastWithdraw": false
                },
                "2": {
                    "chainId": 2,
                    "address": "0xa684f63605ccdedbce7e2e7e3fa06441758da6d1",
                  	"decimals": 10,
                    "fastWithdraw": true
                }
            }
        }
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

It returns a `HashMap<TokenId,TokenResp>`, which has a unique token id and is used for all token-related queries in the RPC service. Symbols are used only for display on the UI and do not promise uniqueness.

#### **TokenResp**

<table><thead><tr><th width="259.07751937984494">Field</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>Token id</td></tr><tr><td>symbol</td><td>Token symbol</td></tr><tr><td>usdPrice</td><td>Token price</td></tr><tr><td>chains</td><td><code>HashMap&#x3C;ChainId,ChainTokenResp></code> that includes the contract addresses on each chain</td></tr></tbody></table>

#### **ChainTokenResp**

<table><thead><tr><th width="255.19691119691117">Field</th><th>Description</th></tr></thead><tbody><tr><td>chainId</td><td>Defined by zkLink</td></tr><tr><td>address</td><td>The on-chain contract address of the token</td></tr><tr><td>decimals</td><td>The decimals of the token on L1</td></tr><tr><td>fastWithdraw</td><td>Whether the token supports fast withdraw</td></tr></tbody></table>

The decimal is the accuracy of the token on L1, which is not always 18 (6 for USDC and 18 for ZKL), and varies on different chains for the same token (6 for USDC on Ethereum and 18 for USDC on BSC).

When a user deposits to zkLink from connected networks, the front-end needs to calculate the amount required for calling the contract according to the accuracy:

```json
var amount_of_user_input = 1.0 // input from the user
var amount_to_call_contract = amount_of_user_input * 10 ** token.decimals // the parameter during calling the contract
// Example
// A user deposits 2 USDC, the parameter is 2 * 10^6
// A user deposits 5 ZKL, the parameter is 5 * 10^18
```

### getSubAccountGlobalVars

Get the global variables information of a specific sub-account.

{% tabs %}
{% tab title="Request" %}
**Parameters**

| Name                | Type         | Description                         |
| ------------------- | ------------ | ----------------------------------- |
| sub\_account\_query | SubAccountId | The ID of the sub-account to query. |

```json
{ 
  "id": 1, 
  "jsonrpc": "2.0", 
  "method": "getSubAccountGlobalVars", 
  "params": [1]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`GlobalVarsResp`

```json
{
  "jsonrpc": "2.0",
  "result": {
    "subAccountId": 1,
    "feeAccount": 100,
    "insuranceFundAccount": 101,
    "marginParams": {
      "1": {
        "token_id": 1,
        "symbol": "USDC",
        "index_price": "1000000000000000000",
        "ratio": 50
      }
    },
    "contractParams": {
      "1": {
        "symbol": "BTC-USDC",
        "mark_price": "30000000000000000000000",
        "initial_margin_rate": 1000,
        "maintenance_margin_rate": 500,
        "acc_funding_price": "-1000000000000000000",
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

#### **GlobalVarsResp**

| Field                | Type              | Description                                                                                                                                                                            |
| -------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| subAccountId         | SubAccountId      | The ID of the queried sub-account.                                                                                                                                                     |
| feeAccount           | AccountId \| null | The ID of the fee account associated with the sub-account, if any.                                                                                                                     |
| insuranceFundAccount | AccountId \| null | The ID of the insurance fund account associated with the sub-account, if any.                                                                                                          |
| marginParams         | MarginParams      | A map of margin parameters for different margin IDs. Each entry contains details like token ID, symbol, index price, and ratio.                                                        |
| contractParams       | ContractParams    | A map of contract parameters for different pair IDs. Each entry contains details like symbol, mark price, initial margin rate, maintenance margin rate, and accumulated funding price. |

### getLatestBlockNumber

Get the latest block height info.

{% tabs %}
{% tab title="Request" %}
**Parameters**

None

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getLatestBlockNumber",
    "params": []
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`BlockNumberResp`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "lastBlockNumber": 2,
        "timestamp": 1663488014,
        "committed": 1,
        "verified": 0 
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

#### **BlockNumberResp**

<table><thead><tr><th width="234.55555555555554">Field</th><th>Description</th></tr></thead><tbody><tr><td>lastBlockNumber</td><td>The block height of the latest batch</td></tr><tr><td>timestamp</td><td>The timestamp of the last block</td></tr><tr><td>committed</td><td>The block height of the latest block committed to L1</td></tr><tr><td>verified</td><td>The block height of the latest block executed on L1</td></tr></tbody></table>

### getBlockByNumber

Get the block info by block height.

{% tabs %}
{% tab title="Request" %}
**Parameters**

* `blockNumber`: the block height, and returns the latest block height if null
* `includeTx` : whether contains transaction details: returns transaction hash if false. only successful transactions will be included in a block. call `getTransactionByHash` to query the failed transactions.
* `includeUpdate`: whether contains the state change by transactions; valid only when `includeTx` is true.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getBlockByNumber",
    "params": [
      123, 
      true, 
      true 
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`BlockResp`

```json
{
  "jsonrpc": "2.0",
  "result": {
    "number": 14127,
    "commitment": "0x052fdba72bbb6fcc10940fc22dc76e459dda32604a17a920b8f2d2d0f0caff8f",
    "rootHash": "0x2a5bb557a7b39afc2480b84c56f230ac2be6148fc367edf5f9447e3521a0da56",
    "feeAccountId": 0,
    "blockSize": 20,
    "opsCompositionNumber": 401,
    "createdAt": "2023-02-04T04:41:35Z",
    "transactions": [
      {
        "txHash": "0x7c85b50664efb9672613b2b3ceafd6e1f9f47938053690b885f0a8071fac1ffa",
        "tx": {
          "type": "Deposit",
          "fromChainId": 2,
          "from": "0x3d809e414ba4893709c85f242ba3617481bc4126",
          "subAccountId": 0,
          "l1SourceToken": 18,
          "l2TargetToken": 18,
          "amount": "10000000000000000000",
          "to": "0xb92a8ba62ff1d141798c7133cccefb33d9073323",
          "serialId": 22,
          "ethHash": "0x6ac27ec5de06c51dc9f167aa13424d08026953c9706d39c72d64cabe59ad7266"
        },
        "executedTimestamp":1689731233,
        "updates": [
          {
            "type": "AccountCreate",
            "updateId": 15,
            "accountId": 4,
            "address": "0xb92a8ba62ff1d141798c7133cccefb33d9073323"
          },
          {
            "type": "BalanceUpdate",
            "updateId": 16,
            "accountId": 4,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "0",
            "newBalance": "10000000000000000000",
            "oldNonce": 0,
            "newNonce": 0
          },
          {
            "type": "BalanceUpdate",
            "updateId": 17,
            "accountId": 1,
            "subAccountId": 2,
            "coinId": 18,
            "oldBalance": "3030000000000000000000",
            "newBalance": "3040000000000000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      },
      {
        "txHash": "0x7aaf7535c5edecf19805b6395e92865c544f387c71d8f75648d0353100a821f6",
        "tx": {
          "type": "FullExit",
          "toChainId": 1,
          "accountId": 28,
          "subAccountId": 1,
          "exitAddress": "0xae08c2e27765faef5cb05908dbac12242caf91af",
          "l2SourceToken": 44,
          "l1TargetToken": 44,
          "serialId": 28,
          "ethHash": "0x57b1fda1f7dd3aac85af60dc69300e0209c0a6abadc047a8f88e0a894220ba82"
        },
        "executedTimestamp":1689731234,
        "updates": [
          {
            "type": "BalanceUpdate",
            "updateId": 0,
            "accountId": 28,
            "subAccountId": 1,
            "coinId": 44,
            "oldBalance": "1080000000000000000",
            "newBalance": "0",
            "oldNonce": 0,
            "newNonce": 0
          },
          {
            "type": "BalanceUpdate",
            "updateId": 1,
            "accountId": 1,
            "subAccountId": 1,
            "coinId": 44,
            "oldBalance": "1497300000000000000000",
            "newBalance": "1496220000000000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      },
      {
        "txHash": "0x7c2dab9dadc2f3471b71c5531bfa70d0a67d16df62cfd6ed43b5970b3dccf7ad",
        "tx": {
          "type": "ChangePubKey",
          "chainId": 2,
          "accountId": 2,
          "subAccountId": 0,
          "newPkHash": "0x870b67b523f93dad7a313f6b64b9608dedab3874",
          "feeToken": 18,
          "fee": "1000000000000000000",
          "nonce": 0,
          "signature": {
            "pubKey": "5f07954b65b5407a37ec0a2c54fb4647e2014475936057bb2f52a6faab938b02",
            "signature": "4ad95ddd573830c2e85065ee201e503b24fb56faeedc1790e8a35668805d7b00691cb8c78ce124fbe0c15ed903c72975750eb12f74a5c711b870fba3496f0402"
          },
          "ethAuthData": {
            "type": "EthECDSA",
            "ethSignature": "0xf8aa40b44c89e3be8a07fc25e90b9c069fde2f3fb01125f9a8683fba054b5b4961ccbc6e957fda303c64868d9f6bc3b0f8c55a38137195633f330573a813a5d31b"
          },
          "ts": 1677821209
        },
        "executedTimestamp":1689731235,
        "updates": [
          {
            "type": "AccountChangePubkeyUpdate",
            "updateId": 8,
            "accountId": 2,
            "oldPubkeyHash": "0x0000000000000000000000000000000000000000",
            "newPubkeyHash": "0x870b67b523f93dad7a313f6b64b9608dedab3874",
            "oldNonce": 0,
            "newNonce": 1
          },
          {
            "type": "BalanceUpdate",
            "updateId": 9,
            "accountId": 2,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "10000000000000000000",
            "newBalance": "9000000000000000000",
            "oldNonce": 1,
            "newNonce": 1
          },
          {
            "type": "BalanceUpdate",
            "updateId": 10,
            "accountId": 0,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "0",
            "newBalance": "1000000000000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      },
      {
        "txHash": "0xa2fa942af20e3ea1764158470a9f1f5609280dcd73cad5497ecf5ec20e8cad83",
        "tx": {
          "type": "Transfer",
          "accountId": 2,
          "fromSubAccountId": 0,
          "toSubAccountId": 1,
          "to": "0xdc9c9863167ee865edd5216964b8b99d43ee7a81",
          "token": 18,
          "amount": "1000000000000",
          "fee": "209000000000000",
          "nonce": 115,
          "signature": {
            "pubKey": "5f07954b65b5407a37ec0a2c54fb4647e2014475936057bb2f52a6faab938b02",
            "signature": "d6501c14f1ed8e3feeb4c3242697067dd60da0c56af544c8faeb2d055a21d3059c78c320008028f37fedc4d9578553782b2fd204610da670d1326a277dac2004"
          },
          "ts": 1677821506
        },
         "executedTimestamp":1689731236,
        "updates": [
          {
            "type": "BalanceUpdate",
            "updateId": 12,
            "accountId": 2,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "3018976060000000000000",
            "newBalance": "3018975850000000000000",
            "oldNonce": 115,
            "newNonce": 116
          },
          {
            "type": "BalanceUpdate",
            "updateId": 13,
            "accountId": 2,
            "subAccountId": 1,
            "coinId": 18,
            "oldBalance": "114000000000000",
            "newBalance": "115000000000000",
            "oldNonce": 115,
            "newNonce": 116
          },
          {
            "type": "BalanceUpdate",
            "updateId": 14,
            "accountId": 0,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "1023826000000000000",
            "newBalance": "1024035000000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      },
      {
        "txHash": "0x3b285c94d89ae17f7c288b10036a3dacff3460384601005afb440b1620bb538a",
        "tx": {
          "type": "Withdraw",
          "toChainId": 1,
          "accountId": 3,
          "subAccountId": 0,
          "to": "0x3d809e414ba4893709c85f242ba3617481bc4126",
          "l2SourceToken": 44,
          "l1TargetToken": 44,
          "amount": "1300000000000000000",
          "fee": "1531000000000000",
          "nonce": 81,
          "signature": {
            "pubKey": "b720c6110e673b55b5725dd0ff5778a8668ef4c7324718f78fa11def63081e85",
            "signature": "ec2c25aded9d1bbc85106178917a9da55a711449b4a49d0dbc01485290959225739ef0b3155498e96ba79cfbcb4a79a5f3ea4a179c6c210baca86820e8020b05"
          },
          "fastWithdraw": 1,
          "withdrawFeeRatio": 2000,
          "ts": 1677830493
        },
        "executedTimestamp":1689731237,
        "updates": [
          {
            "type": "BalanceUpdate",
            "updateId": 3,
            "accountId": 3,
            "subAccountId": 0,
            "coinId": 44,
            "oldBalance": "2993839561700000000000",
            "newBalance": "2992538030700000000000",
            "oldNonce": 81,
            "newNonce": 82
          },
          {
            "type": "BalanceUpdate",
            "updateId": 4,
            "accountId": 1,
            "subAccountId": 1,
            "coinId": 44,
            "oldBalance": "1500000000000000000000",
            "newBalance": "1498700000000000000000",
            "oldNonce": 0,
            "newNonce": 0
          },
          {
            "type": "BalanceUpdate",
            "updateId": 5,
            "accountId": 0,
            "subAccountId": 0,
            "coinId": 44,
            "oldBalance": "438300000000000",
            "newBalance": "1969300000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      },
      {
        "txHash": "0x8ada34680c8ba0e5cdbc14011e51c9989cab9339e0a7e679d14c14e7a587149d",
        "tx": {
          "type": "ForcedExit",
          "toChainId": 2,
          "initiatorAccountId": 3,
          "initiatorSubAccountId": 0,
          "target": "0x086cacda48e8a77680ba1e79177d1655f7130c95",
          "targetSubAccountId": 1,
          "l2SourceToken": 40,
          "l1TargetToken": 40,
          "fee": "19030000000000000",
          "feeToken": 18,
          "nonce": 178,
          "signature": {
            "pubKey": "b720c6110e673b55b5725dd0ff5778a8668ef4c7324718f78fa11def63081e85",
            "signature": "b119bd5971397b6abc499f6a2c09358b8c39d937be5bc96e3f186b4fc5026c80a933eea1b8f9c71cab8bb10ae554a2765008b937a724d026512f97cbeeacef05"
          },
          "ts": 1677836553
        },
        "executedTimestamp":1689731238,
        "updates": [
          {
            "type": "BalanceUpdate",
            "updateId": 20,
            "accountId": 3,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "2790050120799999999999",
            "newBalance": "2790031090799999999999",
            "oldNonce": 178,
            "newNonce": 179
          },
          {
            "type": "BalanceUpdate",
            "updateId": 21,
            "accountId": 15,
            "subAccountId": 1,
            "coinId": 40,
            "oldBalance": "2100000000000000000",
            "newBalance": "0",
            "oldNonce": 0,
            "newNonce": 0
          },
          {
            "type": "BalanceUpdate",
            "updateId": 22,
            "accountId": 1,
            "subAccountId": 2,
            "coinId": 40,
            "oldBalance": "4000001486590000000000000000",
            "newBalance": "4000001484490000000000000000",
            "oldNonce": 0,
            "newNonce": 0
          },
          {
            "type": "BalanceUpdate",
            "updateId": 23,
            "accountId": 0,
            "subAccountId": 0,
            "coinId": 18,
            "oldBalance": "7272586000000000000",
            "newBalance": "7291616000000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      },
      {
        "txHash": "0x640f38c6b09744d627b16e03339064d6edd39187cde8c4329fa19a2a60db8664",
        "tx": {
          "type": "OrderMatching",
          "accountId": 6,
          "subAccountId": 1,
          "taker": {
            "accountId": 13,
            "subAccountId": 1,
            "slotId": 163,
            "nonce": 0,
            "baseTokenId": 41,
            "quoteTokenId": 1,
            "amount": "1886200000000000000",
            "price": "1568210000000000000000",
            "isSell": 1,
            "feeRatio1": 5,
            "feeRatio2": 10,
            "signature": {
              "pubKey": "1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
              "signature": "57b7a0f06eb5d5dffbc8e8a6626ef7f9c472a8ac7761db36f8a0a2df2049988a9b43e8b3292a969b9b6cc5f689a5eecb8b05981ef1e3ca6e0de0da64ae6d6e01"
            }
          },
          "maker": {
            "accountId": 13,
            "subAccountId": 1,
            "slotId": 898,
            "nonce": 1,
            "baseTokenId": 41,
            "quoteTokenId": 1,
            "amount": "684900000000000000",
            "price": "1569150000000000000000",
            "isSell": 0,
            "feeRatio1": 5,
            "feeRatio2": 10,
            "signature": {
              "pubKey": "1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
              "signature": "b0aebe2bdd7a98a78d564d11c5f138cf428382628af55e85c250446b03dc0005f734e952819278d0b96fa970c6ab0018e33bb5bda7c55d69658551d2e606b904"
            }
          },
          "fee": "391000000000000",
          "feeToken": 1,
          "expectBaseAmount": "54800000000000000",
          "expectQuoteAmount": "85989420000000000000",
          "signature": {
            "pubKey": "84bf4edbe1f7056f079ba4c38359427f43d529fbab2e94e6d6b7a18efbf2fb87",
            "signature": "34e768dce60268f702b9a9ca68cb19d6785d2d1da8d7c799a29aa45e8c8bd9096c20cbf518c95fce2b2b58329492c35896162fe9cb1ff13f6e3a946b15bb2202"
          }
        },
        "executedTimestamp":1689731239,
        "updates": [
          {
            "type": "OrderUpdate",
            "updateId": 0,
            "accountId": 13,
            "subAccountId": 1,
            "slotId": 898,
            "oldTidyOrder": {
              "nonce": 1,
              "residue": "54800000000000000"
            },
            "newTidyOrder": {
              "nonce": 2,
              "residue": "0"
            }
          },
          {
            "type": "BalanceUpdate",
            "updateId": 1,
            "accountId": 13,
            "subAccountId": 1,
            "coinId": 1,
            "oldBalance": "200304228482442156994500000",
            "newBalance": "200304142493022156994500000",
            "oldNonce": 1,
            "newNonce": 1
          },
          {
            "type": "BalanceUpdate",
            "updateId": 2,
            "accountId": 13,
            "subAccountId": 1,
            "coinId": 41,
            "oldBalance": "199999971788889400000000000",
            "newBalance": "199999971843662000000000000",
            "oldNonce": 1,
            "newNonce": 1
          },
          {
            "type": "OrderUpdate",
            "updateId": 3,
            "accountId": 13,
            "subAccountId": 1,
            "slotId": 163,
            "oldTidyOrder": {
              "nonce": 0,
              "residue": "1467400000000000000"
            },
            "newTidyOrder": {
              "nonce": 0,
              "residue": "1412600000000000000"
            }
          },
          {
            "type": "BalanceUpdate",
            "updateId": 4,
            "accountId": 13,
            "subAccountId": 1,
            "coinId": 41,
            "oldBalance": "199999971843662000000000000",
            "newBalance": "199999971788862000000000000",
            "oldNonce": 1,
            "newNonce": 1
          },
          {
            "type": "BalanceUpdate",
            "updateId": 5,
            "accountId": 13,
            "subAccountId": 1,
            "coinId": 1,
            "oldBalance": "200304142493022156994500000",
            "newBalance": "200304228396452736994500000",
            "oldNonce": 1,
            "newNonce": 1
          },
          {
            "type": "BalanceUpdate",
            "updateId": 6,
            "accountId": 6,
            "subAccountId": 1,
            "coinId": 1,
            "oldBalance": "9999680162000000000000",
            "newBalance": "9999679771000000000000",
            "oldNonce": 224,
            "newNonce": 224
          },
          {
            "type": "BalanceUpdate",
            "updateId": 7,
            "accountId": 6,
            "subAccountId": 0,
            "coinId": 1,
            "oldBalance": "3529001244641983488661500000",
            "newBalance": "3529001244727972908661500000",
            "oldNonce": 224,
            "newNonce": 224
          },
          {
            "type": "BalanceUpdate",
            "updateId": 8,
            "accountId": 6,
            "subAccountId": 0,
            "coinId": 41,
            "oldBalance": "1594000000063937300000000000",
            "newBalance": "1594000000063964700000000000",
            "oldNonce": 224,
            "newNonce": 224
          },
          {
            "type": "BalanceUpdate",
            "updateId": 9,
            "accountId": 0,
            "subAccountId": 0,
            "coinId": 1,
            "oldBalance": "483683000000000000",
            "newBalance": "484074000000000000",
            "oldNonce": 0,
            "newNonce": 0
          }
        ]
      }
    ]
  },
  "id": 1
}
```

{% endtab %}
{% endtabs %}

#### **BlockResp**

<table><thead><tr><th width="280.55555555555554">Field</th><th>Description</th></tr></thead><tbody><tr><td>number</td><td>The block height</td></tr><tr><td>commitment</td><td>The commitment of the block, similar to the block hash of Ethereum</td></tr><tr><td>rootHash</td><td>The root hash of the state tree</td></tr><tr><td>feeAccountId</td><td>The id of the fee account</td></tr><tr><td>blockSize</td><td>The maximum chunk number that a block can contain</td></tr><tr><td>opsCompositionNumber</td><td>The vk of generating ZKPs</td></tr><tr><td>timestamp</td><td>The block timestamp</td></tr><tr><td>transactions</td><td>Returns <code>[BlockTxResp]</code> when <code>includeTx</code> is false, <code>TxResp</code> when true; ordered by transaction execution: the ones executed first come first in the array</td></tr></tbody></table>

#### **BlockTxResp**

<table><thead><tr><th width="234.55555555555554">Field</th><th>Description</th></tr></thead><tbody><tr><td>txHash</td><td>The transaction hash</td></tr><tr><td>tx</td><td><code>ZkLinkTx</code></td></tr><tr><td>executedTimestamp</td><td>The unix timestamp of transaction execution</td></tr><tr><td>updates</td><td><code>[StateUpdateResp]</code>, ordered by <code>updateId</code>: the ones executed first come first in the array</td></tr></tbody></table>

#### **StateUpdateResp**

The success of transaction execution will lead to the change of the state tree:

* AccountCreate: create a new account in the state tree
* AccountChangePubkeyUpdate: change in pubkey and nonce
* BalanceUpdate: change in account balance and nonce
* OrderUpdate: change in account slot

**AccountCreate**

<table><thead><tr><th width="254.39130434782612">Field</th><th>Description</th></tr></thead><tbody><tr><td>type</td><td>AccountCreate</td></tr><tr><td>updateId</td><td>The position of the update in the block</td></tr><tr><td>accountId</td><td>The id of the new account</td></tr><tr><td>address</td><td>The account address</td></tr></tbody></table>

Example:

```json
{
  "type": "AccountCreate",
  "updateId": 40,
  "accountId": 42,
  "address": "0xe4efc3d7b69a19d3ae574cbc2915ddf598efe43f"
}
```

{% hint style="info" %}
Transactions that may generate `AccountCreate` include:

* Deposit
* Transfer
  {% endhint %}

**AccountChangePubkeyUpdate**

<table><thead><tr><th width="265.3913043478261">Field</th><th>Description</th></tr></thead><tbody><tr><td>type</td><td>AccountChangePubkeyUpdate</td></tr><tr><td>updateId</td><td>The position of the update in the block</td></tr><tr><td>accountId</td><td>The account id</td></tr><tr><td>oldPubkeyHash</td><td>The old pubkeyHash</td></tr><tr><td>newPubkeyHash</td><td>The new pubkeyHash</td></tr><tr><td>oldNonce</td><td>The old nonce</td></tr><tr><td>newNonce</td><td>The new nonce</td></tr></tbody></table>

Example:

```json
{
  "type": "AccountChangePubkeyUpdate",
  "updateId": 10,
  "accountId": 39,
  "oldPubkeyHash": "0x0000000000000000000000000000000000000000",
  "newPubkeyHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
  "oldNonce": 0,
  "newNonce": 1
}
```

{% hint style="info" %}
only `ChangePubKey` will generate `AccountChangePubkeyUpdate`
{% endhint %}

**BalanceUpdate**

<table><thead><tr><th width="276.3913043478261">Field</th><th>Description</th></tr></thead><tbody><tr><td>type</td><td>BalanceUpdate</td></tr><tr><td>updateId</td><td>The position of the update in the block</td></tr><tr><td>accountId</td><td>The account id</td></tr><tr><td>subAccountId</td><td>The id of the sub account</td></tr><tr><td>coinId</td><td>Token id</td></tr><tr><td>oldBalance</td><td>The balance of the sub account before change</td></tr><tr><td>newBalance</td><td>The balance of the sub account after change</td></tr><tr><td>oldNonce</td><td>The old nonce</td></tr><tr><td>newNonce</td><td>The new nonce</td></tr></tbody></table>

Example:

```json
{
  "type": "BalanceUpdate",
  "updateId": 1,
  "accountId": 2,
  "subAccountId": 1,
  "coinId": 18,
  "oldBalance": "66517000000000000",
  "newBalance": "66518000000000000",
  "oldNonce": 66518,
  "newNonce": 66519
}
```

{% hint style="info" %}
All `ZkLinkTx` will generate `BalanceUpdate`
{% endhint %}

**OrderUpdate**

<table><thead><tr><th width="268.3913043478261">Field</th><th>Description</th></tr></thead><tbody><tr><td>type</td><td>OrderUpdate</td></tr><tr><td>updateId</td><td>The position of the update in the block</td></tr><tr><td>accountId</td><td>The account id</td></tr><tr><td>subAccountId</td><td>The id of the sub account</td></tr><tr><td>coinId</td><td>Token id</td></tr><tr><td>oldTidyOrder</td><td>The <code>TidyOrder</code> before change</td></tr><tr><td>newTidyOrder</td><td>The <code>TidyOrder</code> after change</td></tr></tbody></table>

**TidyOrder**

<table><thead><tr><th width="271.5270935960591">Field</th><th>Description</th></tr></thead><tbody><tr><td>nonce</td><td>Slot nonce</td></tr><tr><td>residue</td><td>Slot residue</td></tr></tbody></table>

Example:

```json
{
  "type": "OrderUpdate",
  "updateId": 30,
  "accountId": 11,
  "subAccountId": 1,
  "slotId": 27,
  "oldTidyOrder": {
    "nonce": 14,
    "residue": "4607200000000000000000"
  },
  "newTidyOrder": {
    "nonce": 14,
    "residue": "4233800000000000000000"
  }
}
```

{% hint style="info" %}
Only `OrderMatching` will generate `OrderUpdate`
{% endhint %}

### getPendingBlock

Get info of transactions waiting to be batched.

{% tabs %}
{% tab title="Request" %}
**Parameters**

* transaction execution time, the timestamp in the return can only be bigger than it.
* `includeTx`: whether to include transaction details. False: return transaction hash only. Only successful transactions will be batched in the block. Call `getTransactionByHash` to query failed transaction details.
* `includeUpdate`: whether to include the state change by the transaction. Valid only when `includeTx` is true.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getPendingBlock",
    "params": [
      1689731233,
      true,
      true
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`Vec<BlockTxResp>:` transactions that are executed but not batched yet, where those executed first come first. 100 transactions max. The max transaction time can be used as a parameter for the next round of query.
{% endtab %}
{% endtabs %}

### getBlockOnChainByNumber

Get transaction information in a block executed on L1 blockchains. Every block will be submitted to and executed on every L1 chain.

{% tabs %}
{% tab title="Request" %}
**Parameters**

* `chain_id`

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getBlockOnChainByNumber",
    "params": [4906]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`BlockOnChainResp`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "committed": [
            {
                "chainId": 2,
                "txHash": "0x7264f1d95b5339f77f2b24939bada1cbca183c77110e514159bbcfad3aa303d2"
            },
            {
                "chainId": 1,
                "txHash": "0x3e30f9bed591ec0339278faaed08e6200f4a5ded4668e3038e7ed70512a68967"
            }
        ],
        "verified": [
            {
                "chainId": 2,
                "txHash": "0xaa0f1fed256b21d8b2fd4b91450418061674971bce452121229126aa35effc37"
            },
            {
                "chainId": 1,
                "txHash": "0xa9548f4fe6a8d3127fdfd221ee2c97149bee8ad82744d2c698440ef3774f1122"
            }
        ]
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

#### **BlockOnChainResp**

<table><thead><tr><th width="168">Field</th><th>Description</th></tr></thead><tbody><tr><td>committed</td><td>Transaction info committed to L1, with type <code>OnChainResp</code></td></tr><tr><td>verified</td><td>Transaction info executed on L1, with type <code>OnChainResp</code></td></tr></tbody></table>

#### **OnChainResp**

<table><thead><tr><th width="168">Field</th><th>Description</th></tr></thead><tbody><tr><td>chain_id</td><td>The chain id defined by zkLink</td></tr><tr><td>tx_hash</td><td>The hash of the transaction on L1 blockchains</td></tr></tbody></table>

{% hint style="info" %}
Noted that since blocks are committed to and executed on L1 blockchains in batches, the on-chain data of blocks in the same batch is the same. For example, when blocks \[4906, 4910] are in the same batch, their on-chain transaction info is the same.

Commitment and batching are asynchronous. For example, when the current block height is 1000, the committed block height can be 980, and the verified block height can be 950. The API caller should query the on-chain infor by the committed and verified block height via `getLatestBlockNumber`. For example, when the latest verified block height is 950, the return of the on-chain block info that is after 950 must be null.
{% endhint %}

### **getAccount**

Get account info by address or account id.

{% tabs %}
{% tab title="Request" %}
**Parameters**

* Address|AccountID - Address(20Bytes or 32Bytes) or integer account id.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getAccount",
    "params": [
        "0x1aef2b4c06b83cdb2783d3458cdbf3886a6ae7d4"
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`AccountInfoResp`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "id": 1,
        "address": "0x1aef2b4c06b83cdb2783d3458cdbf3886a6ae7d4",
        "nonce": 0,
        "pubKeyHash": "0x0000000000000000000000000000000000000000",
      	"subAccountNonces": {
          "1": 0,
          "2":13
        }
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

#### **AccountInfoResp**

<table><thead><tr><th width="316">Field</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>Account id</td></tr><tr><td>address</td><td>Account address</td></tr><tr><td>nonce</td><td>Account nonce</td></tr><tr><td>pubKeyHash</td><td>Account pubKeyHash</td></tr><tr><td>subAccountNonces</td><td>Nonce of the subaccount, HashMap&#x3C;SubAccountId,Nonce></td></tr></tbody></table>

{% hint style="info" %}
`pubKeyHash` being `0x0000000000000000000000000000000000000000` means unactivated account.
{% endhint %}

### getAccountBalances

Get the balance info of an account.

{% tabs %}
{% tab title="Request" %}
**Parameters:**

* `accountId`: account id
* `subAccountId`: optional, the id of the subaccount; null if the query requests the balance of all subaccounts.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getAccountBalances",
    "params": [
        1,
        0
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`HashMap<SubAccountId,<TokenId,Balance>>`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "0": {
           "18": "1498994167999999999973"
        }
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

### getAccountOrderSlots

Get the order slot of an account.

{% tabs %}
{% tab title="Request" %}
**Parameters**

* `accountId`: account id
* `subAccountId`: optional, the id of the subaccount; null if the query requests the balance of all subaccounts.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getAccountOrderSlots",
    "params": [
        1,
        null
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`HashMap<SubAccountId,<SlotId, TidyOrder>>`

```json
{
    "jsonrpc": "2.0",
    "result": {
      "0": {
        "3": {
          "nonce": 21,
          "residue": "348694029837858"
        }
      }
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

### getTokenReserve

Get the withdrawable limit of a token on a certain L1 chain. There are 3 cases:

<table data-view="cards" data-full-width="false"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td>Case 1</td><td><p><strong>User Input:</strong></p><p>Token: <code>ZKL</code></p><p>Withdraw to: <code>ETH</code></p><p><strong>The maximum ZKL that the user can withdraw:</strong></p><p>RPC-API tokenId: <code>ZKL, false</code></p></td><td></td></tr><tr><td>Case 2</td><td><p><strong>User Input:</strong></p><p>Token: <code>USDC</code></p><p>Withdraw to: <code>ETH</code></p><p><strong>The maximum USDC that the user can withdraw:</strong></p><p>RPC-API tokenId: <code>USDC, false</code></p></td><td></td></tr><tr><td>Case 3</td><td><p><strong>User Input:</strong></p><p>Token: <code>USD</code></p><p>Withdraw to: <code>ETH</code></p><p>Withdraw as: <code>USDC</code></p><p><strong>The maximum USDC that the user can withdraw:</strong></p><p>RPC-API tokenId: <code>USDC, true</code></p></td><td></td></tr></tbody></table>

{% tabs %}
{% tab title="Request" %}
**Parameters**

* `tokenId`: tokenId
* `mapping`: whether to query mapping, valid only when tokenId corresponds to USD stable.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getTokenReserve",
    "params": [
      17,
      true
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`HashMap<ChainId, Balance>`

```json
{
    "jsonrpc": "2.0",
    "result": {
			"0": "134",
			"1": "1000000000000000000000000000000000000000000000"
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

### getAccountSnapshot

In zkLink v0.4.0, transactions are executed before being batched, thus the APIs that request account states may not return the states in the latest block. The related APIs include:

* getAccount
* getAccountBalances
* getAccountOrderSlots
* getTokenReserve

getAccountSnapshot is introduced to request the account states of a certain block height, including the basic info, balance info, and order slot info.

{% tabs %}
{% tab title="Request" %}
**Parameters:**

* `accountAddress` or `accountId`
* `subAccountId`: optional, the id of the subaccount; null if the query requests the balance of all subaccounts.
* blockNumber: optional, null to return the latest block snapshot

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getAccountSnapshot",
    "params": [
      10,
      1,
      103
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`AccountSnapshotResp`

```json
{
  "jsonrpc": "2.0",
  "result": {
    "id": 1,
    "address": "0x1aef2b4c06b83cdb2783d3458cdbf3886a6ae7d4",
    "nonce": 0,
    "pubKeyHash": "0x0000000000000000000000000000000000000000",
    "subAccountNonces": {
      "1": 0,
      "2":13
    }
    "balances": {
      "0": {
        "18": "1498994167999999999973"
      }
    },
    "orderSlots": {
      "0": {
        "3": {
          "nonce": 21,
          "residue": "348694029837858"
        }
      },
      "blockNumber": 103
    }
  },
  "id": 1
}
```

{% endtab %}
{% endtabs %}

#### AccountSnapshotResp

<table><thead><tr><th width="306.9699570815451">Field</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>Account id</td></tr><tr><td>address</td><td>Account address</td></tr><tr><td>nonce</td><td>Account nonce</td></tr><tr><td>pubKeyHash</td><td>Account pubKeyHash</td></tr><tr><td>subAccountNonces</td><td>Nonce of the subaccount, HashMap&#x3C;SubAccountId,Nonce></td></tr><tr><td>balances</td><td><code>HashMap&#x3C;SubAccountId,&#x3C;TokenId,Balance>></code></td></tr><tr><td>orderSlots</td><td><code>HashMap&#x3C;SubAccountId,&#x3C;SlotId, TidyOrder>></code></td></tr><tr><td>blockNumber</td><td>The block height of the snapshot</td></tr></tbody></table>

### getTransactionByHash

Get transaction info.

{% tabs %}
{% tab title="Request" %}
**Parameters:**

* `txHash`
* `includeUpdate`: whether to include the state change by the transaction

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getTransactionByHash",
    "params": [
        "0x3210bb3d6719d730b30c4c9a0086d507040e25f83bea4ff4b8c2c91bf8e8c4f9",
      	true
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`TxResp`\*since the transaction may fail, the `TxResp` will also include `receipt`.

```json
{
    "jsonrpc": "2.0",
    "result": {
        "txHash": "0x4221afe405566e4b057d36060e6a5d33151a10a1b9b00da71705e534b6646f22",
        "tx": {
            "type": "Transfer",
            "accountId": 2,
            "fromSubAccountId": 0,
            "toSubAccountId": 1,
            "to": "0xdc9c9863167ee865edd5216964b8b99d43ee7a81",
            "token": 18,
            "amount": "1000000000000",
            "fee": "216000000000000",
            "nonce": 38192,
            "signature": {
                "pubKey": "5f07954b65b5407a37ec0a2c54fb4647e2014475936057bb2f52a6faab938b02",
                "signature": "79bdeaa739557a4be289ef2bf718253ce791adc3ce5fbcb7abcad4b0a2d6e203a9c38d68d987f96ffc7a391f2518f281874f33c7a5a7110d27591ad029b31005"
            },
            "ts": 1675406687
        },
        "receipt": {
            "executed": true,
                "executedTimestamp": 1689731233,
            "success": true,
            "failReason": null,
            "block": 3947,
          	"index": 1
        },
        "updates": [
            {
                "type": "BalanceUpdate",
                "updateId": 9,
                "accountId": 2,
                "subAccountId": 0,
                "coinId": 18,
                "oldBalance": "1941710093000000000000",
                "newBalance": "1941709876000000000000",
                "oldNonce": 38192,
                "newNonce": 38193
            },
            {
                "type": "BalanceUpdate",
                "updateId": 10,
                "accountId": 2,
                "subAccountId": 1,
                "coinId": 18,
                "oldBalance": "38191000000000000",
                "newBalance": "38192000000000000",
                "oldNonce": 38192,
                "newNonce": 38193
            }
        ]
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

#### TxResp

<table><thead><tr><th width="251">Field</th><th>Decription</th></tr></thead><tbody><tr><td>txHash</td><td>The trasnaction hash</td></tr><tr><td>tx</td><td><code>ZkLinkTx</code></td></tr><tr><td>receipt</td><td>The execution receipt of the transaction</td></tr><tr><td>updates</td><td><code>[StateUpdateResp]</code> that is ordered by <code>updateId</code>: the ones generated first come first in the array</td></tr></tbody></table>

**TxReceiptResp**

<table><thead><tr><th width="251">Field</th><th>Decription</th></tr></thead><tbody><tr><td>executed</td><td>Whether the transaction is executed</td></tr><tr><td>executedTimestamp</td><td>The unix timestamp of exection time. Null if <code>executed</code> is false</td></tr><tr><td>success</td><td>The result of the transaction. If <code>executed</code> is false, it must be false</td></tr><tr><td>failReason</td><td>The reason of failure of the transaction. Null if <code>success</code> is True.</td></tr><tr><td>block</td><td>The block height of the transaction. 0 if <code>success</code> is False.</td></tr><tr><td>index</td><td>The index of the transaction in the block. 0 if <code>success</code> is False.</td></tr></tbody></table>

### getAccountTransactionHistory

Get account history in descending order of the transaction id in the database. Current only `Deposit`, `Withdraw`, and `Transfer` are supported.

{% tabs %}
{% tab title="Request" %}
**Parameters**

* `Deposit`, `Withdraw` or `Transfer`
* account address
* the page index, starting from 0
* the page size

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getAccountTransactionHistory",
    "params": [
        "Deposit",
        "0xdc9c9863167ee865edd5216964b8b99d43ee7a81",
      	0,
        100
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`Page<ZkLinkTxHistory>`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "totalPageNum": 20,
        "pageIndex": 0,
        "pageSize": 2,
        "pageData": [
            {
                "chainId": 0,
                "fromAccount": "0x3498f456645270ee003441df82c718b56c0e6666",
                "toAccount": "0xbfda941bd2a0eddb57b10f8e8d3486a738b92ccc",
                "amount": "10000000000000000000000000",
                "nonce": 262,
                "tx": {
                    "type": "Transfer",
                    "accountId": 4,
                    "fromSubAccountId": 0,
                    "toSubAccountId": 1,
                    "to": "0xbfda941bd2a0eddb57b10f8e8d3486a738b92ccc",
                    "token": 47,
                    "amount": "10000000000000000000000000",
                    "fee": "4290000000000",
                    "nonce": 262,
                    "signature": {
                        "pubKey": "84bf4edbe1f7056f079ba4c38359427f43d529fbab2e94e6d6b7a18efbf2fb87",
                        "signature": "a5389ea55bfb88a9457eadba7ef1821d1cc7a51d29ab1fe17b64b7294ea8160acde7ece1fd3c8028b92a1071f41f567e11b27fa30b39959c744f8ccd04052003"
                    },
                    "ts": 1675442473
                },
                "txHash": "0x741b9b668430c78f87c8a9fb6b257f93a151f1101160bcc681536536f982c5b5",
                "txReceipt": {
                    "executed": true,
                    "success": true,
                    "failReason": null,
                    "block": 9991,
                    "index": 3
                },
                "createdAt": "2023-02-03T16:41:13.501848Z"
            },
            {
                "chainId": 0,
                "fromAccount": "0x3498f456645270ee003441df82c718b56c0e6666",
                "toAccount": "0xbfda941bd2a0eddb57b10f8e8d3486a738b92ccc",
                "amount": "10000000000000000000000000",
                "nonce": 261,
                "tx": {
                    "type": "Transfer",
                    "accountId": 4,
                    "fromSubAccountId": 0,
                    "toSubAccountId": 1,
                    "to": "0xbfda941bd2a0eddb57b10f8e8d3486a738b92ccc",
                    "token": 46,
                    "amount": "10000000000000000000000000",
                    "fee": "1270000000000000",
                    "nonce": 261,
                    "signature": {
                        "pubKey": "84bf4edbe1f7056f079ba4c38359427f43d529fbab2e94e6d6b7a18efbf2fb87",
                        "signature": "df5b57a04d907bf2a4639cb4b405320da69416e45516c3d2d4346058fa8a538498d8ca7ec4c84d11fa58f71395d8c5f45adffa4e2ff418038dd0dbc3cf4e7a00"
                    },
                    "ts": 1675442469
                },
                "txHash": "0xb4e12570be6c01a49cfd6c14e7021b7e482ea938804242b41680acd09ffe59d8",
                "txReceipt": {
                    "executed": true,
                    "success": true,
                    "failReason": null,
                    "block": 9989,
                    "index": 6
                },
                "createdAt": "2023-02-03T16:41:10.744899Z"
            }
        ]
    },
    "id": 1
}
```

{% endtab %}
{% endtabs %}

#### **Page\<ZkLinkTxHistory>**

<table><thead><tr><th width="241.48806941431673">Field</th><th>Description</th></tr></thead><tbody><tr><td>totalPageNum</td><td>The number of pages</td></tr><tr><td>pageIndex</td><td>Index of the current page</td></tr><tr><td>pageSize</td><td>The size of the page</td></tr><tr><td>pageData</td><td>Page data<code>[ZkLinkTxHistory]</code></td></tr></tbody></table>

#### **ZkLinkHistory**

<table><thead><tr><th width="227.62655601659753">Field</th><th>Description</th></tr></thead><tbody><tr><td>chainId</td><td><p>Chain id defined by zkLink</p><ul><li>Deposit: the chain that the deposit is from</li><li>Transfer and Withdraw: no specific meaning</li></ul></td></tr><tr><td>fromAccount</td><td><p>Address of from_account</p><ul><li>Deposit: the L1 address that the deposit is from</li><li>Transfer: the from_address of the transfer</li><li>Withdraw: the from_address of the withdraw</li></ul></td></tr><tr><td>toAccount</td><td><p>Address of to_account</p><ul><li>Deposit: L2 address that the deposit is to</li><li>Transfer: the to_address of the transfer</li><li>Withdraw: the L1 address that the withdraw is to</li></ul></td></tr><tr><td>amount</td><td><p>The amount of the transaction</p><ul><li>Deposit: the amount of the deposit</li><li>Transfer: the amount of the transfer</li><li>Withdraw: the amount of the withdraw</li></ul></td></tr><tr><td>nonce</td><td><p>The nonce of the transaction</p><ul><li>Deposit: the serialId of L1 event</li><li>Transfer and Withdraw: the nonce of the transaction</li></ul></td></tr><tr><td>tx</td><td><code>ZkLinkTx</code></td></tr><tr><td>txHash</td><td>The hash of the transaction</td></tr><tr><td>txReceipt</td><td><code>TxReceiptResp</code></td></tr><tr><td>createdAt</td><td>The time that the transaction is received by zkLink</td></tr></tbody></table>

{% hint style="info" %}
Deposit: returns the transaction history of which the account address equals to\_address;

Withdraw: returns the transaction history of which the account address equals from\_address;

Transfer: returns the transaction history of which the account address equals either to\_address or from\_address.
{% endhint %}

### getWithdrawTxs

Get transaction info of withdraw transactions.

{% tabs %}
{% tab title="Request" %}
**Parameters:**

* `lastTxTimestamp`: ISO 8601 standard with date, time, and time zone;
* `maxTxs`: the max value of the number of Withdraw in the return.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "getWithdrawTxs",
    "params": [
        "2023-02-03T16:41:10.744899Z",
        10
    ]
}
```

{% endtab %}

{% tab title="Response" %}
**Returns**

`Vec<FastWithdrawTxResp>`

```json
{
  "jsonrpc": "2.0",
  "result": [
    {
      "txHash": "0xb4e12570be6c01a49cfd6c14e7021b7e482ea938804242b41680acd09ffe59d8",
      "tx": {
        "type": "Withdraw",
        "toChainId": 1,
        "accountId": 7,
        "subAccountId": 2,
        "to": "0x3498f456645270ee003441df82c718b56c0e6666",
        "l2SourceToken": 1,
        "l1TargetToken": 17,
        "amount": "995900000000000000",
        "fee": "4100000000000000",
        "withdrawFeeRatio": 50,
        "fastWithdraw": 1,
        "ts": 1646102148,
        "nonce": 0, // subaccount nonce
        "signature": {
          "pubKey": "0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
          "signature": "a8719d0f771f34a177bbf199ab7b0decd03b5db29edf173ed980d19c7864c5a3761111620ab1982ef1bb7459d5a919727e51b895799e2706ddd5a5328146eb01"
        }
      },
      "executedTimestamp": "2023-02-03T16:41:10.744899Z"
    }
  ],
  "id": 1
}
```

{% endtab %}
{% endtabs %}

#### **FastWithdrawTxResp**

<table><thead><tr><th width="284.6573875802998">Field</th><th>Description</th></tr></thead><tbody><tr><td>txHash</td><td>Transaction hash on zkLink</td></tr><tr><td>tx</td><td>zkLink transaction</td></tr><tr><td>executedTimestamp</td><td>The execution timestamp of the transaction</td></tr></tbody></table>

zkLink will scan the `maxTxs` number of executed withdraw transactions, and returns the fast\_withdraw transactions among which; thus the number of returns might be less than `maxTxs`, even be 0.

In the first scan, `lastTxTimestamp` can be set as 0 to scan from the beginning. Then the `executedTimestamp` of the last record can be used as the `lastTxTimestamp` of the next scan.

### getEthProperty

Get all the information about the Ethereum property.

<table><thead><tr><th width="284.6573875802998">Field</th><th>Description</th></tr></thead><tbody><tr><td>chainId</td><td>Chain id defined by zkLink</td></tr><tr><td>layerOneChainId</td><td>The layer 1 chain id</td></tr><tr><td>gateways</td><td>The list of GateWayInfo</td></tr></tbody></table>

#### GateWayInfo

<table><thead><tr><th width="284.6573875802998">Field</th><th>Description</th></tr></thead><tbody><tr><td>chainId</td><td>the chain id</td></tr><tr><td>chainId</td><td>the chain id</td></tr><tr><td>l1GatewayContract</td><td>the layer 1 gateway contract address</td></tr><tr><td>l2GatewayContract</td><td>the layer 2 gateway contract address</td></tr><tr><td>tokens</td><td>the list that all the TokenInfo on the gateway</td></tr></tbody></table>

#### TokenInfo

<table><thead><tr><th width="284.6573875802998">Field</th><th>Description</th></tr></thead><tbody><tr><td>tokenId</td><td>The token id</td></tr><tr><td>tokenAddress</td><td>token address</td></tr><tr><td>decimal</td><td>the token amount decimal</td></tr><tr><td>fastWithdraw</td><td>support fast withdraw or not</td></tr></tbody></table>

```json
{
  "chainId": 4,
  "layerOneChainId": "0x1",
  "gateways": [
    {
      "chainId": 5,
      "l1GatewayContract": "0x3498f456645270ee003441df82c718b56c0e6666",
      "l2GatewayContract": "0x3498f456645270ee003441df82c718b56c0e6666",
      "tokens": [
        {
          "tokenId": 1,
          "tokenAddress":"0x3498f456645270ee003441df82c718b56c0e6666",
          "decimal": 6,
          "fastWithdraw": true
        },
        {
          "tokenId": 3,
          "tokenAddress":"0x3498f456645270ee003441df82c718b56c0e6666",
          "decimal": 7,
          "fastWithdraw": false
        }
      ]
    },
    {
      "chainId": 7,
      "l1GatewayContract": "0x3498f456645270ee003441df82c718b56c0e6666",
      "l2GatewayContract": "0x3498f456645270ee003441df82c718b56c0e6666",
      "tokens": [
        {
          "tokenId": 1,
          "tokenAddress":"0x3498f456645270ee003441df82c718b56c0e6666",
          "decimal": 6,
          "fastWithdraw": true
        },
        {
          "tokenId": 3,
          "tokenAddress":"0x3498f456645270ee003441df82c718b56c0e6666",
          "decimal": 6,
          "fastWithdraw": false
        }
      ]
    }
  ]
}
```

### sendTransaction

Submit L2 transaction and return transaction hash.

{% tabs %}
{% tab title="Request" %}
**Parameters:**

* `ZkLinkTx`: [L2 transaction](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/json-rpc/layer2-transaction.md)
* Layer1Signature: layer1 signature with type Option\<TxLayer1Signature>; required for Layer2 transactions apart from `ChangePubKey` or `OrderMatching`.
* submitterSignature: `Option<ZkLinkSignature>`, required only when the transaction involves subaccounts (except #0 subaccount); `submitterSignature` is a zk signature to `tx` hash.

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "sendTransaction",
    "params": [
        {
            "accountId": 8,
            "fromSubAccountId": 3,
            "toSubAccountId": 3,
            "from": "0x3498F456645270eE003441df82C718b56c0e6666",
            "to": "0xbfDa941Bd2a0eddB57b10f8E8d3486A738B92cCC",
            "tokenId": 3,
            "amount": "998000000000000000",
            "fee": "3000000000000000",
            "ts": 1646101085,
            "nonce": 1,
            "type": "Transfer",
            "token": 3,
            "signature": {
                "pubKey": "0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
                "signature": "892c622afac908201df54a3cfdecf8eba46d5411bdc29365f5536f024c195f2893d6313a6371fe1659830e2560c1eaedbafcc835837593d017cd557074f0bb03"
            }
        },
        {
            "type": "EthereumSignature",
            "signature": "0xc29d647a5e9e078c66594f04881c34d6b57e1085ab825f17ffb1d0fe233e9834191b374daaaf1e44e5749f6cf44f2143799373fc5e7e844d48fec5e6bc08f0651b"
        },
      	null
    ]
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": "0x3210bb3d6719d730b30c4c9a0086d507040e25f83bea4ff4b8c2c91bf8e8c4f9"
}
```

{% endtab %}
{% endtabs %}

#### **TxLayer1Signature**

L1 signatures apply [EIP-191](https://eips.ethereum.org/EIPS/eip-191) specification with zkLink `Eth sig message`.

<table><thead><tr><th width="185">Field</th><th>Description</th></tr></thead><tbody><tr><td>type</td><td><p>The type of the signature</p><ul><li>EthereumSignature: Ethereum ECDSA signature</li><li>EIP1271Signature: Ethereum <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md">EIP1271</a> signature</li></ul></td></tr><tr><td>signature</td><td>Signature output, a hex string</td></tr></tbody></table>

Examples:

```json
{
  "type": "EthereumSignature",
  "signature": "0xc29d647a5e9e078c66594f04881c34d6b57e1085ab825f17ffb1d0fe233e9834191b374daaaf1e44e5749f6cf44f2143799373fc5e7e844d48fec5e6bc08f0651b"
}
```

```json
{
  "type": "EIP1271Signature",
  "signature": "0xc29d647a5e9e078c66594f04881c34d6b57e1085ab825f17ffb1d0fe233e9834191b374daaaf1e44e5749f6cf44f2143799373fc5e7e844d48fec5e6bc08f0651b"
}
```

#### **ZkLinkSignature**

Signatures for L2 transactions use zkLink `Encode`.

<table><thead><tr><th width="158">Field</th><th>Description</th></tr></thead><tbody><tr><td>pubKey</td><td>The public key of ，a hex string with <code>0x</code> prefix</td></tr><tr><td>signature</td><td>Signature output, a hex string without <code>0x</code> prefix</td></tr></tbody></table>

Example:

```json
{
  "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
  "signature": "892c622afac908201df54a3cfdecf8eba46d5411bdc29365f5536f024c195f2893d6313a6371fe1659830e2560c1eaedbafcc835837593d017cd557074f0bb03"
}
```

`version: 7df6cd1`


# JSON-RPC Errors

The format of an error message that the RPC returns:

```
{
    "jsonrpc": "2.0",
    "error": {
        "code": -32602,
        "message": "Layer1Address deserialize error: incorrect Layer1Address format"
    },
    "id": 1
}
```

* code: error code
* message: error message in English

## Error Types

* -32602: incorrect number of parameters or unable to serialize parameters correctly
* 100-200: parameter value is not within the correct range
* 201-300: Incorrect state, such as insufficient account balance for a transfer
* 500: RPC server internal error

## Error Code

The table below lists most error codes and their meanings. While the error codes and meanings generally remain the same, the error messages may change with version iterations. The range from -32768 to -32000 represents the predefined errors in the JSON RPC 2.0 protocol and are less likely to occur if the API documentation is followed. The range from 100 to 500 represents custom errors defined by the zklink RPC server and should be handled by the caller.

<table><thead><tr><th width="117">Code</th><th>Meaning</th><th>Message (Example)</th><th>Notes</th></tr></thead><tbody><tr><td>-32602</td><td>Incorrect number of parameters or the parameters cannot be serialized correctly.</td><td>Layer1Address deserialize error: incorrect Layer1Address format</td><td>This error can occur if the RPC is not called following the API documentation.</td></tr><tr><td>100</td><td>Invalid chain ID</td><td>Invalid chain id</td><td>Related to the chains that zklink connects. For example, if there are 4 supported chains, the correct range for chain IDs would be [1, 4].</td></tr><tr><td>101</td><td>Invalid account ID</td><td>Invalid account id</td><td>[0, 2^24 -1]</td></tr><tr><td>102</td><td>Invalid subaccount ID</td><td>Invalid sub account id</td><td>[0, 7]</td></tr><tr><td>103</td><td>Invalid token ID</td><td>Invalid token id</td><td>[1, 65535]</td></tr><tr><td>104</td><td>Invalid block range</td><td>Invalid block range</td><td>blockEnd >= blockStart</td></tr><tr><td>105</td><td>Invalid transaction type</td><td>Invalid tx type</td><td>Only specific transaction types are supported for querying transaction history or submitting transactions. Refer to <a href="/pages/QgF52eLdnMhFYB4Q8InT">API doc</a> for details.</td></tr><tr><td>106</td><td>Invalid field in a format</td><td>Invalid tx format</td><td>There can be various reasons for this error, such as an incorrect transfer accountId or inconsistent subAccountIds between maker and taker in OrderMatching. Refer to <a href="https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/json-rpc/layer3-transaction.md">API doc </a>for details.</td></tr><tr><td>107</td><td>Invalid ChangePubKey auth type</td><td>Invalid change pubkey auth type</td><td>Only Onchain, EthECDSA, and EthCREATE2 are currently supported.</td></tr><tr><td>108</td><td>Fail to pass ChangePubKey auth check</td><td>Invalid change pubkey auth data</td><td>Refer to zkLink <a href="/pages/QgF52eLdnMhFYB4Q8InT">API doc</a>.</td></tr><tr><td>109</td><td>Missing or invalid layer1 signature</td><td>Missing or invalid layer one signature</td><td>All Layer3 transactions, except ChangePubKey, require a valid Layer 1 signature.</td></tr><tr><td>110</td><td>Invalid Layer 2 signature</td><td>Invalid zk signature</td><td>All Layer 2 transactions require a valid Layer 2 signature.</td></tr><tr><td>111</td><td>Missing submitter's Layer 2 signature</td><td>Missing or invalid submitter zk signature</td><td>When a transaction results in the asset decrease in subaccounts (except #0 subaccount), a valid submitter signature must be provided.</td></tr><tr><td>112</td><td>Invalid taker's Layer 2 signature</td><td>Invalid taker zk signature</td><td>-</td></tr><tr><td>113</td><td>Invalid maker's Layer 2 signature</td><td>Invalid maker zk signature</td><td>-</td></tr><tr><td>201</td><td>Account not found</td><td>Account not found</td><td>The account does not exist in the state tree.</td></tr><tr><td>202</td><td>Token configuration not found</td><td>Token not found</td><td>The token configuration does not exist in the state tree.</td></tr><tr><td>203</td><td>Tx not found</td><td>Tx not found</td><td>Cannot find the transaction record in the database.</td></tr><tr><td>204</td><td>The account not actived</td><td>Account not active</td><td>The account needs to be activated before executing Layer 2 transactions (except for ChangePubKey).</td></tr><tr><td>205</td><td>Incorrect nonce</td><td>Incorrect nonce</td><td>The transaction nonce must be monotonically increasing.</td></tr><tr><td>206</td><td>Insufficient account balance</td><td>Insufficient account balance</td><td>When involving a decrease in account assets, the account balance is checked for sufficiency.</td></tr><tr><td>207</td><td>The fee for the transaction is too low</td><td>Fee too low</td><td>All Layer 2 transactions require a fee, which can be obtained through get_tx_fee.</td></tr><tr><td>208</td><td>The withdraw amount exceeds available contract reserve</td><td>Withdraw amount exceed contract reserve</td><td>The Withdraw or ForcedExit transaction checks the withdrawal amount. The token_remain API can be used to query the reserve on Layer1 contract.</td></tr><tr><td>209</td><td>ForcedExit transaction cannot be initiated to activated account</td><td>Can not force exit active account</td><td>ForcedExit can only be iniciated to accounts that haven't been activated.</td></tr><tr><td>210</td><td>Target account of ForcedExit exists less than required minimum time</td><td>Target account exists less than required minimum time</td><td>When initiating a ForcedExit transaction to an inactive account, the account must exist for a certain duration, such as 24 hours, to provide enough time for the account to be activated.</td></tr><tr><td>211</td><td>Target account address of ForcedExit is 0xffffffffffffffffffffffffffffffffffffffff</td><td>Target account can not be global asset account</td><td>The address 0xffffffffffffffffffffffffffffffffffffffff is a global asset account, and ForcedExit is not allowed on this account.</td></tr><tr><td>212</td><td>Submitter is not in the whitelist</td><td>Submitter not in whitelist</td><td>A submitter's signature is required when a transaction results in a decrease of assets in a subaccount (except #0 subaccount). The submitter needs to be registered on zkLink.</td></tr><tr><td>213</td><td>A transaction is submitted for more than once</td><td>Duplicate tx</td><td>The submitted transaction hash must be unique and should not be duplicated.</td></tr><tr><td>214</td><td>Block not found</td><td>Block not found</td><td>The block height exceeds the latest block height.</td></tr><tr><td>215</td><td>The initicator forced_exit it's own account</td><td>Initiator account cannot be the target account, please Withdraw transaction</td><td>When the initiator is attempting to force withdraw its own assets, it should initiate a withdraw transaction.</td></tr><tr><td>500</td><td>Server internal error</td><td>Server internal error</td><td></td></tr></tbody></table>

## Notable Errors

### 201

When using some APIs that involve querying account status such as getAccount, getAccountSnapshot, etc., if the account does not exist, it will return this error message, rather than returning a default. This is because the account with '`accountId=0`' is a Layer3 fee account, and the default accountId is also 0. If the account does not exist, returning the default value will cause confusion.

### 207

Transaction fees are related to Layer3 token price, which is stable over a period of time (for example, half an hour). If the price is updated just after `get_tx_fee`, `tx_submit` may fail. In this case, the initiator need to re-query the transaction fee and then try to submit the transaction again.\\

`version: 7df6cd1`


# Websocket

## Connect

In the public channel, when the client successfully connects to the ZkLink node, the server will return a message with ID 0, which contains the `listen_key` automatically created by the server for the connection:

```json
{ "result": 
    {
      "listen_key": "9752db94ea664f1ea1e58074f547a9fe"
    }, 
  "error_code": 0,
  "error_msg": "",
  "id": 0
}
```

The server will send `ping` frame to the client every two minutes, and the client should reply the `pong` frame within 10 minutes, otherwise the connection will be automatically disconnected.

## Public Topics

* Topic of transaction execution results: `txExecuteResult@{sub_account_id}`, for example when `sub_account_id` is `1`, the topic will be `txExecuteResult@1`;
* full exit event： `fullExitEvent@{sub_account_id}`, for example when `sub_account_id` is `1`， the topic will be `fullExitEvent@1`.

## Subscribe & Unsubscribe Topics

The client can subscribe and unsubscribe to topics at any time after connecting, and only needs to send a request to the service:

```json
{
    "method": "subscribe",
    "topics": ["fullExitEvent@01", "txExecuteResult@1"],
    "id": 1
}
```

where the value of `method` can be `subscribe` or `unSubscribe`. The id in the response content is an unsigned integer, which serves as the unique identifier of the communication. It also contains the value of the currently subscribed topic list.

```json
{
  "result": {
    "topics":["fullExitEvent@01", "txExecuteResult@1"]
  },
  "error_code":0,
  "error_msg":"",
  "id":1
}
```

## Query Topic

`GET /api/topics/{listen_key}`

The client can use the `listen_key`(returned when the Websocket first connection) to query the `topic` list of its corresponding Websocket connection. The return value is:

```json
["txExecuteResult@1", "fullExitEvent@1"]
```

When the Websocket connection corresponding to `listen_key` is disconnected, `null` is returned.

## Data Push

### Transaction Execution Results

topic: `txExecuteResult@{sub_account_id}`

| Name                | Type                                                                                                                                                | Describe                                                                                               |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| type                | String                                                                                                                                              | Event type                                                                                             |
| tx\_hash            | [TxHash](/developer/api-and-sdk/basic-types#txhash)                                                                                                 | The tx hash on L1                                                                                      |
| tx                  | [ZklinkTx](/developer/api-and-sdk/transaction)                                                                                                      | [Transaction](/developer/api-and-sdk/transaction) detail                                               |
| receipt             | struct                                                                                                                                              | The transaction status after received                                                                  |
| > executed          | bool                                                                                                                                                | The transaction finished executing or not                                                              |
| > executedTimestamp | Option                                                                                                                                              | The Unix microsecond timestamp when transaction excute, when executed is false, the value will be null |
| > success           | bool                                                                                                                                                | The transaction executed successfull or not                                                            |
| > failReason        | Option                                                                                                                                              | The reason that transaction execute fail, the value will be null if transaction execute success        |
| > block             | Option                                                                                                                                              | Block height that contains the transaction, it will be null if success is false                        |
| > index             | Option                                                                                                                                              | The transaction index in the block, if value will be null if success is false                          |
| updates             | [StateUpdateResp](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/websocket/broken-reference/README.md) array | Update event                                                                                           |

```json
{
  "type": "TxExecuteResult",
  "tx_hash": "0xde9b5a916309f5097825ed1fb34eb5cc3a52faa1f5ef901aab54ef546d8e86b7",
  "tx": {
      "type": "Transfer",
      "accountId": 8,
      "fromSubAccountId": 3,
      "toSubAccountId": 3,
      "to": "0xbfDa941Bd2a0eddB57b10f8E8d3486A738B92cCC",
      "token": 3,
      "amount": "998000000000000000",
      "fee": "3000000000000000",
      "ts": 1646101085,
      "nonce": 1,
      "signature": {
        "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
        "signature": "892c622afac908201df54a3cfdecf8eba46d5411bdc29365f5536f024c195f2893d6313a6371fe1659830e2560c1eaedbafcc835837593d017cd557074f0bb03"
      }
   },
  "receipt": {
      "executed": true,
      "executedTimestamp": 1689731233000000,
      "success": true,
      "failReason": null,
      "block": 3947,
      "index": 1
    },
  "updates": [
    {
      "type": "BalanceUpdate",
      "updateId": 12,
      "accountId": 2,
      "subAccountId": 0,
      "coinId": 18,
      "oldBalance": "3018976060000000000000",
      "newBalance": "3018975850000000000000",
      "oldNonce": 115,
      "newNonce": 116
    },
    {
      "type": "BalanceUpdate",
      "updateId": 13,
      "accountId": 2,
      "subAccountId": 1,
      "coinId": 18,
      "oldBalance": "114000000000000",
      "newBalance": "115000000000000",
      "oldNonce": 115,
      "newNonce": 116
    },
    {
      "type": "BalanceUpdate",
      "updateId": 14,
      "accountId": 0,
      "subAccountId": 0,
      "coinId": 18,
      "oldBalance": "1023826000000000000",
      "newBalance": "1024035000000000000",
      "oldNonce": 0,
      "newNonce": 0
    }
  ]
}
```

### Full Exit Event

topic: fullExitEvent@{sub\_account\_id}

| Name     | Type                                                | Description          |
| -------- | --------------------------------------------------- | -------------------- |
| type     | String                                              | Event type           |
| tx\_hash | [TxHash](/developer/api-and-sdk/basic-types#txhash) | The tx hash on L1    |
| tx       | [Transaction](/developer/api-and-sdk/transaction)   | FullExit transaction |

For example:

```json
{
  "type": "FullExitEvent",
  "tx_hash": "0xde9b5a916309f5097825ed1fb34eb5cc3a52faa1f5ef901aab54ef546d8e86b7",
  "tx": {
      "type": "FullExit",
      "toChainId": 1,
      "accountId": 25,
      "subAccountId": 1,
      "exitAddress": "0xae08c2e27765faef5cb05908dbac12242caf91af",
      "l2SourceToken": 47,
      "l1TargetToken": 47,
      "serialId": 43,
      "ethHash": "0x748d32538f71d937d9e2c47adc26c499d0451b87e4fd337c2d6190c3271dafd7"
   }
}
```


# Kafka

## Connect

When using Kafka, the client establishes a connection by specifying the Kafka server's address and port. In the configuration file (such as the application's configuration file or the Kafka client configuration), the bootstrap.servers property must be set to specify the connection information for the Kafka cluster.

Below is a JSON format example demonstrating how to configure the Kafka server's address and port in the client:

```json
{
  "servers": "localhost:9092"
}
```

This configuration ensures that the client can locate and connect to the Kafka server running on localhost with the port number 9092.

## Consumer Topics

### Common consumer topics

The event type [`TxEventMsg`](#txeventmsg) and its associated data structures consumed in the Kafka `SUBMIT_TX_TOPIC` topic. This topic is specifically used for receiving l2 submit transactions, as well as FullExit ready message.

### Event type

The event type consumed is `TxEventMsg`, which is an enumeration type. Currently, there is only `Submit`.

#### Submit event

The `Submit` event carries a `BatchSubmitMessages` structure, which represents a batch of submitted transaction messages.

### data structure

#### TxEventMsg

| eventType | Type                                        | Description                             |
| --------- | ------------------------------------------- | --------------------------------------- |
| Submit    | [BatchSubmitMessages](#batchsubmitmessages) | Submitted transaction batch information |

#### BatchSubmitMessages

| Field     | Type                       | Description                |
| --------- | -------------------------- | -------------------------- |
| messages  | Vec<[TxParams](#txparams)> | Transaction parameter list |
| messageId | `i64`                      | message id                 |
| id        | `i64`                      | batch id                   |
| createdAt | `i64`                      | Creation timestamp         |

#### TxParams

| Field              | Type                                                                      | Description         |
| ------------------ | ------------------------------------------------------------------------- | ------------------- |
| tx                 | [ZkLinkTx](/developer/api-and-sdk/transaction)                            | Transaction details |
| ethSignature       | [TxLayer1Signature](/developer/api-and-sdk/basic-types#txlayer1signature) | layer1 signature    |
| submitterSignature | [ZkLinkSignature](/developer/api-and-sdk/basic-types#zklinksignature)     | Submitter signature |

### JSON example

```json
{
 "refId": 0,
 "createdAt": 1712495689413,
 "eventType": "submit",
 "messageId": 94795,
 "id": 510694,
 "messages": [
   {
     "tx": {
       "type": "Funding",
       "accountId": 4,
       "subAccountId": 0,
       "fee": "0",
       "feeToken": 140,
       "signature": {
         "pubKey": "b939c75660ac6ec9dc7c4233c53647ba69bb8db7dc0485134f14fc8bc8b23e15",
         "signature": "4af9bc51a6118b1226a1887bd657faedeeb5422f87b04c23af94d2c5193a041e1855c45dc576e5966e4ca47b9f28200d4600a8ad78d8f9159cd0a0af6625bf01"
       },
       "subAccountNonce": 755,
       "fundingAccountIds": [93]
     },
     "ethSignature": null,
     "submitterSignature": {
       "pubKey": "b939c75660ac6ec9dc7c4233c53647ba69bb8db7dc0485134f14fc8bc8b23e15",
       "signature": "7f709ca1cff725ef0bec2a5147bd2405cf2cf843b16e94e0af2c4559eae31f122f685da8fc52c6d0056b19e29ecd87532467e8642a6203d46307d617b9237403"
     }
   }
 ]
}
```

### Special consumer topics

The `SYSTEM` topic, be used for stopping consuming messages.

## Producer Topics

### Topic Description

This document provides details about the event types and data structures associated with the `TX_RESULT_TOPIC` topic in Kafka. It is designed to guide producers on how to format messages that consumers will process.

### Consumer Usage Guide

To ensure that consumers can effectively process messages received from the `TX_RESULT_TOPIC` topic, here are the data and structures that consumers need to be familiar with:

### data structure

#### TxMsgResp(stage)

| stage    | Type                              | Description                                                                                                      |
| -------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| ready    | [TxReadyResp](#txreadyresp)       | This is for FullExit, Deposit, means layer2 is ready, not yet executed(be executed after [submit](#event-type)). |
| submit   | [TxExecutedResp](#txexecutedresp) | This is the result for a failed tx(all tx type).                                                                 |
| executed | [TxExecutedResp](#txexecutedresp) | This is the result for a successfully executed tx(all tx type).                                                  |

#### TxReadyResp

| Field   | Type                                                | Description       |
| ------- | --------------------------------------------------- | ----------------- |
| txInput | Vec<[ZkLinkTx](/developer/api-and-sdk/transaction)> | Transaction input |
| txHash  | [TxHash](/developer/api-and-sdk/basic-types#txhash) | Transaction Hash  |

#### TxExecutedResp

| Field     | Type                                                | Description         |
| --------- | --------------------------------------------------- | ------------------- |
| txInput   | Vec<[ZkLinkTx](/developer/api-and-sdk/transaction)> | Transaction input   |
| messageId | `Option<i64>`                                       | message ID          |
| id        | `Option<i64>`                                       | Transaction ID      |
| txResults | Vec<[TxResult](#txresult)>                          | Transaction results |

#### TxResult

`TxResult` is an enumeration type that contains three cases: `Succeed`, `Failed` and `UnExecuted`.

**Succeed**

| Field   | Type                                                                                    | Description      |
| ------- | --------------------------------------------------------------------------------------- | ---------------- |
| txHash  | [TxHash](/developer/api-and-sdk/basic-types#txhash)                                     | Transaction Hash |
| updates | Vec<[StateUpdateResp](/developer/json-rpc-and-websocket-and-kafka/json-rpc-api#txresp)> | Status updates   |

**Failed**

| Field   | Type     | Description   |
| ------- | -------- | ------------- |
| code    | `i32`    | error code    |
| message | `String` | error message |

**UnExecuted**

No field means the transaction was not executed.

### JSON example

#### ready

```json
{
  "stage": "ready",
  "txInput": [
    {
      "type": "Deposit",
      "fromChainId": 1,
      "from": "0x76920dfacad4f28f97d6209977c1057b9e3e5cad",
      "subAccountId": 1,
      "l1SourceToken": 18,
      "l2TargetToken": 1,
      "amount": "4000000000000000000000",
      "to": "0x76920dfacad4f28f97d6209977c1057b9e3e5cad",
      "serialId": 53,
      "l2Hash": "0xaaa1e7a5bc48e7cfaa562a4d1a5abc1d6dc5e7f7683e89eb00e895d438f0acab"
    }
  ],
  "txHash": "0xbb4d4852f06e143aa1451666085180a517e83f2c0a5f42fdd40e8df180b54c91"
}
```

#### submit

```json
{
  "stage": "submit",
  "txInput": [
    {
      "type": "OrderMatching",
      "accountId": 2,
      "subAccountId": 0,
      "taker": {
        "accountId": 28,
        "subAccountId": 0,
        "slotId": 9378,
        "nonce": 6,
        "baseTokenId": 17,
        "quoteTokenId": 140,
        "amount": "33000000000000000000",
        "price": "1000000000000000000",
        "isSell": 0,
        "hasSubsidy": 0,
        "feeRates": [
          10,
          20
        ],
        "signature": {
          "pubKey": "0x06cca8fbfa06c39801f8cb0d8032539cba8491f4fdee275abf390c49ec9e8dae",
          "signature": "a7702be3d72b3f9ea333c3da90746845a21bd9b00273f7f8363d8542d60ef22085737ea8eba0fc383edf29ebe4e0fa83b3ddc2f96f9b7f44cd29e17783efe400"
        }
      },
      "maker": {
        "accountId": 100,
        "subAccountId": 0,
        "slotId": 14381,
        "nonce": 4,
        "baseTokenId": 17,
        "quoteTokenId": 140,
        "amount": "31000000000000000000",
        "price": "1000000000000000000",
        "isSell": 1,
        "hasSubsidy": 0,
        "feeRates": [
          10,
          20
        ],
        "signature": {
          "pubKey": "0x9953827fc901dd57718d464ddc5db23445474e9f87f6f554c81176c5d93a760b",
          "signature": "f43675557eb4f581a97bf1662ce2b0058f56f718569fbcafb6b2c53fe7efc2971ebe906f7185daab8f2b3e363f8281b91027189eb51bc65491a54e1a7944c004"
        }
      },
      "oraclePrices": {
        "contractPrices": [
          {
            "pairId": 0,
            "marketPrice": "69407038011000000000000"
          },
          {
            "pairId": 1,
            "marketPrice": "0"
          },
          {
            "pairId": 2,
            "marketPrice": "0"
          },
          {
            "pairId": 3,
            "marketPrice": "0"
          },
          {
            "pairId": 4,
            "marketPrice": "0"
          },
          {
            "pairId": 5,
            "marketPrice": "0"
          },
          {
            "pairId": 6,
            "marketPrice": "0"
          },
          {
            "pairId": 7,
            "marketPrice": "1000085417000000000000"
          }
        ],
        "marginPrices": [
          {
            "tokenId": 140,
            "price": "1000000000000000000"
          },
          {
            "tokenId": 17,
            "price": "999500000000000000"
          },
          {
            "tokenId": 142,
            "price": "1000000000000000000000"
          },
          {
            "tokenId": 0,
            "price": "0"
          }
        ]
      },
      "fee": "0",
      "feeToken": 140,
      "expectBaseAmount": "0",
      "expectQuoteAmount": "0",
      "signature": {
        "pubKey": "0x51ab37221738f1b013233e07b4d502abed0562060689b3ccc7b7766999dfc681",
        "signature": "7b41379292f91b77cd2ce1b750c9e18fdaf569cbbe6f33b4f89ce3cca3b8d7a9ccbf6d364bdd61bf7d590d0e30997b325e7dda4091b7d225529a7a8fe67c9001"
      }
    }
  ],
  "messageId": null,
  "id": null,
  "txResults": [
    {
      "code": 213,
      "message": "Duplicate tx"
    }
  ]
}
```

#### executed

```json
{
  "stage": "executed",
  "txInput": [
    {
      "type": "OrderMatching",
      "accountId": 2,
      "subAccountId": 0,
      "taker": {
        "accountId": 28,
        "subAccountId": 0,
        "slotId": 9378,
        "nonce": 6,
        "baseTokenId": 17,
        "quoteTokenId": 140,
        "amount": "33000000000000000000",
        "price": "1000000000000000000",
        "isSell": 0,
        "hasSubsidy": 0,
        "feeRates": [
          10,
          20
        ],
        "signature": {
          "pubKey": "0x06cca8fbfa06c39801f8cb0d8032539cba8491f4fdee275abf390c49ec9e8dae",
          "signature": "a7702be3d72b3f9ea333c3da90746845a21bd9b00273f7f8363d8542d60ef22085737ea8eba0fc383edf29ebe4e0fa83b3ddc2f96f9b7f44cd29e17783efe400"
        }
      },
      "maker": {
        "accountId": 100,
        "subAccountId": 0,
        "slotId": 14381,
        "nonce": 4,
        "baseTokenId": 17,
        "quoteTokenId": 140,
        "amount": "31000000000000000000",
        "price": "1000000000000000000",
        "isSell": 1,
        "hasSubsidy": 0,
        "feeRates": [
          10,
          20
        ],
        "signature": {
          "pubKey": "0x9953827fc901dd57718d464ddc5db23445474e9f87f6f554c81176c5d93a760b",
          "signature": "f43675557eb4f581a97bf1662ce2b0058f56f718569fbcafb6b2c53fe7efc2971ebe906f7185daab8f2b3e363f8281b91027189eb51bc65491a54e1a7944c004"
        }
      },
      "oraclePrices": {
        "contractPrices": [
          {
            "pairId": 0,
            "marketPrice": "69407038011000000000000"
          },
          {
            "pairId": 1,
            "marketPrice": "0"
          },
          {
            "pairId": 2,
            "marketPrice": "0"
          },
          {
            "pairId": 3,
            "marketPrice": "0"
          },
          {
            "pairId": 4,
            "marketPrice": "0"
          },
          {
            "pairId": 5,
            "marketPrice": "0"
          },
          {
            "pairId": 6,
            "marketPrice": "0"
          },
          {
            "pairId": 7,
            "marketPrice": "1000085417000000000000"
          }
        ],
        "marginPrices": [
          {
            "tokenId": 140,
            "price": "1000000000000000000"
          },
          {
            "tokenId": 17,
            "price": "999500000000000000"
          },
          {
            "tokenId": 142,
            "price": "1000000000000000000000"
          },
          {
            "tokenId": 0,
            "price": "0"
          }
        ]
      },
      "fee": "0",
      "feeToken": 140,
      "expectBaseAmount": "0",
      "expectQuoteAmount": "0",
      "signature": {
        "pubKey": "0x51ab37221738f1b013233e07b4d502abed0562060689b3ccc7b7766999dfc681",
        "signature": "7b41379292f91b77cd2ce1b750c9e18fdaf569cbbe6f33b4f89ce3cca3b8d7a9ccbf6d364bdd61bf7d590d0e30997b325e7dda4091b7d225529a7a8fe67c9001"
      }
    }
  ],
  "messageId": null,
  "id": null,
  "txResults": [
    {
      "txHash": "0xbb4d4852f06e143aa1451666085180a517e83f2c0a5f42fdd40e8df180b54c91",
      "updates": [
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "OrderUpdate",
          "updateId": 0,
          "accountId": 100,
          "subAccountId": 0,
          "slotId": 14381,
          "oldTidyOrder": {
            "nonce": 4,
            "residue": "0"
          },
          "newTidyOrder": {
            "nonce": 4,
            "residue": "25000000000000000000"
          }
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 1,
          "accountId": 100,
          "subAccountId": 0,
          "coinId": 17,
          "oldBalance": "68498000000000000000",
          "newBalance": "62498000000000000000",
          "oldNonce": 0,
          "newNonce": 0
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 2,
          "accountId": 100,
          "subAccountId": 0,
          "coinId": 140,
          "oldBalance": "39306373000000000000",
          "newBalance": "45300373000000000000",
          "oldNonce": 0,
          "newNonce": 0
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "OrderUpdate",
          "updateId": 3,
          "accountId": 28,
          "subAccountId": 0,
          "slotId": 9378,
          "oldTidyOrder": {
            "nonce": 6,
            "residue": "6000000000000000000"
          },
          "newTidyOrder": {
            "nonce": 7,
            "residue": "0"
          }
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 4,
          "accountId": 28,
          "subAccountId": 0,
          "coinId": 140,
          "oldBalance": "67593004000000000000",
          "newBalance": "61593004000000000000",
          "oldNonce": 0,
          "newNonce": 0
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 5,
          "accountId": 28,
          "subAccountId": 0,
          "coinId": 17,
          "oldBalance": "35333000000000000000",
          "newBalance": "41321000000000000000",
          "oldNonce": 0,
          "newNonce": 0
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 6,
          "accountId": 2,
          "subAccountId": 0,
          "coinId": 140,
          "oldBalance": "0",
          "newBalance": "0",
          "oldNonce": 6,
          "newNonce": 6
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 7,
          "accountId": 3,
          "subAccountId": 0,
          "coinId": 17,
          "oldBalance": "6761781393480000000000",
          "newBalance": "6761793393480000000000",
          "oldNonce": 0,
          "newNonce": 0
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 8,
          "accountId": 3,
          "subAccountId": 0,
          "coinId": 140,
          "oldBalance": "1307544014198290000000000",
          "newBalance": "1307544020198290000000000",
          "oldNonce": 0,
          "newNonce": 0
        },
        {
          "stateUpdateType": "AccountUpdate",
          "accountUpdateType": "BalanceUpdate",
          "updateId": 9,
          "accountId": 3,
          "subAccountId": 0,
          "coinId": 140,
          "oldBalance": "1307544020198290000000000",
          "newBalance": "1307544020198290000000000",
          "oldNonce": 0,
          "newNonce": 0
        }
      ]
    }
  ]
}
```


# Transactions

zkLink sdk now support all the functions in Golang, Javascript and Rust. You can use it to generate private key, build the transaction and generate signature. For the developer who use the other langu

## Private Key and Signature

After user create an account in zkLink, a layer3 private key need to be generated from the L1 wallet private key. User operations such as placing order, withdraw, transfer asset etc require this L3 private key to generate the signature. And zkLink server will verify the signature of the received transaction. This part will describe how to generate the L3 private key and encode the transaction to be signed. For the developers who use the SDK can ignore this part.

## Data Types

This part include all the transaction types and state update definition including the sdk example to sign the transactions.


# Basic Types

## Basic types

* [ChainId](#chainid)
* [AccountId](#accountid)
* [SubAccountId](#subaccountid)
* [TokenId](#tokenid)
* [SlotId](#slotid)
* [PairId](#pairid)
* [MarginId](#marginid)
* [Nonce](#nonce)
* [ChainType](#chaintype)
* [H256](#h256)
* [TxHash](#txhash)
* [PubKeyHash](#pubkeyhash)

## Basic structures

* [TxLayer1Signature](#txlayer1signature)
* [ZkLinkSignature](#zklinksignature)

#### ChainId

The chain id defined by ZkLink, the type is `u8`, Value range: \[0, 31]

#### AccountId

The account id defined by ZkLink, the type is `u32`, Value range: 0 or \[2, 2^24 - 1]

#### SubAccountId

The subaccount id defined by ZkLink, the type is`u8`, Value range: \[0, 31]

#### TokenId

The type is`u32`, different token contract addresses correspond to different token ids. There are many stablecoins, for example, USDC or BUSD are equivalent to USD. In order to aggregate the liquidity of these stablecoins, zkLink created a virtual USD token on L3. Users deposite USDC or BUSD at L1 and can choose to receive the same amount of USD at L3. Conversely, when withdrawing USD, users can choose to withdraw an equivalent amount of USDC or BUSD to L1.

| TokenId  | description                                        |
| -------- | -------------------------------------------------- |
| 0        | illegal                                            |
| 1        | USD                                                |
| 2-16     | mapping tokenId of stablecoin corresponding to USD |
| 17-31    | the token id of stablecoin                         |
| 32-65535 | other token id                                     |

#### SlotId

The id of slot in [Order](#order), the type is `u32`, Value range: \[0, 2^16 - 1]

#### PairId

The trading pair ID of the pertetual contract, the type is `u16`. The PairId is defined by decentralized exchange, not defined by ZkLink, Value range: \[0, 8]

#### MarginId

The margin ID of the pertetual contract, the type is `u8`, Value range: \[0, 3]

#### Nonce

The nonce type in transaction and account, the type is `u32`, Value range: \[0, 2^32 - 1]

#### Price

The price in transaction, the type is `BigUint`, Value range: \[0, (2^120 - 1) / 10^18 - 1]

#### ChainType

* 0: EVM
* 1: StarkNet

#### TxHash

Transaction Hash, it is the unique address of a transaction that acts as a record or proof that the transaction has taken place. It is the hexadecimal serialized string of `[u8; 32]` starting with `0x`, for example：

`0x7264f1d95b5339f77f2b24939bada1cbca183c77110e514159bbcfad3aa303d2`

#### H256

the type is string, it is the hexadecimal serialized string of `[u8; 32]` starting with `0x`, for example:

`0x052fdba72bbb6fcc10940fc22dc76e459dda32604a17a920b8f2d2d0f0caff8f`

#### PubKeyHash

The public key hash of Zklink layer side, it is the hexadecimal serialized string of `[u8; 20]`, for example:

`0x3cfdecf8eba46d5411bdc29365f5536f024c195f`

#### ZkLinkSignature

The L3 transaction signature.

| Name      | Type   | Description                                                                                                        |
| --------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| pubKey    | String | the public key of the signature which used to verify the signature, hexadecimal serialized string with `0x` prefix |
| signature | String | the signature，hexadecimal serialized string without 0x\` prefix                                                    |

For example:

```json
{
    "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
    "signature": "892c622afac908201df54a3cfdecf8eba46d5411bdc29365f5536f024c195f2893d6313a6371fe1659830e2560c1eaedbafcc835837593d017cd557074f0bb03"
}
```

#### TxLayer1Signature

The transaction L1 signature, for the ethereum, there are two types signatures [EIP-191](https://eips.ethereum.org/EIPS/eip-191) and [EIP1271](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md).

| Name      | Type   | Required | Description                        |
| --------- | ------ | -------- | ---------------------------------- |
| type      | String | yes      | the type of signature              |
| signature | String | yes      | signature string, starts with `0x` |

where the `type` can be `EthereumSignature`, `EIP1271Signature` and `StarkSignature`:

{% tabs %}
{% tab title="EthereumSignature" %}
The ethereum ECDSA signature, for example:

```json
{
   "type": "EthereumSignature",
   "signature": "0xc29d647a5e9e078c66594f04881c34d6b57e1085ab825f17ffb1d0fe233e9834191b374daaaf1e44e5749f6cf44f2143799373fc5e7e844d48fec5e6bc08f0651b"
}
```

{% endtab %}

{% tab title="EIP1271Signature" %}
The ethereum EIP1271 signature, for example:

```json
{
   "type": "EIP1271Signature",
   "signature": "0xc29d647a5e9e078c66594f04881c34d6b57e1085ab825f17ffb1d0fe233e9834191b374daaaf1e44e5749f6cf44f2143799373fc5e7e844d48fec5e6bc08f0651b"
}
```

{% endtab %}

{% tab title="StarkSignature" %}
The starknet ECDSA signature, for example:

```json
{
   "type": "StarkSignature",
   "signature": "0xc29d647a5e9e078c66594f04881c34d6b57e1085ab825f17ffb1d0fe233e9834191b374daaaf1e44e5749f6cf44f2143799373fc5e7e844d48fec5e6bc08f0651b"
}
```

{% endtab %}
{% endtabs %}


# State Update

Updates are generated after zkLinkTx execution, details can be found in [StateUpdateResp](/developer/json-rpc-and-websocket-and-kafka/json-rpc-api#txresp).\
Parsing the updates can get some data that is only known after the transaction is executed, such as the actual withdraw amount of FullExit

## AccountUpdate.

There are 4 types of AccountUpdate:

1. `AccountCreate`: A new account created on the state tree;
2. `AccountChangePubkeyUpdate`: The `pubkey` and `nonce` changed;
3. `BalanceUpdate`: The assets of account and `nonce` changed;
4. `OrderUpdate`: The order slot of the account has changed.

{% tabs %}
{% tab title="AccountCreate" %}

| Name      | Type                                                      | Description         |
| --------- | --------------------------------------------------------- | ------------------- |
| type      | String                                                    | Update Name         |
| updateId  | i32                                                       | Update id           |
| accountId | [AccountId](/developer/api-and-sdk/basic-types#accountid) | The new accout id   |
| address   | String                                                    | The account address |

Transaction that generate `AccountCreate`:

* [Deposit](/developer/api-and-sdk/transaction/deposit)
* [Transfer](/developer/api-and-sdk/transaction/transfer)

For Example:

```json
{
  "type": "AccountCreate",
   "updateId": 40,
   "accountId": 42,
   "address": "0xe4efc3d7b69a19d3ae574cbc2915ddf598efe43f"
}
```

{% endtab %}

{% tab title="AccountChangePubkeyUpdate" %}

| Name          | Type                                                        | Description        |
| ------------- | ----------------------------------------------------------- | ------------------ |
| type          | String                                                      | Update name        |
| updateId      | i32                                                         | Update Id          |
| accountId     | [AccountId](/developer/api-and-sdk/basic-types#accountid)   | Account id         |
| oldPubkeyHash | [PubkeyHash](/developer/api-and-sdk/basic-types#pubkeyhash) | The old pubkeyHash |
| newPubkeyHash | [PubkeyHash](/developer/api-and-sdk/basic-types#pubkeyhash) | The new pubkeyHash |
| oldNonce      | [Nonce](/developer/api-and-sdk/basic-types#nonce)           | The old nonce      |
| newNonce      | [Nonce](/developer/api-and-sdk/basic-types#nonce)           | The new nonce      |

Transaction that generate `AccountChangePubkeyUpdate`:

* [ChangePubKey](/developer/api-and-sdk/transaction/change_pubkey)

For example:

```json
{
  "type": "AccountChangePubkeyUpdate",
  "updateId": 10,
  "accountId": 39,
  "oldPubkeyHash": "0x0000000000000000000000000000000000000000",
  "newPubkeyHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
  "oldNonce": 0,
  "newNonce": 1
}
```

{% endtab %}

{% tab title="BalanceUpdate" %}

| Name         | Type                                                                                                                                 | Description                   |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------- |
| type         | String                                                                                                                               | The update name               |
| updateId     | i32                                                                                                                                  | The update id                 |
| accountId    | [AccountId](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/data_tpes.md#accountid) | The account id                |
| subAccountId | [SubAccountId](/developer/api-and-sdk/basic-types#subaccountid)                                                                      | The subaccount id             |
| coinId       | [TokenId](/developer/api-and-sdk/basic-types#tokenid)                                                                                | The token id                  |
| oldBalance   | String                                                                                                                               | The old balance of subaccount |
| newBalance   | String                                                                                                                               | The new balance of subaccount |
| oldNonce     | [Nonce](/developer/api-and-sdk/basic-types#nonce)                                                                                    | The old nonce of subaccount   |
| newNonce     | [Nonce](/developer/api-and-sdk/basic-types#nonce)                                                                                    | The new nonce of subaccount   |

Transaction that generate `BalanceUpdate`:

* [ChangePubKey](/developer/api-and-sdk/transaction/change_pubkey)
* [Deposit](/developer/api-and-sdk/transaction/deposit)
* [ForcedExit](/developer/api-and-sdk/transaction/forced_exit)
* [FullExit](/developer/api-and-sdk/transaction/full_exit)
* [Transfer](/developer/api-and-sdk/transaction/transfer)
* [Withdraw](/developer/api-and-sdk/transaction/withdraw)
* [OrderMatching](/developer/api-and-sdk/transaction/order_matching)
* [ContractMatching](/developer/api-and-sdk/transaction/contract_matching)
* [Liquidation](/developer/api-and-sdk/transaction/liquidation)
* [AutoDeleveraging](/developer/api-and-sdk/transaction/auto_deleveraging)
* [Funding](/developer/api-and-sdk/transaction/funding)
* [UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var)

For example

```json
{
  "type": "BalanceUpdate",
  "updateId": 1,
  "accountId": 2,
  "subAccountId": 1,
  "coinId": 18,
  "oldBalance": "66517000000000000",
  "newBalance": "66518000000000000",
  "oldNonce": 66518,
  "newNonce": 66519
}
```

{% endtab %}

{% tab title="OrderUpdate" %}

| Name         | Type                                                                                                                                  | Description     |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| type         | String                                                                                                                                | Update name     |
| updateId     | i32                                                                                                                                   | Update id       |
| accountId    | [AccountId](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/basic_type.md#accountid) | Account id      |
| subAccountId | [SubAccountId](/developer/api-and-sdk/basic-types#subaccountid)                                                                       | Subaccount id   |
| slotId       | [SlotId](/developer/api-and-sdk/basic-types#slotid)                                                                                   | Slot id         |
| oldTidyOrder | [ResponseTidyOrder](#responsetidyorder)                                                                                               | Old`TidyOrder`  |
| newTidyOrder | [ResponseTidyOrder](#responsetidyorder)                                                                                               | New `TidyOrder` |

where ResponseTidyOrder is

| Name    | Type            | Description                                                  |
| ------- | --------------- | ------------------------------------------------------------ |
| nonce   | [Nonce](#nonce) | The slot nonce of order                                      |
| residue | String          | The string format of BigDecimal, the residue balance of slot |

Transaction that generate `OrderUpdate`:

* [OrderMatching](/developer/api-and-sdk/transaction/order_matching)

For Example:

```json
{
  "type": "OrderUpdate",
  "updateId": 30,
  "accountId": 11,
  "subAccountId": 1,
  "slotId": 27,
  "oldTidyOrder": {
    "nonce": 14,
    "residue": "4607200000000000000000"
  },
  "newTidyOrder": {
    "nonce": 14,
    "residue": "4233800000000000000000"
  }
}
```

{% endtab %}
{% endtabs %}

## GlobalVarUpdate

`GlobalVarsUpdate` is an enumeration type used to represent the update status of global variables. It includes the following 4 types:

1. `FeeAccountUpdate`: The fee account of global variables changed
2. `InsuranceFundAccountUpdate`: The Insurance fund account of global variables changed
3. `MarginParamsUpdate`: The margin parameter of global variables changed
4. `ContractParamsUpdate`: The contract parameter of global variables changed

{% tabs %}
{% tab title="FeeAccountUpdate" %}

| Field                 | Type                                                                                                                                  | Description        |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| type                  | String                                                                                                                                | The update name    |
| update\_id            | i32                                                                                                                                   | update index       |
| sub\_account\_id      | [SubAccountId](/developer/api-and-sdk/basic-types#subaccountid)                                                                       | sub-account ID     |
| old\_fee\_account\_id | [AccountId](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/basic_type.md#accountid) | Old fee account ID |
| new\_fee\_account\_id | [AccountId](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/basic_type.md#accountid) | New fee account ID |

Transaction that generate `FeeAccountUpdate`:

* [UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var)

For Example:

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "FeeAccountUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "oldFeeAccountId": 0,
  "newFeeAccountId": 3
}
```

{% endtab %}

{% tab title="InsuranceFundAccountUpdate" %}

| Field                             | Type                                                                                                                                  | Description                   |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| type                              | String                                                                                                                                | The update name               |
| update\_id                        | i32                                                                                                                                   | update index                  |
| sub\_account\_id                  | [SubAccountId](/developer/api-and-sdk/basic-types#subaccountid)                                                                       | sub-account id                |
| old\_insurance\_fund\_account\_id | [AccountId](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/basic_type.md#accountid) | old insurance fund account id |
| new\_insurance\_fund\_account\_id | [AccountId](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/basic_type.md#accountid) | new insurance fund account id |

Transaction that generate `InsuranceFundAccountUpdate`:

* [UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var)

For example:

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "InsuranceFundAccountUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "oldInsuranceFundAccountId": 4,
  "newInsuranceFundAccountId": 6
}
```

{% endtab %}

{% tab title="MarginParamsUpdate" %}

| Field             | Type                                                            | Description                           |
| ----------------- | --------------------------------------------------------------- | ------------------------------------- |
| type              | String                                                          | The update name                       |
| update\_id        | i32                                                             | update index                          |
| sub\_account\_id  | [SubAccountId](/developer/api-and-sdk/basic-types#subaccountid) | sub-account id                        |
| margin\_id        | [MarginId](/developer/api-and-sdk/basic-types#marginid)         | margin index                          |
| old\_symbol       | String                                                          | Old symbol of the margin token        |
| new\_symbol       | String                                                          | New symbol of the margin token        |
| old\_index\_price | String                                                          | Old index price of the margin token   |
| new\_index\_price | String                                                          | New index price of the margin token   |
| old\_token\_id    | [TokenId](/developer/api-and-sdk/basic-types#tokenid)           | Old margin token id of the margin\_id |
| new\_token\_id    | [TokenId](/developer/api-and-sdk/basic-types#tokenid)           | New margin token id of the margin\_id |
| old\_ratio        | u8                                                              | Old margin ratio of the margin token  |
| new\_ratio        | u8                                                              | New margin ratio of the margin token  |

Transaction that generate `MarginParamsUpdate`:

* [UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var)

For example

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "MarginParamsUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "marginId": 2,
  "oldSymbol": "",
  "newSymbol": "BTC",
  "oldIndexPrice": "0",
  "newIndexPrice": "0",
  "oldTokenId": 0,
  "newTokenId": 142,
  "oldRatio": 0,
  "newRatio": 90
}
```

{% endtab %}

{% tab title="ContractParamsUpdate" %}

| Field                          | Type                                                            | Description                                      |
| ------------------------------ | --------------------------------------------------------------- | ------------------------------------------------ |
| update\_id                     | i32                                                             | update id                                        |
| sub\_account\_id               | [SubAccountId](/developer/api-and-sdk/basic-types#subaccountid) | sub-account id                                   |
| pair\_id                       | [PairId](/developer/api-and-sdk/basic-types#pairid)             | contract pair id                                 |
| old\_symbol                    | String                                                          | old symbol of the contract pair                  |
| new\_symbol                    | String                                                          | new symbol of the contract pair                  |
| old\_maintenance\_margin\_rate | u16                                                             | old maintenance margin rate of the contract pair |
| new\_maintenance\_margin\_rate | u16                                                             | new maintenance margin rate of the contract pair |
| old\_initial\_margin\_rate     | u16                                                             | old initial margin rate of the contract pair     |
| new\_initial\_margin\_rate     | u16                                                             | new initial margin rate of the contract pair     |
| old\_acc\_funding\_price       | String                                                          | old accumulated funding price the contract pair  |
| new\_acc\_funding\_price       | String                                                          | new accumulative funding price the contract pair |
| old\_mark\_price               | String                                                          | old mark price of the contract pair              |
| new\_mark\_price               | String                                                          | new mark price of the contract pair              |

Transaction that generate `ContractParamsUpdate`:

* [UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var)

For Example:

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "ContractParamsUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "pairId": 0,
  "oldSymbol": "",
  "newSymbol": "BTC/USDT",
  "oldMaintenanceMarginRate": 0,
  "newMaintenanceMarginRate": 5,
  "oldInitialMarginRate": 0,
  "newInitialMarginRate": 10,
  "oldAccFundingPrice": "0",
  "newAccFundingPrice": "0",
  "oldMarkPrice": "0",
  "newMarkPrice": "0"
}
```

{% endtab %}
{% endtabs %}

## Deposit

Updates generated by Deposit:

```
[AccountCreate(to)], BalanceUpdate(to), BalanceUpdate(global_asset)
```

> \[`update`]: this update may occur, `update(account)`: the update related to a certain account. The account id of `global_asset` is 1, and the account id of `fee` is 0.

When the `to` account does not exist, a new account will be automatically created by `AccountCreate`.

### Example

```json
"updates": [
  // As the to_account (accountId is 4) does not exist, an AccountCreate is involved
  {
      "type": "AccountCreate",
      "updateId": 15,
      "accountId": 4,
      "address": "0xb92a8ba62ff1d141798c7133cccefb33d9073323"
  },
  // The balance of the to_account increased, depositAmount=newBalance-oldBalance
  {
      "type": "BalanceUpdate",
      "updateId": 16,
      "accountId": 4,
      "subAccountId": 0,
      "coinId": 18,
      "oldBalance": "0",
      "newBalance": "10000000000000000000",
      "oldNonce": 0,
      "newNonce": 0
  },
  // The 'global asset' account records the increase of on-chain asset reserves
  {
      "type": "BalanceUpdate",
      "updateId": 17,
      "accountId": 1,
      "subAccountId": 2,
      "coinId": 18,
      "oldBalance": "3030000000000000000000",
      "newBalance": "3040000000000000000000",
      "oldNonce": 0,
      "newNonce": 0
  }
]
```

## FullExit

Updates generated by FullExit:

```
BalanceUpdate(exit), BalanceUpdate(global_asset)
```

### Example

```json
"updates": [
  // The balance of the exit_account decreased, exitAmount=oldBalance-newBalance
  {
      "type": "BalanceUpdate",
      "updateId": 0,
      "accountId": 28,
      "subAccountId": 1,
      "coinId": 44,
      "oldBalance": "1080000000000000000",
      "newBalance": "0",
      "oldNonce": 0,
      "newNonce": 0
  },
  // The 'global asset' account records the decrease of on-chain asset reserves
  {
      "type": "BalanceUpdate",
      "updateId": 1,
      "accountId": 1,
      "subAccountId": 1,
      "coinId": 44,
      "oldBalance": "1497300000000000000000",
      "newBalance": "1496220000000000000000",
      "oldNonce": 0,
      "newNonce": 0
  }
]
```

## ChangePubKey

Updates generated by ChangePubKey:

```
AccountChangePubkeyUpdate(target), BalanceUpdate(target), BalanceUpdate(fee)
```

### Example

```json
"updates": [
  // The pubkey of target account was successfully set
 
{
    "type": "AccountChangePubkeyUpdate",
    "updateId": 8,
    "accountId": 2,
    "oldPubkeyHash": "0x0000000000000000000000000000000000000000",
    "newPubkeyHash": "0x870b67b523f93dad7a313f6b64b9608dedab3874",
    "oldNonce": 0,
    "newNonce": 1
  },
  // The balance of the target account decreased
  {
    "type": "BalanceUpdate",
    "updateId": 9,
    "accountId": 2,
    "subAccountId": 0,
    "coinId": 18,
    "oldBalance": "10000000000000000000",
    "newBalance": "9000000000000000000",
    "oldNonce": 1,
    "newNonce": 1
  },
  // The balance of the fee account increased
  {
    "type": "BalanceUpdate",
    "updateId": 10,
    "accountId": 0,
    "subAccountId": 0,
    "coinId": 18,
    "oldBalance": "0",
    "newBalance": "1000000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

## Transfer

Updates generated by Transfer:

```
[AccountCreate(to)], BalanceUpdate(from), BalanceUpdate(to), BalanceUpdate(fee)
```

Similar to [Deposit](#deposit), when the `to` account does not exist, a new account will be automatically created by `AccountCreate`.

### Example

```json
"updates": [
  // The balance of the from_account decreased
  {
    "type": "BalanceUpdate",
    "updateId": 12,
    "accountId": 2,
    "subAccountId": 0,
    "coinId": 18,
    "oldBalance": "3018976060000000000000",
    "newBalance": "3018975850000000000000",
    "oldNonce": 115,
    "newNonce": 116
  },
  // The balance of the to_account increased. Noted that the to_accountId is the same as the from_accountId, but the subAccountId is different
  // It means that this transaction is a token transfer between separate sub-accounts of the same account
  {
    "type": "BalanceUpdate",
    "updateId": 13,
    "accountId": 2,
    "subAccountId": 1,
    "coinId": 18,
    "oldBalance": "114000000000000",
    "newBalance": "115000000000000",
    "oldNonce": 115,
    "newNonce": 116
  },
  // The balance of the fee account increased
  {
    "type": "BalanceUpdate",
    "updateId": 14,
    "accountId": 0,
    "subAccountId": 0,
    "coinId": 18,
    "oldBalance": "1023826000000000000",
    "newBalance": "1024035000000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

## Withdraw

Updates generated by Withdraw:

```
BalanceUpdate(from), BalanceUpdate(global_asset), BalanceUpdate(fee)
```

### Example

```json
"updates": [
  // The from_account balance decreased due to the withdrawal
  {
    "type": "BalanceUpdate",
   

"updateId": 3,
    "accountId": 3,
    "subAccountId": 0,
    "coinId": 44,
    "oldBalance": "2993839561700000000000",
    "newBalance": "2992538030700000000000",
    "oldNonce": 81,
    "newNonce": 82
  },
  // The global asset account records the decrease in on-chain asset reserves
  {
    "type": "BalanceUpdate",
    "updateId": 4,
    "accountId": 1,
    "subAccountId": 1,
    "coinId": 44,
    "oldBalance": "1500000000000000000000",
    "newBalance": "1498700000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  // The balance of the fee account increased
  {
    "type": "BalanceUpdate",
    "updateId": 5,
    "accountId": 0,
    "subAccountId": 0,
    "coinId": 44,
    "oldBalance": "438300000000000",
    "newBalance": "1969300000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

## ForcedExit

Updates generated by ForcedExit:

```
BalanceUpdate(init), BalanceUpdate(target), BalanceUpdate(global_asset), BalanceUpdate(fee)
```

### Example

```json
"updates": [
  // The balance of init account decreased due to the payment of transaction fees
  {
    "type": "BalanceUpdate",
    "updateId": 20,
    "accountId": 3,
    "subAccountId": 0,
    "coinId": 18,
    "oldBalance": "2790050120799999999999",
    "newBalance": "2790031090799999999999",
    "oldNonce": 178,
    "newNonce": 179
  },
  // The amount of the withdrawal to the target account on Layer1: exitAmount=oldBalance-newBalance
  {
    "type": "BalanceUpdate",
    "updateId": 21,
    "accountId": 15,
    "subAccountId": 1,
    "coinId": 40,
    "oldBalance": "2100000000000000000",
    "newBalance": "0",
    "oldNonce": 0,
    "newNonce": 0
  },
  // The global asset account records the decrease in on-chain asset reserves
  {
    "type": "BalanceUpdate",
    "updateId": 22,
    "accountId": 1,
    "subAccountId": 2,
    "coinId": 40,
    "oldBalance": "4000001486590000000000000000",
    "newBalance": "4000001484490000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  //The balance of the fee account increased
  {
    "type": "BalanceUpdate",
    "updateId": 23,
    "accountId": 0,
    "subAccountId": 0,
    "coinId": 18,
    "oldBalance": "7272586000000000000",
    "newBalance": "7291616000000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
```

### OrderMatching

Updates generated by OrderMatching:

```
OrderUpdate(maker), BalanceUpdate(maker), BalanceUpdate(maker),
OrderUpdate(taker), BalanceUpdate(taker), BalanceUpdate(taker),
BalanceUpdate(submitter), BalanceUpdate(submitter), BalanceUpdate(submitter),
BalanceUpdate(fee)
```

### Example

```json
"updates": [
  // Orderslot of the maker
  {
    "type": "OrderUpdate",
    "updateId": 0,
    "accountId": 13,
    "subAccountId": 1,
    "slotId": 898,
    "oldTidyOrder": {
      "nonce": 1,
      "residue": "54800000000000000"
    },
    "newTidyOrder": {
      "nonce": 2,
      "residue": "0"
    }
  },
  // The balance of token0 in the maker account decreased
  {
    "type": "BalanceUpdate",
    "updateId": 1,
    "accountId": 13,
    "subAccountId": 1,
    "coinId": 1,
    "oldBalance": "200304228482442156994500000",
    "newBalance": "200304142493022156994500000",
    "oldNonce": 1,
    "newNonce": 1
  },
  // The balance of token1 in the maker account increased
  {
    "type": "BalanceUpdate",
    "updateId": 2,
    "accountId": 13,
    "subAccountId": 1,
    "coinId": 41,
    "oldBalance": "199999971788889400000000000",
    "newBalance": "199999971843662000000000000",
    "oldNonce": 1,
    "newNonce": 1
  },
  // Orderslot of the taker
  {
    "type": "OrderUpdate",
    "updateId": 3,
    "accountId": 13,
    "subAccountId": 1,
    "slotId": 163,
    "oldTidyOrder": {
      "nonce": 0,
      "residue": "1467400000000000000"
    },
    "newTidyOrder": {
      "nonce": 0,
      "residue": "1412600000000000000"
    }
  },
  // The balance of token1 in the taker account decreased
  {
    "type": "BalanceUpdate",
    "updateId": 4,
    "accountId": 13,
    "subAccountId": 1,
    "coinId": 41,
    "oldBalance": "199999971843662000000000000",
    "newBalance": "199999971788862000000000000",
    "oldNonce": 1,
    "newNonce": 1
  },
  // The balance of token0 in the taker account increased
  {
    "type": "BalanceUpdate",
    "updateId": 5,
    "accountId": 13,
    "subAccountId": 1,
    "coinId": 1,
    "oldBalance": "200304142493022156994500000",
    "newBalance": "200304228396452736994500000",
    "oldNonce": 1,
    "newNonce": 1
  },
  // The submitter balance of token0 decreased due to transaction fees
  {
    "type": "BalanceUpdate",
    "updateId": 6,
    "accountId": 6,
    "subAccountId": 1,
    "coinId": 1,
    "oldBalance": "9999680162000000000000",
    "newBalance": "9999679771000000000000",
    "oldNonce": 224,
    "newNonce": 224
  },
  // The submitter collect token0 as transaction fee
  {
    "type": "BalanceUpdate",
    "updateId": 7,
    "accountId": 6,
    "subAccountId": 0,
    "coinId": 1,
    "oldBalance": "3529001244641983488661500000",
    "newBalance": "3529001244727972908661500000",
    "oldNonce": 224,
    "newNonce": 224
  },
  // The submitter collect token1 as transaction fee
  {
    "type": "BalanceUpdate",
    "updateId": 8,
    "accountId": 6,
    "subAccountId": 0,
    "coinId": 41,
    "oldBalance": "1594000000063937300000000000",
    "newBalance": "1594000000063964700000000000",
    "oldNonce": 224,
    "newNonce": 224
  },
  // The balance of the fee account increased
  {
    "type": "BalanceUpdate",
    "updateId": 9,
    "accountId": 0,
    "subAccountId": 0,
    "coinId": 1,
    "oldBalance": "483683000000000000",
    "newBalance": "484074000000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

### ContractMatching

Updates generated by ContractMatching:

```
OrderUpdate(maker), PositionUpdate(maker), BalanceUpdate(maker),
OrderUpdate(taker), PositionUpdate(taker), BalanceUpdate(taker),
BalanceUpdate(submitter), BalanceUpdate(fee), BalanceUpdate(submitter),
```

### Example

```json
"updates": [
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "OrderUpdate",
    "updateId": 9,
    "accountId": 14,
    "subAccountId": 0,
    "slotId": 61089,
    "oldTidyOrder": {
      "nonce": 0,
      "residue": "0"
    },
    "newTidyOrder": {
      "nonce": 1,
      "residue": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 10,
    "accountId": 14,
    "subAccountId": 0,
    "pairId": 0,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": true,
      "price": "70000000000000000000000",
      "value": "70000000000000000000000",
      "size": "1000000000000000000",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 11,
    "accountId": 14,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "9981900000000000000000",
    "newBalance": "9911900000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "OrderUpdate",
    "updateId": 12,
    "accountId": 14,
    "subAccountId": 0,
    "slotId": 62895,
    "oldTidyOrder": {
      "nonce": 0,
      "residue": "0"
    },
    "newTidyOrder": {
      "nonce": 1,
      "residue": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 13,
    "accountId": 14,
    "subAccountId": 0,
    "pairId": 0,
    "oldPosition": {
      "direction": true,
      "price": "70000000000000000000000",
      "value": "70000000000000000000000",
      "size": "1000000000000000000",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 14,
    "accountId": 14,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "9911900000000000000000",
    "newBalance": "9771900000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 15,
    "accountId": 3,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "18100000000000000000",
    "newBalance": "228100000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 16,
    "accountId": 2,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "0",
    "newBalance": "0",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 17,
    "accountId": 3,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "228100000000000000000",
    "newBalance": "228100000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

### Liquidation

Updates generated by Liquidation:

```
PositionUpdate(liquidator), ......,
PositionUpdate(insurance fund account), ......,
BalanceUpdate(liquidator), 
BalanceUpdate(insurance fund account),
BalanceUpdate(submitter), BalanceUpdate(fee account), 
```

#### Example

```json
"updates": [
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 0,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 0,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "-113682873499983950000"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "-113682873499983950000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 1,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 1,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 2,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 2,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 3,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 3,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 4,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 4,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 5,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 5,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 6,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 6,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "0"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 7,
    "accountId": 21,
    "subAccountId": 0,
    "pairId": 7,
    "oldPosition": {
      "direction": true,
      "price": "3560007803000000000000",
      "value": "35600078030000000000000",
      "size": "10000000000000000000",
      "accFundingPrice": "400710000000000000000"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "400710000000000000000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 8,
    "accountId": 21,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "570283843940000000000",
    "newBalance": "0",
    "oldNonce": 1,
    "newNonce": 1
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 9,
    "accountId": 21,
    "subAccountId": 0,
    "coinId": 17,
    "oldBalance": "1000000000000000000000",
    "newBalance": "0",
    "oldNonce": 1,
    "newNonce": 1
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 10,
    "accountId": 21,
    "subAccountId": 0,
    "coinId": 142,
    "oldBalance": "10099800000000000000",
    "newBalance": "0",
    "oldNonce": 1,
    "newNonce": 1
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 11,
    "accountId": 6,
    "subAccountId": 0,
    "pairId": 7,
    "oldPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "400710000000000000000"
    },
    "newPosition": {
      "direction": true,
      "price": "3560007803000000000000",
      "value": "35600078030000000000000",
      "size": "10000000000000000000",
      "accFundingPrice": "400710000000000000000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 12,
    "accountId": 6,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "0",
    "newBalance": "570283843940000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 13,
    "accountId": 6,
    "subAccountId": 0,
    "coinId": 17,
    "oldBalance": "1000000000000000000000",
    "newBalance": "2000000000000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 14,
    "accountId": 6,
    "subAccountId": 0,
    "coinId": 142,
    "oldBalance": "0",
    "newBalance": "10099800000000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 15,
    "accountId": 2,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "0",
    "newBalance": "0",
    "oldNonce": 0,
    "newNonce": 1
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 16,
    "accountId": 3,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "1298848471059090000000000",
    "newBalance": "1298848471059090000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

### AutoDeleveraging

Updates generated by AutoDeleveraging:

```
PositionUpdate(insurance fund account), BalanceUpdate(insurance fund account),
PositionUpdate(ADL account), BalanceUpdate(ADL account),
BalanceUpdate(submitter), BalanceUpdate(fee),
```

#### Example

```json
"updates": [
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 17,
    "accountId": 6,
    "subAccountId": 0,
    "pairId": 7,
    "oldPosition": {
      "direction": true,
      "price": "3560007803000000000000",
      "value": "35600078030000000000000",
      "size": "10000000000000000000",
      "accFundingPrice": "400710000000000000000"
    },
    "newPosition": {
      "direction": false,
      "price": "0",
      "value": "0",
      "size": "0",
      "accFundingPrice": "400710000000000000000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 18,
    "accountId": 6,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "570283843940000000000",
    "newBalance": "-24986787496060000000000",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 19,
    "accountId": 126,
    "subAccountId": 0,
    "pairId": 7,
    "oldPosition": {
      "direction": false,
      "price": "3559280996274044968406",
      "value": "238450471064383368613418",
      "size": "66994000000000000000",
      "accFundingPrice": "400710000000000000000"
    },
    "newPosition": {
      "direction": false,
      "price": "3559280996274044968406",
      "value": "202857661101642918929355",
      "size": "56994000000000000000",
      "accFundingPrice": "400710000000000000000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 20,
    "accountId": 126,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "1005451189769616631386582",
    "newBalance": "1031000993042357081070645",
    "oldNonce": 0,
    "newNonce": 0
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 21,
    "accountId": 2,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "0",
    "newBalance": "0",
    "oldNonce": 1,
    "newNonce": 2
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 22,
    "accountId": 3,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "1298848471059090000000000",
    "newBalance": "1298848471059090000000000",
    "oldNonce": 0,
    "newNonce": 0
  }
]
```

### funding

Updates generated by funding:

```
PositionUpdate(funding account), PositionUpdate(funding account), 
BalanceUpdate(funding account), BalanceUpdate(fee account),
```

#### Example

```json
[
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 2,
    "accountId": 20,
    "subAccountId": 0,
    "pairId": 0,
    "oldPosition": {
      "direction": true,
      "price": "70726400000000000000000",
      "value": "240469760000000000000000",
      "size": "3400000000000000000",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": true,
      "price": "70726400000000000000000",
      "value": "240469760000000000000000",
      "size": "3400000000000000000",
      "accFundingPrice": "14149851999998000000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "PositionUpdate",
    "updateId": 7,
    "accountId": 20,
    "subAccountId": 0,
    "pairId": 7,
    "oldPosition": {
      "direction": false,
      "price": "3581685331905781584582",
      "value": "5017941150000000000000",
      "size": "1401000000000000000",
      "accFundingPrice": "0"
    },
    "newPosition": {
      "direction": false,
      "price": "3581685331905781584582",
      "value": "5017941150000000000000",
      "size": "1401000000000000000",
      "accFundingPrice": "5374000000000000000"
    }
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 8,
    "accountId": 20,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "294694153026870000000000",
    "newBalance": "294653572504070006800000",
    "oldNonce": 2,
    "newNonce": 2
  },
  {
    "stateUpdateType": "AccountUpdate",
    "accountUpdateType": "BalanceUpdate",
    "updateId": 9,
    "accountId": 4,
    "subAccountId": 0,
    "coinId": 140,
    "oldBalance": "0",
    "newBalance": "0",
    "oldNonce": 4,
    "newNonce": 5
  }
]
```

### update\_global\_var

All updates that may be generated by update\_global\_var:

#### Example

```
FeeAccountUpdate(global)
```

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "FeeAccountUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "oldFeeAccountId": 0,
  "newFeeAccountId": 3
}
```

```
InsuranceFundAccountUpdate(global)
```

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "InsuranceFundAccountUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "oldInsuranceFundAccountId": 4,
  "newInsuranceFundAccountId": 6
}
```

```
MarginParamsUpdate(global)
```

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "MarginParamsUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "marginId": 2,
  "oldSymbol": "",
  "newSymbol": "BTC",
  "oldIndexPrice": "0",
  "newIndexPrice": "0",
  "oldTokenId": 0,
  "newTokenId": 142,
  "oldRatio": 0,
  "newRatio": 90
}
```

```
ContractParamsUpdate(global)
```

```json
{
  "stateUpdateType": "GlobalVarsUpdate",
  "globalVarUpdate": "ContractParamsUpdate",
  "updateId": 0,
  "subAccountId": 0,
  "pairId": 0,
  "oldSymbol": "",
  "newSymbol": "BTC/USDT",
  "oldMaintenanceMarginRate": 0,
  "newMaintenanceMarginRate": 5,
  "oldInitialMarginRate": 0,
  "newInitialMarginRate": 10,
  "oldAccFundingPrice": "0",
  "newAccFundingPrice": "0",
  "oldMarkPrice": "0",
  "newMarkPrice": "0"
}
```

`version: fa4618`


# Transaction


# Deposit

Deposit from Layer 1 to [zkLink layer](/developer/api-and-sdk/transaction/deposit).

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td></td><td></td><td></td><td></td></tr><tr><td>type</td><td>String</td><td>yes</td><td>The value is "Deposit"</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>fromChainId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#chainid">ChainId</a></td><td>yes</td><td>The chain id defined by zkLink, the chain that the deposit is initiated on</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>from</td><td>String</td><td>yes</td><td>The initiator address of the deposit</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>to</td><td>String</td><td>yes</td><td>The recipient of the deposit. An account will be created if it does not exist on zkLink Layer3</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The subaccount id of the recipient</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>l1SourceToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token deducted from the initiator on Layer 1</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>l2TargetToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token received by the recipient on zkLink Layer 3</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>amount</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The amount of deposit</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>serialId</td><td>u64</td><td>yes</td><td>The serial number of the event, used as nonce</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>l2Hash</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#txhash">TxHash</a></td><td>no</td><td>Transaction hash of linea/zksync/starket</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td>ethHash</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#txhash">TxHash</a></td><td>no</td><td>Transaction hash of ethereum, exist when deposit from Ethereum bridge to linea/zksync/starket</td></tr></tbody></table>

For example:

```json
{
    "type": "Deposit",
    "fromChainId": 1,
    "from": "0x76920dfacad4f28f97d6209977c1057b9e3e5cad",
    "subAccountId": 1,
    "l1SourceToken": 18,
    "l2TargetToken": 1,
    "amount": "4000000000000000000000",
    "to": "0x76920dfacad4f28f97d6209977c1057b9e3e5cad",
    "serialId": 53,
    "l2Hash": "0xaaa1e7a5bc48e7cfaa562a4d1a5abc1d6dc5e7f7683e89eb00e895d438f0acab"
}
```


# FullExit

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "FullExit"</td></tr><tr><td>toChainId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#chainid">ChainId</a></td><td>yes</td><td>The chain id defined by zkLink, to which the user wish to withdrawal</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>The id of the withdrawal account</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The id of the subaccount for withdrawal</td></tr><tr><td>exitAddress</td><td>String</td><td>yes</td><td>The Layer1 address of the recipient</td></tr><tr><td>l2SourceToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token deducted from the withdrawal account on Layer3</td></tr><tr><td>l1TargetToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token received by the recipient on Layer 1</td></tr><tr><td>serialId</td><td>u64</td><td>yes</td><td>The serial number of the event, used as nonce</td></tr><tr><td>ethHash</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#txhash">TxHash</a></td><td>yes</td><td>The transaction hash that generated this event on Layer 1</td></tr></tbody></table>

For example:

```json
{
    "type": "FullExit",
    "toChainId": 1,
    "accountId": 25,
    "subAccountId": 1,
    "exitAddress": "0xae08c2e27765faef5cb05908dbac12242caf91af",
    "l2SourceToken": 47,
    "l1TargetToken": 47,
    "serialId": 43,
    "ethHash": "0x748d32538f71d937d9e2c47adc26c499d0451b87e4fd337c2d6190c3271dafd7"
}
```


# ChangePubKey

Modifies the public key hash of the Layer3 account.

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "ChangePubKey"</td></tr><tr><td>chainId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#chainid">ChainId</a></td><td>yes</td><td>ID defined by zkLink, for example, when the user performs ChangePubKey on ETH, the front-end needs to set this value to the Ethereum ID defined by zkLink on Layer3</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>Target account ID of ChangePubKey</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccount">SubAccountId</a></td><td>yes</td><td>Target subaccount ID of ChangePubKey, the fee will be deducted from this subaccount</td></tr><tr><td>newPkHash</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#pubkeyhash">PubkeyHash</a></td><td>yes</td><td>New public key hash</td></tr><tr><td>nonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>Current nonce of the target account</td></tr><tr><td>feeToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token used as the fee token</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Fee obtained via <code>estimateTransactionFee</code> API, the value should be packable</td></tr><tr><td>ethAuthData</td><td><a href="/pages/70l3aRZKdb1EKyQE2GuC">ChangePubKeyAuthData</a></td><td>yes</td><td>ChangePubKeyAuthData to set the public key</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignatur</a></td><td>yes</td><td>the public key hash corresponding to the signature must be aligned with the newPkHash</td></tr><tr><td>ts</td><td>u32</td><td>yes</td><td>Timestamp of the API call, used as front-end request id to generate transaction hash</td></tr></tbody></table>

where the ChangePubKeyAuthData is an Enum which contains 3 types: `EthECDSA`, `EthCreate2`, `Onchain`

{% tabs %}
{% tab title="EthECDSA" %}

| Name         | Type   | Required | Description                    |
| ------------ | ------ | -------- | ------------------------------ |
| type         | String | yes      | The value is "EthECDSA"        |
| ethSignature | String | yes      | eth signature with `0x` prefix |

Refer to [EIP712](https://eips.ethereum.org/EIPS/eip-712) to create the signature content in this way, where the domain is:

```json
{
  "name":"ZkLink", // constaint
  "version":"1", // constaint
  "chainId":13, // this this the L1 chain id, not the one defined by zkLink
  "verifyingContract":"0x388c818ca8b9251b393131c08a736a67ccb19297" // this is the zkLink contract address on L1
}
```

> Note: Different chain has different `chainId` and `verifyingContract`, you can get the chain information from rpc interface `getSupportChains`.

For Example:

```json
{
  "type": "ChangePubKey",
  "chainId": 1,
  "accountId": 39,
  "subAccountId": 1,
  "newPkHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
  "feeToken": 1,
  "fee": "1285000000000000",
  "nonce": 0,
  "signature": {
    "pubKey": "0xed53a138751ed1e456f46e74eff3463d2420e488a4f608bde0f28d13c7104d29",
    "signature": "3b91c0421df4295281596746722ae20ccf270c5fc0561f93a0219db1faea6518f033e778dd552f90a9a6afd06427428b2ac4ea6f6893a3f162b32683d1108a02"
  },
  "ethAuthData": {
    "type": "EthECDSA",
    "ethSignature": "0x8e548e3727a94533b3963877b87966e308e6eef7762f78de567ff14b4e0e87780d37a845501ffd2cdbc7d6f0d620c14589212761f1637ea8214b0b6bac10aa9b1b"
  },
  "ts": 1675650037
}
```

{% endtab %}

{% tab title="EthCreate2" %}

| Name           | Type   | Required | Description                                            |
| -------------- | ------ | -------- | ------------------------------------------------------ |
| type           | String | yes      | The value is "EthCreate2"                              |
| creatorAddress | String | yes      | creator address                                        |
| saltArg        | String | yes      | The salt argument when create address, H256 hex string |
| codeHash       | String | yes      | code hash, H256 hex string                             |

Refer to [EIP1271](https://eips.ethereum.org/EIPS/eip-1271) to create a contract address, then the ChangePubKey is executed by the account that can successfully call the contract's isValidSignature method.

For Example:

```json
{
  "type": "ChangePubKey",
  "chainId": 1,
  "accountId": 39,
  "subAccountId": 1,
  "newPkHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
  "feeToken": 1,
  "fee": "1285000000000000",
  "nonce": 0,
  "signature": {
    "pubKey": "0xed53a138751ed1e456f46e74eff3463d2420e488a4f608bde0f28d13c7104d29",
    "signature": "3b91c0421df4295281596746722ae20ccf270c5fc0561f93a0219db1faea6518f033e778dd552f90a9a6afd06427428b2ac4ea6f6893a3f162b32683d1108a02"
  },
  "ethAuthData": {
    "type":"EthCreate2",
    "creatorAddress":"0x388c818ca8b9251b393131c08a736a67ccb19297",
    "saltArg":"0x66b8e2fa879542a0c32c77e137ab830c3345788a2696999afbd07acabab8ad81",
    "codeHash":"0xfb57f5a066444ff426f4433344fd2e179843fd9069c06eb3b4ecc74e8b599410"
  },
  "ts": 1675650037
}
```

{% endtab %}

{% tab title="Onchain" %}

| Name | Type   | Required | Description            |
| ---- | ------ | -------- | ---------------------- |
| type | String | yes      | The value is "Onchain" |

Before sending the transaction, you must use the layer1 address of the account to call the `setAuthPubkeyHash` interface(by call the `setAuthPubkeyHash` function of Wallet in sdk) of the ZkLink contract to pre-set the PubkeyHash for your layer2 account (the ChangePubKey tx will be checked against the ZkLink contract after on-chain).

For Example:

```json
{
  "type": "ChangePubKey",
  "chainId": 1,
  "accountId": 39,
  "subAccountId": 1,
  "newPkHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
  "feeToken": 1,
  "fee": "1285000000000000",
  "nonce": 0,
  "signature": {
    "pubKey": "0xed53a138751ed1e456f46e74eff3463d2420e488a4f608bde0f28d13c7104d29",
    "signature": "3b91c0421df4295281596746722ae20ccf270c5fc0561f93a0219db1faea6518f033e778dd552f90a9a6afd06427428b2ac4ea6f6893a3f162b32683d1108a02"
  },
  "ethAuthData": {
      "type": "Onchain"
  },
  "ts": 1675650037
}
```

{% endtab %}
{% endtabs %}

### sign

{% tabs %}
{% tab title="Golang" %}

```go
import (
    time
    fmt
    sdk "github.com/zkLinkProtocol/zklink_sdk/generated/uniffi/zklink_sdk"
)

func SignChangePubkey {
    ethSignature := sdk.PackedEthSignature("0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b")
    // get current timestamp
    now := time.Now()
    timeStamp := sdk.TimeStamp(now.Unix())
    mainContract := sdk.ZkLinkAddress("0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896")

    // create ChangePubKey transaction type without signed
    builder := sdk.ChangePubKeyBuilder{
		ChainId: sdk.ChainId(1),
		AccountId: sdk.AccountId(1),
		SubAccountId: sdk.SubAccountId(4),
		NewPubkeyHash: sdk.PubKeyHash("0xd8d5fb6a6caef06aa3dc2abdcdc240987e5330fe"),
		FeeToken: sdk.TokenId(1),
		Fee: *big.NewInt(100),
		Nonce: sdk.Nonce(100),
		EthSignature: &ethSignature,
		Timestamp: timeStamp,
    }
    tx := sdk.NewChangePubKey(builder)
    l1ClientId := uint32(1)
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignChangePubkeyWithEthEcdsaAuth(tx, l1ClientId, mainContract)
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="Javascript" %}

```js
import init, *  as wasm  from "/path/to/zklink-sdk-web.js";

async function testEcdsaAuth() {
    await init();
    const main_contract = "0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896";
    const l1_client_id = 80001;
    const new_pubkey_hash = "0xd8d5fb6a6caef06aa3dc2abdcdc240987e5330fe";
    const ts  = Math.floor(Date.now() / 1000);
    try {
        let tx_builder = new wasm.ChangePubKeyBuilder(
            1,5,1,new_pubkey_hash,18,"100000000000000",
            1,"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b",
            ts);
        let tx = wasm.newChangePubkey(tx_builder);
        const signer = new wasm.JsonRpcSigner();
        await signer.initZklinkSigner();
        let tx_signature = await signer.signChangePubkeyWithEthEcdsaAuth(tx,l1_client_id,main_contract);
        console.log(tx_signature);
        let submitter_signature = signer.submitterSignature(tx_signature.tx);
        console.log(submitter_signature);
        //send to zklink
        let rpc_client = new wasm.RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(tx_signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }
}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# Withdraw

Withdraw from zkLink L2 to connected networks.

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "Withdraw"</td></tr><tr><td>toChainId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#chainid">ChainId</a></td><td>yes</td><td>The target chain of the withdrawal</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>TheID of the withdraw account</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The ID of the withdraw subaccount</td></tr><tr><td>to</td><td>String</td><td>yes</td><td>The target address of the withdrawal</td></tr><tr><td>l2SourceToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#TokenId">TokenId</a></td><td>yes</td><td>The source token to be deducted from the Layer3 account and used as the fee token</td></tr><tr><td>l1TargetToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#TokenId">TokenId</a></td><td>yes</td><td>The target token to be sent to the to_address on Layer1</td></tr><tr><td>amount</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Withdrawal amount, the value does not have to be packable</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Fee requested via <code>estimateTransactionFee</code> API, the value should be packable</td></tr><tr><td>withdrawToL1</td><td>u8</td><td>yes</td><td>1: true, 0: false. Withdraw to L1 or not</td></tr><tr><td>withdrawFeeRatio</td><td>u16</td><td>yes</td><td>Transaction fee for fast withdraw, 100 as 1%, 10000 as 100%, If ratio is not zero means fast withdraw, Value range: [0, 10000]</td></tr><tr><td>ts</td><td>u32</td><td>yes</td><td>Timestamp of the API call, used as front-end request id to generate transaction hash</td></tr><tr><td>nonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>Current nonce of the account</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>the public key hash corresponding to the signature must be aligned with the withdraw account</td></tr></tbody></table>

For Example:

```json
{
  "type": "Withdraw",
  "toChainId": 1,
  "accountId": 7,
  "subAccountId": 2,
  "to": "0x3498f456645270ee003441df82c718b56c0e6666",
  "l2SourceToken": 1,
  "l1TargetToken": 17,
  "amount": "995900000000000000",
  "fee": "4100000000000000",
  "withdrawToL1": 0,
  "withdrawFeeRatio": 50,
  "ts": 1646102148,
  "nonce": 0,
  "signature": {
    "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
    "signature": "a8719d0f771f34a177bbf199ab7b0decd03b5db29edf173ed980d19c7864c5a3761111620ab1982ef1bb7459d5a919727e51b895799e2706ddd5a5328146eb01"
  }
}
```

### sign Withdraw

{% tabs %}
{% tab title="Golang" %}

```go
import (
	"math/big"
	"fmt"
	"time"
	sdk "github.com/zkLinkProtocol/zklink_sdk/go_example/generated/uniffi/zklink_sdk"
)

func SignWithdraw() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
	accountId := sdk.AccountId(8300)
	subAccountId := sdk.SubAccountId(4)
	toChainId := sdk.ChainId(1)
    toAddress := sdk.ZkLinkAddress("0xAFAFf3aD1a0425D792432D9eCD1c3e26Ef2C42E9")
    l3SourceToken := sdk.TokenId(6)
    l1TargetToken := sdk.TokenId(5)
	amount := *big.NewInt(1000000)
	fee := *big.NewInt(1000)
	nonce := sdk.Nonce(1)
	withdrawFeeRatio := uint16(50)
    // get current timestamp
    now := time.Now()
    timestamp := sdk.TimeStamp(now.Unix())
    builder := sdk.WithdrawBuilder{
        AccountId: accountId,
        ToChainId: toChainId,
        SubAccountId: subAccountId,
        ToAddress: toAddress,
        L2SourceToken: l3SourceToken,
        L1TargetToken: l1TargetToken,
        Amount: amount,
        Fee: fee,
        Nonce: nonce,
        WithdrawToL1: true,
        WithdrawFeeRatio: withdrawFeeRatio,
        Timestamp: timestamp,
    }
    tx := sdk.NewWithdraw(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignWithdraw(tx, "USDT")
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more details please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
import init, *  as wasm  from "/path/to/zklink-sdk-web.js";

async function sign_withdraw() {
    await init();
    const to_address = "0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896";
    const ts  = Math.floor(Date.now() / 1000);
    try {

        let tx_builder = new wasm.WithdrawBuilder(10, 1, 1, to_address,18, "100000000000000", false,10,18,"10000000000000000", 1,ts);
        let withdraw = wasm.newWithdraw(tx_builder);
        let signer = new wasm.JsonRpcSigner();
        await signer.initZklinkSigner();
        let signature = await signer.signWithdraw(withdraw,"USDC")
        console.log(signature);

        let submitter_signature = signer.submitterSignature(signature.tx);
        console.log(submitter_signature);
        let rpc_client = new wasm.RpcClient("testnet");
        let l1_signature = new wasm.TxLayer1Signature(wasm.L1SignatureType.Eth,signature.eth_signature);
        let tx_hash = await rpc_client.sendTransaction(signature.tx,l1_signature,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# Transfer

L3 transfer

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "Transfer"</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>Account ID of the from_account</td></tr><tr><td>fromSubAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>Subaccount ID of the from_account</td></tr><tr><td>toSubAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>Sub-account ID of the to_account</td></tr><tr><td>to</td><td>String</td><td>yes</td><td>Account address of the to_account, if the account does not exist, a new account will be automatically created on zkLink Layer3 for this address</td></tr><tr><td>token</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>Token ID</td></tr><tr><td>amount</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Token amount, the value must be packable</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Fee returned by <code>estimateTransactionFee</code> API, the value should be packable</td></tr><tr><td>nonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>Current nonce of the account |</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>the public key hash corresponding to the signature must be aligned with the from_account</td></tr><tr><td>ts</td><td>u32</td><td>yes</td><td>Timestamp of the API call, used as front-end request id to generate transaction hash</td></tr></tbody></table>

For example:

```json
{
  "type": "Transfer",
  "accountId": 8,
  "fromSubAccountId": 3,
  "toSubAccountId": 3,
  "to": "0xbfDa941Bd2a0eddB57b10f8E8d3486A738B92cCC",
  "token": 3,
  "amount": "998000000000000000",
  "fee": "3000000000000000",
  "ts": 1646101085,
  "nonce": 1,
  "signature": {
    "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
    "signature": "892c622afac908201df54a3cfdecf8eba46d5411bdc29365f5536f024c195f2893d6313a6371fe1659830e2560c1eaedbafcc835837593d017cd557074f0bb03"
  }
}
```

### sign Transfer

{% tabs %}
{% tab title="Golang" %}

```go
import (
	"math/big"
	"fmt"
	sdk "github.com/zkLinkProtocol/zklink_sdk/go_example/generated/uniffi/zklink_sdk"
)
func SignTransfer() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
    address := sdk.ZkLinkAddress("0xAFAFf3aD1a0425D792432D9eCD1c3e26Ef2C42E9")
    builder := sdk.TransferBuilder {
        sdk.AccountId(1),
        address,
        sdk.SubAccountId(1),
        sdk.SubAccountId(1),
        sdk.TokenId(18),
        *big.NewInt(100000),
        *big.NewInt(100),
        sdk.Nonce(1),
        sdk.TimeStamp(1693472232),
    }
    tokenSymbol := "DAI"
    tx := sdk.NewTransfer(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignTransfer(tx, tokenSymbol)
    if err != nil {
        return
    }
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more details please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="Javascript" %}

```javascript
import init, *  as wasm  from "./web-dist/zklink-sdk-web.js";

async function main() {
    await init();
    const to_address = "0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896";
    const ts  = Math.floor(Date.now() / 1000);
    try {
        let amount = wasm.closestPackableTransactionAmount("1234567899808787");
        let fee = wasm.closestPackableTransactionFee("10000567777")
        let tx_builder = new wasm.TransferBuilder(10, to_address, 1,
            1, 18, fee, amount, 1,ts);
        let transfer = wasm.newTransfer(tx_builder);
        let signer = new wasm.JsonRpcSigner();
        await signer.initZklinkSigner();
        let signature = await signer.signTransfer(transfer,"USDC")
        console.log(signature);

        let submitter_signature = signer.submitterSignature(signature.tx);
        console.log(submitter_signature);
        let rpc_client = new wasm.RpcClient("testnet");
        let l1_signature = new wasm.TxLayer1Signature(wasm.L1SignatureType.Eth,signature.eth_signature);
        let tx_hash = await rpc_client.sendTransaction(signature.tx,l1_signature,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

{% endtab %}
{% endtabs %}


# ForcedExit

Forced withdraw from Layer3

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "ForcedExit"</td></tr><tr><td>toChainId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#chainid">ChainId</a></td><td>yes</td><td>The target chain of the withdrawal</td></tr><tr><td>initiatorAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>Account ID of the transaction initiator</td></tr><tr><td>initiatorSubAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>Subaccount ID of the transaction initiator</td></tr><tr><td>initiatorNonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>Nonce of the transaction initiator's subaccount</td></tr><tr><td>target</td><td>String</td><td>yes</td><td>The account address of the forced withdraw, the token on Layer 1 is also sent to this address</td></tr><tr><td>targetSubAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>Subaccount ID of the account of the forced withdraw</td></tr><tr><td>l2SourceToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token deducted from the account of the forced withdraw</td></tr><tr><td>l1TargetToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>This token sent to the to_address on L1</td></tr><tr><td>exitAmount</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Withdrawal amount</td></tr><tr><td>withdrawToL1</td><td>u8</td><td>yes</td><td>1: true, 0: false. withdraw to L1 or not</td></tr><tr><td>ts</td><td>u32</td><td>yes</td><td>Timestamp of the API call, used as front-end request id to generate transaction hash</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>the public key hash corresponding to the signature must be aligned with the initiator account</td></tr></tbody></table>

For example:

```json
{
  "type": "ForcedExit",
  "toChainId": 1,
  "initiatorAccountId": 7,
  "initiatorSubAccountId": 3,
  "initiatorNonce":4,
  "target": "0x3498f456645270ee003441df82c718b56c0e6666",
  "targetSubAccountId": 2,
  "l2SourceToken": 1,
  "l1TargetToken": 17,
  "exitAmount": "4100000000000000",
  "ts": 1646102148,
  "withdrawToL1": 0,
  "signature": {
    "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
    "signature": "a8719d0f771f34a177bbf199ab7b0decd03b5db29edf173ed980d19c7864c5a3761111620ab1982ef1bb7459d5a919727e51b895799e2706ddd5a5328146eb01"
  }
}
```

### sign ForcedExit

{% tabs %}
{% tab title="Golang" %}

```go
func SignForcedExit() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
    address := sdk.ZkLinkAddress("0xAFAFf3aD1a0425D792432D9eCD1c3e26Ef2C42E9")
    builder := sdk.ForcedExitBuilder{
        ToChainId: sdk.ChainId(1),
        InitiatorAccountId: sdk.AccountId(1),
        TargetSubAccountId: sdk.SubAccountId(1),
        Target: address,
        InitiatorSubAccountId: sdk.SubAccountId(1),
        L2SourceToken: sdk.TokenId(18),
        L1TargetToken: sdk.TokenId(18),
        InitiatorNonce: sdk.Nonce(1),
        ExitAmount: *big.NewInt(100000),
        WithdrawToL1: false,
        Timestamp: sdk.TimeStamp(1693472232),
    }
    tx := sdk.NewForcedExit(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignForcedExit(tx)
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
import init, *  as wasm  from "/path/to/zklink-sdk-web.js";

async function main() {
    await init();
    const to_address = "0x5505a8cD4594Dbf79d8C59C0Df1414AB871CA896";
    const ts  = Math.floor(Date.now() / 1000);
    try {
        let tx_builder = new wasm.ForcedExitBuilder(1,10, 1, 1, to_address,18, 18,"100000000000000",  1,ts);
        let forced_exit = wasm.newForcedExit(tx_builder);
        let signer = new wasm.JsonRpcSigner();
        await signer.initZklinkSigner();
        let signature = signer.signForcedExit(forced_exit)
        console.log(signature);

        let submitter_signature = signer.submitterSignature(signature.tx);
        console.log(submitter_signature);
        let rpc_client = new wasm.RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# OrderMatching

Order Matching

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>OrderMatching</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>Initiator's account id. Only specific accounts can initiate this type of transaction on Layer3</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">SubAccountId</a></td><td>yes</td><td>Initiator's subaccount id</td></tr><tr><td>taker</td><td><a href="https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/transaction/order/README.md">Order</a></td><td>yes</td><td>taker order</td></tr><tr><td>maker</td><td><a href="https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data-types/transaction/order/README.md">Order</a></td><td>yes</td><td>maker order</td></tr><tr><td>feeToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>Fee token, deducted from the initiator's subaccount</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>Fee returned via the <code>estimateTransactionFee</code> API. The value should be packable</td></tr><tr><td>expectBaseAmount</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The maximum amount of base token that the initiator expects to be traded in this order matching, which cannot exceed the maximum amount that the maker and taker can actually trade. The value does not need to be packable</td></tr><tr><td>expectQuoteAmount</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The maximum amount of quote token that the initiator expects to be traded in this order matching, which cannot exceed the maximum amount that the maker and taker can actually trade. The value does not need to be packable</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>The pub key hash corresponding to the signature must be aligned with the initiator account</td></tr></tbody></table>

\<a id="order>where the type `Order` is

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">Accountid</a></td><td>yes</td><td>The Account id</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The sub-account id</td></tr><tr><td>slotId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#slotid">SlotId</a></td><td>yes</td><td>slot id</td></tr><tr><td>nonce</td><td>Nonce</td><td>yes</td><td>slot nonce, Value range: [0, 2^24 - 1]</td></tr><tr><td>baseTokenId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>the base token, for example `BTC` in BTC/USDT pair</td></tr><tr><td>quoteTokenId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The quote token, for example `USDT` in BTC/USDT pair</td></tr><tr><td>amount</td><td>String</td><td>yes</td><td>The string format of BigUint, the amount request in this order</td></tr><tr><td>price</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>yes</td><td>The string format of BigUint, the price request in this order, the value can't be zero</td></tr><tr><td>isSell</td><td>u8</td><td>yes</td><td>1:seller, 0: buyer</td></tr><tr><td>feeRates</td><td>[u8, u8]</td><td>yes</td><td>the fee of [maker, taker], 100 means 1.0%, the maximum 2.56%</td></tr><tr><td>hasSubsidy</td><td>u8</td><td>yes</td><td>1: true, 0: false. If maker has subsidy, the submitter will give maker subsidy</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#ZkLinkSignature">ZkLinkSignature</a></td><td>yes</td><td>The ZkLink signature of this order</td></tr></tbody></table>

For example:

```json
{
  "type": "OrderMatching",
  "accountId": 4,
  "subAccountId": 1,
  "taker": {
    "accountId": 11,
    "subAccountId": 1,
    "slotId": 5844,
    "nonce": 24,
    "baseTokenId": 42,
    "quoteTokenId": 1,
    "amount": "373400000000000000000",
    "price": "1210900000000000000",
    "isSell": 1,
    "feeRates": [5, 10],
    "signature": {
      "pubKey": "0x1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
      "signature": "3a5c5c23a74cc04d256f03eb1671acd3959d707252ed52b16cb7b2ffe332a804986e09e0d62bcf49fc9231b38f07b71199769a7343eddc8b43ed9dd2ef8a4405"
    }
  },
  "maker": {
    "accountId": 11,
    "subAccountId": 1,
    "slotId": 5915,
    "nonce": 14,
    "baseTokenId": 42,
    "quoteTokenId": 1,
    "amount": "5165400000000000000000",
    "price": "1210900000000000000",
    "isSell": 0,
    "feeRates": [5, 10],
    "signature": {
      "pubKey": "0x1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
      "signature": "9579e54f53aa709e72c7e4de9815d258cf92bb3e9c4b9d03c2f79a7a49b5bda062d7e81b278eb62f2452294d178728b460efdb80017c83748dd190e41e05b802"
    }
  },
  "fee": "405000000000000",
  "feeToken": 1,
  "expectBaseAmount": "373400000000000000000",
  "expectQuoteAmount": "452150060000000000000",
  "signature": {
    "pubKey": "0x84bf4edbe1f7056f079ba4c38359427f43d529fbab2e94e6d6b7a18efbf2fb87",
    "signature": "1242830780b17dd362e8d31952deab6d8b5d81cadd62779b2caab0821baa030a770afa9a2c249d8f45000c4b9c6f01ef6b002682760e5bc4e5d39ef7f511ce03"
  }
}
```

### Sign OrderMatching

{% tabs %}
{% tab title="Golang" %}

```go
import (
	"math/big"
	"fmt"
	sdk "github.com/zkLinkProtocol/zklink_sdk/go_example/generated/uniffi/zklink_sdk"
)

func SignOrderMatching() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
    // create zklink signer
	zklinkSigner, err := sdk.ZkLinkSignerNewFromHexEthSigner(privateKey)
	if err != nil {
		return
	}
    taker := sdk.NewOrder(
        sdk.AccountId(1),
        sdk.SubAccountId(1),
        sdk.SlotId(3),
        sdk.Nonce(1),
        sdk.TokenId(18),
        sdk.TokenId(145),
        *big.NewInt(323289),
        *big.NewInt(135),
        true,
        2,
        5,
        nil,
    )
    taker, err = sdk.CreateSignedOrder(
        zklinkSigner,
        taker,
    )

    maker := sdk.NewOrder(
         sdk.AccountId(2),
         sdk.SubAccountId(1),
         sdk.SlotId(3),
         sdk.Nonce(1),
         sdk.TokenId(18),
         sdk.TokenId(145),
         *big.NewInt(323355),
         *big.NewInt(135),
         false,
         2,
         5,
         nil,
    )
    maker, err = sdk.CreateSignedOrder(
        zklinkSigner,
        maker,
    )

    builder := sdk.OrderMatchingBuilder{
        sdk.AccountId(3),
        sdk.SubAccountId(1),
        taker,
        maker,
        *big.NewInt(1000),
        sdk.TokenId(18),
        *big.NewInt(808077878),
        *big.NewInt(5479779),
    }
    tx := sdk.NewOrderMatching(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignOrderMatching(tx)
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
import init, *  as wasm  from "/path/to/zklink-sdk-web.js";

async function sign_order_matching() {
    await init();
    try {
        let signer = new wasm.JsonRpcSigner();
        await signer.initZklinkSigner();
        let maker = new wasm.Order(5,1,1,1,18,17,"10000000000000","10000000000",true,5,3);
        let signed_maker = signer.createSignedOrder(maker);
        console.log(signed_maker);
        let taker = new wasm.Order(5,1,1,1,18,17,"10000000000000","10000000000",false,5,3);
        let signed_taker = signer.createSignedOrder(taker_order);
        console.log(signed_taker);
        let tx_builder = new wasm.OrderMatchingBuilder(10, 1, signed_taker, signed_maker, "1000000000", 18,"10000000000000000", "10000000000000000");
        let order_matching = wasm.newOrderMatching(tx_builder);
        let signature = signer.signOrderMatching(order_matching);
        console.log(signature);

        let submitter_signature = signer.submitterSignature(signature.tx);
        console.log(submitter_signature);
        let rpc_client = new wasm.RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }
}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# AutoDeleveraging

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "AutoDeleveraging"</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>Account id</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>Subaccount id</td></tr><tr><td>subAccountNonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>The nonce of subaccount</td></tr><tr><td>oraclePrices</td><td>struct</td><td>yes</td><td>contains all infomation about contract price and margin price</td></tr><tr><td>> contractPrices</td><td>array</td><td>yes</td><td><a href="/pages/A9izOaSjjohWewTX2HHj">ContractPrice</a> array</td></tr><tr><td>> marginPrices</td><td>array</td><td>yes</td><td><a href="/pages/A9izOaSjjohWewTX2HHj">SpotPriceInfo</a> array</td></tr><tr><td>adlAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>The ADL account id</td></tr><tr><td>pairId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#pairid">PairId</a></td><td>yes</td><td>The pair id, for example the id of BTC-USDT pair</td></tr><tr><td>adlSize</td><td>BigUint</td><td>yes</td><td>The ADL size, the value can't be zero</td></tr><tr><td>adlPrice</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>yes</td><td>The ADL price, the value can't be zero</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The fee</td></tr><tr><td>feeToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token id of the fee</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>The pub key hash corresponding to the signature must be aligned with the initiator account</td></tr></tbody></table>

where the `ContractPrice` and `SpotPriceInfo` defined as below:

{% tabs %}
{% tab title="ContractPrice" %}

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>pairId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#pairid">PairId</a></td><td>yes</td><td>The pair id of trade pair, for example the id of BTC-USDT pair</td></tr><tr><td>marketPrice</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>yes</td><td>The market price of the associated pair</td></tr></tbody></table>
{% endtab %}

{% tab title="SpotPriceInfo" %}

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>tokenId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The pair id of trade pair, for example the id of BTC-USDT pair</td></tr><tr><td>price</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>yes</td><td>The spot price</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

For example:

```json

{
  "type": "AutoDeleveraging",
  "accountId": 0,
  "subAccountId": 0,
  "subAccountNonce": 0,
  "oraclePrices": {
    "contractPrices": [
      {
        "pairId": 1,
        "marketPrice": "100"
      }
    ],
    "marginPrices": [
      {
        "tokenId": 1,
        "price": "100"
      }
    ]
  },
  "adlAccountId": 0,
  "pairId": 0,
  "adlSize": "0",
  "adlPrice": "0",
  "fee": "100",
  "feeToken": 1,
  "signature": {
    "pubKey": "0x43cbec0bf142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
    "signature": "366e759d61a5052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
  }
}
```

### Sign autoDeleveraging

{% tabs %}
{% tab title="Golang" %}

```go
import (
    fmt
    sdk "github.com/zkLinkProtocol/zklink_sdk/generated/uniffi/zklink_sdk"
)
func SignAutoDeleveraging() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
    contract_price1 := sdk.ContractPrice{
        sdk.PairId(1),
        *big.NewInt(656566),
    }

    contract_price2 := sdk.ContractPrice{
        sdk.PairId(3),
        *big.NewInt(52552131),
    }

    var contract_prices = make([]sdk.ContractPrice,2)
    contract_prices[0] = contract_price1
    contract_prices[1] = contract_price2

    margin_price1 := sdk.SpotPriceInfo {
       sdk.TokenId(17),
       *big.NewInt(3236653653635635),
    }
    margin_price2 := sdk.SpotPriceInfo {
      sdk.TokenId(18),
      *big.NewInt(549574875297),
    }

    var margin_prices = make([]sdk.SpotPriceInfo,2)
    margin_prices[0] = margin_price1
    margin_prices[1] = margin_price2

    builder := sdk.AutoDeleveragingBuilder{
        sdk.AccountId(3),
        sdk.SubAccountId(1),
        sdk.Nonce(9),
        contract_prices,
        margin_prices,
        sdk.AccountId(7),
        sdk.PairId(3),
        *big.NewInt(1000),
        *big.NewInt(100000000000),
         *big.NewInt(10000),
        sdk.TokenId(18),
    }
    tx := sdk.NewAutoDeleveraging(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignAutoDeleveraging(tx)
    if err != nil {
        return
    }
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
const {AutoDeleveragingBuilder,Signer,newAutoDeleveraging,ContractPrice,SpotPriceInfo,RpcClient } = require('./node-dist/zklink-sdk-node');

async function testAutoDeleveraging() {
    const private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4";
    try {
        const contract_price1 = new ContractPrice(1,"10000000000000");
        const contract_price2 = new ContractPrice(1,"2000000000000");
        let contract_prices = [];
        contract_prices.push(contract_price1.jsonValue());
        contract_prices.push(contract_price2.jsonValue());

        let margin_prices = [];
        const margin_price1 = new SpotPriceInfo(17,"3236653653635635");
        const margin_price2 = new SpotPriceInfo(18,"549574875297");
        margin_prices.push(margin_price1.jsonValue());
        margin_prices.push(margin_price2.jsonValue());
        let tx_builder = new AutoDeleveragingBuilder(5,1,10,contract_prices,margin_prices,3,2,"33535545","188888","199",17);
        let tx = newAutoDeleveraging(tx_builder);
        console.log(tx);
        const signer = new Signer(private_key);
        let tx_signature = signer.signAutoDeleveraging(tx);
        console.log(tx_signature);

        let submitter_signature = signer.submitterSignature(tx_signature.tx);
        console.log(submitter_signature);
        //send to zklink
        let rpc_client = new RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(tx_signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# ContractMatching

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "ContractMatching"</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>The account id</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The subaccount id</td></tr><tr><td>maker</td><td>Array of Contracts</td><td>yes</td><td>The maker list</td></tr><tr><td>taker</td><td>Contract</td><td>yes</td><td>The taker</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The fee amount of ContractMatching</td></tr><tr><td>feeToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token id of the fee</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>the pub key hash corresponding to the signature must be aligned with the account</td></tr></tbody></table>

where the `Contract` is the order in perpetual contract

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>account id</td><td></td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>sub account id</td><td></td></tr><tr><td>slotId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#slotid">SlotId</a></td><td>slot id</td><td></td></tr><tr><td>nonce</td><td>Nonce</td><td>slot nonce, Value range: [0, 2^24 - 1]</td><td></td></tr><tr><td>pairId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#pairid">PairId</a></td><td>the pair id</td><td></td></tr><tr><td>size</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>position size</td><td></td></tr><tr><td>price</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>price, the value can't be zero</td><td></td></tr><tr><td>direction</td><td>u8</td><td>1: long, 0: short</td><td></td></tr><tr><td>feeRates</td><td>[u8, u8]</td><td>The fee rates of [maker, taker], 100 means 1.00%, max is 2.56%</td><td></td></tr><tr><td>hasSubsidy</td><td>u8</td><td>1: true, 0: false, if the maker has subsidy, the submitter will give maker subsidy</td><td></td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#ZkLinkSignature">ZkLinkSignature</a></td><td>ZkLink L3 signature</td><td></td></tr></tbody></table>

For example:

```json
{
  "type": "ContractMatching",
  "accountId": 0,
  "subAccountId": 0,
  "maker": [
    {
      "accountId": 0,
      "subAccountId": 0,
      "slotId": 0,
      "nonce": 0,
      "pairId": 0,
      "size": "0",
      "price": "0",
      "direction": 0,
      "feeRates": [
        0,
        0
      ],
      "hasSubsidy": 0,
      "signature": {
        "pubKey": "0x99575738f142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
        "signature": "957826468392052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
      }
    }
  ],
  "taker": {
    "accountId": 0,
    "subAccountId": 0,
    "slotId": 0,
    "nonce": 0,
    "pairId": 0,
    "size": "0",
    "price": "0",
    "direction": 0,
    "feeRates": [
      0,
      0
    ],
    "hasSubsidy": 0,
    "signature": {
      "pubKey": "0x43cbec0bf142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
      "signature": "366e759d61a5052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
    }
  },
  "fee": "0",
  "feeToken": 0,
  "signature": {
    "pubKey": "0x1234567bf142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
    "signature": "1234567861a5052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
  }
}
```

### sign contractMatching

{% tabs %}
{% tab title="Golang" %}

```go
import (
    fmt
    sdk "github.com/zkLinkProtocol/zklink_sdk/generated/uniffi/zklink_sdk"
)

func SignContractMatching() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
    // create zklink signer
	zklinkSigner, err := sdk.ZkLinkSignerNewFromHexEthSigner(privateKey)
	if err != nil {
		return
	}
	taker_contract_builder := sdk.ContractBuilder {
        sdk.AccountId(1),
        sdk.SubAccountId(1),
        sdk.SlotId(2),
        sdk.Nonce(10),
        sdk.PairId(1),
        *big.NewInt(45454),
        *big.NewInt(113),
        true,
        5,
        3,
        false,
    }

    unsigned_taker_contract := sdk.NewContract(taker_contract_builder)
    taker_contract, err := unsigned_taker_contract.CreateSignedContract(
        zklinkSigner,
    )

    maker_contract1_builder := sdk.ContractBuilder {
        sdk.AccountId(3),
        sdk.SubAccountId(1),
        sdk.SlotId(2),
        sdk.Nonce(6),
        sdk.PairId(1),
        *big.NewInt(43434),
        *big.NewInt(6767),
        true,
        1,
        2,
        false,
    }

    maker_contract2_builder := sdk.ContractBuilder {
        sdk.AccountId(5),
        sdk.SubAccountId(1),
        sdk.SlotId(2),
        sdk.Nonce(100),
        sdk.PairId(1),
        *big.NewInt(45656),
        *big.NewInt(343),
        true,
        8,
        20,
        true,
    }

    unsigned_maker_contract1 := sdk.NewContract(maker_contract1_builder)
    unsigned_maker_contract2 := sdk.NewContract(maker_contract2_builder)
    maker_contract1, err := unsigned_maker_contract1.CreateSignedContract(
        zklinkSigner,
    )
    maker_contract2, err := unsigned_maker_contract2.CreateSignedContract(
        zklinkSigner,
    )

    var makers []*sdk.Contract
    makers = make([]*sdk.Contract,2)
    makers[0] = maker_contract1
    makers[1] = maker_contract2

    builder := sdk.ContractMatchingBuilder {
        sdk.AccountId(1),
        sdk.SubAccountId(1),
        taker_contract,
        makers,
       *big.NewInt(5545),
        sdk.TokenId(17),
    }

    tx := sdk.NewContractMatching(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignContractMatching(tx)
    if err != nil {
        return
    }
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)

    // get submitter signature
    zklinkTx := tx.ToZklinkTx()
    submitterSignature, err := signer.SubmitterSignature(zklinkTx)
    fmt.Println("submitter signatur: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
const {ContractMatchingBuilder,Signer,newContractMatching,newContract,ContractBuilder,RpcClient } = require('./node-dist/zklink-sdk-node');

async function testContractMatching() {
    const private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4";
    try {
        const signer = new Signer(private_key);
        let taker_contract_builder = new ContractBuilder(5,1,1,3,2,
            "343434343434","5454545445",true,50,22,false);
        let unsigned_taker_contract = newContract(taker_contract_builder);
        let taker_contract = signer.createSignedContract(unsigned_taker_contract);
        console.log(taker_contract);

        let maker_contract_builder1 = new ContractBuilder(5,1,1,4,2,
            "556556","898989",false,50,22,true);
        let unsigned_maker_contract1 = newContract(maker_contract_builder1);
        let maker_contract1 = signer.createSignedContract(unsigned_maker_contract1);
        console.log(maker_contract1);

        let maker_contract_builder2 = new ContractBuilder(5,1,1,5,2,
            "54554","78787878",false,50,22,false);
        let unsigned_maker_contract2 = newContract(maker_contract_builder2);
        let maker_contract2 = signer.createSignedContract(unsigned_maker_contract2);
        console.log(maker_contract2);

        let tx_builder = new ContractMatchingBuilder(5,1,taker_contract,[maker_contract1,maker_contract2],"34343",17);
        let tx = newContractMatching(tx_builder);
        console.log(tx);
        let tx_signature = signer.signContractMatching(tx);
        console.log(tx_signature);

        let submitter_signature = signer.submitterSignature(tx_signature.tx);
        console.log(submitter_signature);
        //send to zklink
        let rpc_client = new RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(tx_signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# Funding

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "Funding"</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>The account ID of Funding</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The subaccount ID of Funding</td></tr><tr><td>subAccountNonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>The subaccount nonce</td></tr><tr><td>fundingAccountIds</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a> array</td><td>yes</td><td>The account id list of funding</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The fee</td></tr><tr><td>feeToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token id of the fee</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>The Zklink L2 signature</td></tr></tbody></table>

For example:

```json
{
  "accountId": 0,
  "subAccountId": 0,
  "subAccountNonce": 0,
  "fundingAccountIds": [
    1,
    2
  ],
  "fee": "0",
  "feeToken": 0,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
```

### Sign Funding

{% tabs %}
{% tab title="Golang" %}

```go
import (
    fmt
    sdk "github.com/zkLinkProtocol/zklink_sdk/generated/uniffi/zklink_sdk"
)

func SignFunidng() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"

    var funding_account_ids = make([]sdk.AccountId,3)
    funding_account_ids[0] = sdk.AccountId(55)
    funding_account_ids[1] = sdk.AccountId(56)
    funding_account_ids[2] = sdk.AccountId(57)

    builder := sdk.FundingBuilder{
        sdk.AccountId(1),
        sdk.SubAccountId(99),
        sdk.Nonce(23),
        funding_account_ids,
        *big.NewInt(100000000000),
        sdk.TokenId(17),
    }
    tx := sdk.NewFunding(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignFunding(tx)
    if err != nil {
        return
    }
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
const {FundingBuilder,Signer,newFunding,RpcClient } = require('./node-dist/zklink-sdk-node');
async function testFunding() {
    const private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4";
    try {
        const signer = new Signer(private_key);
        let tx_builder = new FundingBuilder(5,1,2,[3,4,5],"34343",17);
        let tx = newFunding(tx_builder);
        console.log(tx);
        let tx_signature = signer.signFunding(tx);
        console.log(tx_signature);

        let submitter_signature = signer.submitterSignature(tx_signature.tx);
        console.log(submitter_signature);
        //send to zklink
        let rpc_client = new RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(tx_signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# Liquidation

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "Liquidation"</td></tr><tr><td>accountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>The account id of Liquidation</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The subaccount id</td></tr><tr><td>subAccountIdNonce</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#nonce">Nonce</a></td><td>yes</td><td>The Nonce of subaccount id</td></tr><tr><td>oraclePrices</td><td>struct</td><td>yes</td><td>contains all infomation about contract price and margin price</td></tr><tr><td>> contractPrices</td><td>array</td><td>yes</td><td><a href="/pages/gAbkxxgv8k1tUX4sxvfV">ContractPrice</a> array</td></tr><tr><td>> marginPrices</td><td>array</td><td>yes</td><td><a href="/pages/gAbkxxgv8k1tUX4sxvfV">SpotPriceInfo</a> array</td></tr><tr><td>liquidationAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#accountid">AccountId</a></td><td>yes</td><td>The account id of liquidation</td></tr><tr><td>fee</td><td><a href="/pages/BDCFoF8VRxOutzyi5iLV">BigUint</a></td><td>yes</td><td>The fee amount</td></tr><tr><td>feeToken</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The token id of the fee</td></tr><tr><td>signature</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#zklinksignature">ZkLinkSignature</a></td><td>yes</td><td>The ZkLink L3 signature of Liquidation</td></tr></tbody></table>

where the `ContractPrice` and `SpotPriceInfo` defined as below:

{% tabs %}
{% tab title="ContractPrice" %}

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>pairId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#pairid">PairId</a></td><td>yes</td><td>The pair id of trade pair, for example the id of BTC-USDT pair</td></tr><tr><td>marketPrice</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>yes</td><td>The market price of the associated pair</td></tr></tbody></table>
{% endtab %}

{% tab title="SpotPriceInfo" %}

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>tokenId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#tokenid">TokenId</a></td><td>yes</td><td>The pair id of trade pair, for example the id of BTC-USDT pair</td></tr><tr><td>price</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#price">BigUint</a></td><td>yes</td><td>The spot price</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

For example:

```json
{
  "type": "Liquidation",
  "accountId": 0,
  "subAccountId": 0,
  "subAccountNonce": 0,
  "oraclePrices": {
    "contractPrices": [
      {
        "pairId": 1,
        "marketPrice": "100"
      }
    ],
    "marginPrices": [
      {
        "tokenId": 1,
        "price": "100"
      }
    ]
  },
  "liquidationAccountId": 0,
  "fee": "0",
  "feeToken": 0,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
```

### Sign Liquidation

{% tabs %}
{% tab title="Golang" %}

```go
import (
    fmt
    sdk "github.com/zkLinkProtocol/zklink_sdk/generated/uniffi/zklink_sdk"
)

func HighLevelLiquidation() {
    privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"

    contract_price1 := sdk.ContractPrice{
        sdk.PairId(1),
        *big.NewInt(656566),
    }

    contract_price2 := sdk.ContractPrice{
        sdk.PairId(3),
        *big.NewInt(52552131),
    }
    var contract_prices = make([]sdk.ContractPrice,2)
    contract_prices[0] = contract_price1
    contract_prices[1] = contract_price2

    margin_price1 := sdk.SpotPriceInfo {
       sdk.TokenId(17),
       *big.NewInt(3236653653635635),
    }
    margin_price2 := sdk.SpotPriceInfo {
      sdk.TokenId(18),
      *big.NewInt(549574875297),
    }

    var margin_prices = make([]sdk.SpotPriceInfo,2)
    margin_prices[0] = margin_price1
    margin_prices[1] = margin_price2

    builder := sdk.LiquidationBuilder {
        sdk.AccountId(1),
        sdk.SubAccountId(1),
        sdk.Nonce(9),
        contract_prices,
        margin_prices,
        sdk.AccountId(3),
       *big.NewInt(5545),
        sdk.TokenId(17),
    }

    tx := sdk.NewLiquidation(builder)
    signer, err := sdk.NewSigner(privateKey)
    if err != nil {
        return
    }
    txSignature, err := signer.SignLiquidation(tx)
    if err != nil {
        return
    }
    fmt.Println("L1 signature: %s", txSignature.Layer1Signature)
    fmt.Println("signed Tx: %s", txSignature.Tx)
    submitterSignature, err := signer.SubmitterSignature(txSignature.Tx)
    fmt.Println("submitter signature: %s, %s", submitterSignature.PubKey, submitterSignature.Signature)
}
```

For more detail please refer to [Golang example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Golang) in SDK
{% endtab %}

{% tab title="javascript" %}

```javascript
const {LiquidationBuilder,Signer,RpcClient,ContractPrice,newLiquidation,SpotPriceInfo } = require('./node-dist/zklink-sdk-node');

async function testLiquidation() {
    const private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4";
    try {
        const contract_price1 = new ContractPrice(1,"10000000000000");
        const contract_price2 = new ContractPrice(1,"2000000000000");
        let contract_prices = [];
        contract_prices.push(contract_price1.jsonValue());
        contract_prices.push(contract_price2.jsonValue());

        let margin_prices = [];
        const margin_price1 = new SpotPriceInfo(17,"3236653653635635");
        const margin_price2 = new SpotPriceInfo(18,"549574875297");
        margin_prices.push(margin_price1.jsonValue());
        margin_prices.push(margin_price2.jsonValue());
        let tx_builder = new LiquidationBuilder(5,1,10,contract_prices,margin_prices,3,"188888",17);
        let tx = newLiquidation(tx_builder);
        console.log(tx);
        const signer = new Signer(private_key);
        let tx_signature = signer.signLiquidation(tx);
        console.log(tx_signature);

        let submitter_signature = signer.submitterSignature(tx_signature.tx);
        console.log(submitter_signature);
        //send to zklink
        let rpc_client = new RpcClient("testnet");
        let tx_hash = await rpc_client.sendTransaction(tx_signature.tx,null,submitter_signature);
        console.log(tx_hash);

    } catch (error) {
        console.error(error);
    }

}
```

For more detail please refer to [javascript example](https://github.com/zkLinkProtocol/zklink_sdk/tree/main/examples/Javascript)
{% endtab %}
{% endtabs %}


# UpdateGlobalVar

This transaction is used to update the global variable settings.

<table><thead><tr><th width="20">Name</th><th width="20">Type</th><th width="10">Required</th><th width="250">Description</th></tr></thead><tbody><tr><td>type</td><td>String</td><td>yes</td><td>The value is "UpdateGlovalVar "</td></tr><tr><td>fromChainId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#chainid">ChainId</a></td><td>yes</td><td>The layer3 chain id</td></tr><tr><td>subAccountId</td><td><a href="/pages/9wsGjTwfpfc2nyUJWAzS#subaccountid">SubAccountId</a></td><td>yes</td><td>The subaccount id</td></tr><tr><td>parameter</td><td><a href="/pages/fzxZg2TYd0M956BdFhGy">Parameter</a></td><td>yes</td><td>Different operation has different variable</td></tr><tr><td>seriaId</td><td>u64</td><td>yes</td><td>The serial id</td></tr></tbody></table>

There are 5 parameters, different operations correspond to different parameters:

{% tabs %}
{% tab title="feeAccount" %}
Modify the collect-fee account.

| Name       | Type                                                      | Required | Description        |
| ---------- | --------------------------------------------------------- | -------- | ------------------ |
| feeAccount | [AccountId](/developer/api-and-sdk/basic-types#accountid) | yes      | The fee account id |

For example:

```json
{
  "type": "UpdateGlobalVar",
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "feeAccount": {
      "accountId": 10
    }
  },
  "serialId": 100
}
```

{% endtab %}

{% tab title="insuranceFundAccount" %}
Modify the insurance fund account

| Name      | Type                                                      | Required | Description                            |
| --------- | --------------------------------------------------------- | -------- | -------------------------------------- |
| accountId | [AccountId](/developer/api-and-sdk/basic-types#accountid) | yes      | The account id of insuranceFundAccount |

For Example:

```json
{
  "type": "UpdateGlobalVar",
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "insuranceFundAccount": {
      "accountId": 9
    }
  },
  "serialId": 100
}
```

{% endtab %}

{% tab title="marginInfo" %}
Modify the margin info in the specified index.

| Name     | Type                                                    | Required | Description               |
| -------- | ------------------------------------------------------- | -------- | ------------------------- |
| marginId | [MarginId](/developer/api-and-sdk/basic-types#marginid) | yes      | The margin id             |
| tokenId  | [TokenId](/developer/api-and-sdk/basic-types#tokenid)   | yes      | The Token id              |
| ratio    | u8                                                      | yes      | the ratio, 100 means 1.0% |

For example

```json
{
  "type": "UpdateGlobalVar",
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "marginInfo": {
      "marginId": 1,
      "tokenId": 9,
      "ratio": 0
    }
  },
  "serialId": 100
}
```

{% endtab %}

{% tab title="contractInfo" %}
Modify the info of every perpetual contract pair.

| Name                  | Type                                                | Required | Description                                             |
| --------------------- | --------------------------------------------------- | -------- | ------------------------------------------------------- |
| pairId                | [PairId](/developer/api-and-sdk/basic-types#pairid) | yes      | The pair id                                             |
| symbol                | String                                              | yes      | The symbol of the contract                              |
| initialMarginRate     | u16                                                 | yes      | The initial margin rate of the contract, 100 means 0.1% |
| maintenanceMarginRate | u16                                                 | yes      | The maintenance margin rate, 100 means 0.1%             |

```json
{
  "type": "UpdateGlobalVar",
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "contractInfo": {
      "pairId": 2,
      "symbol": "BTCUSDC",
      "initialMarginRate": 6,
      "maintenanceMarginRate": 8
    }
  },
  "serialId": 100
}
```

{% endtab %}

{% tab title="fundingInfos" %}
Update the funding rates to accumulated funding rates of the Global Vars for all position(contract pair) in this period

| Name          | Type                                                | Required | Description                                                           |
| ------------- | --------------------------------------------------- | -------- | --------------------------------------------------------------------- |
| infos         | array                                               | yes      | funding info list                                                     |
| > pairId      | [PairId](/developer/api-and-sdk/basic-types#pairid) | yes      | The pair id                                                           |
| > price       | [BigUint](/developer/api-and-sdk/basic-types#price) | yes      | the mark price of the trade pair                                      |
| > fundingRate | i16                                                 | yes      | the fee funding rate, the actual result needs to be divided by `10^6` |

For example:

```json
{
  "type": "UpdateGlobalVar",
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "fundingInfos": {
      "infos": [
        {
          "pairId": 0,
          "price": "1000000000000000000",
          "fundingRate": 32767
        },
        {
          "pairId": 1,
          "price": "1000000000000000",
          "fundingRate": 0
        }
      ]
    }
  },
  "serialId": 100
}
```

{% endtab %}
{% endtabs %}


# Private Key & Signature

ZkLink protocal requires two signature methods:

* ECDSA: Digital Signature Algorithm (DSA) which uses keys derived from elliptic curve cryptography (ECC)
* EdDSA: A digital signature scheme using a variant of Schnorr signature based on twisted Edwards curves. It is designed to be faster than existing digital signature schemes without sacrificing security.

## Account PrivateKey

The account private key is the EdDSA private key generated by the user through the Ethereum wallet private key signature, the signature signed by this private key also called [ZkLinkSignature](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/data_types.md#zklinksignature). The pseudocode method for private key generation is as follows:

```
msg = "Sign this message to create a key to interact with zkLink's layer3 services.\nNOTE: This application is powered by zkLink protocol.\n\nOnly sign this message for a trusted client!"
signature = eth_private_key.sign(msg)
seed = signature.serialize_packed()
eddsa_private_key = new_from_seed(seed)
```

for example

```
ecdsa_private_key = "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
seed = [26, 208, 188, 78, 155, 166, 203, 253, 121, 248, 112, 168, 98, 143, 117, 247, 223, 252, 97, 47, 9, 58, 70, 56, 185, 231, 144, 91, 43, 169, 89, 89, 117, 74, 199, 139, 225, 74, 115, 205, 214, 157, 63, 60, 214, 191, 152, 224, 193, 118, 235, 35, 36, 138, 7, 247, 152, 164, 128, 134, 71, 102, 193, 42, 27];
eddsa_private_key = new_from_seed(seed)
public_key = "0x7b173e25e484eed3461091430f81b2a5bd7ae792f69701dcb073cb903f812510"
msg = b"hello world"
zklink_signature = eddsa_private_key.sign(msg)
zlink_signature = "0xe396adddbd484e896d0eea6b248a339a0497f65d482112981d947fd71010c4022a40cc5a72b334e89a1601f71518dcaa05c56737e1647828fa822e94b1ff7501"
```

## L3 signature

The Layer3 transactions need to attach the ZkLink signature, to encode the transactions, see more in the [encode](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/private-key-and-signature/broken-reference/README.md) part.


# Algorithm

The integer is composed of `mantissa` and `exponent` part of encoding, and pack algorithm is:

> `integer = mantissa * (exponent_base^exponent)`

where the `exponent_base` is `10`. This compression algorithm is mainly targeted at two types of data `fee` and `amount`:

* fee: 11 bits of mantissa and 5bits of exponent, total in 2 bytes
* amount: 35 bits of mantissa and 5bits of exponent, total in 5 bytes

## max value limitation of algorithm

For the `amount`, the max mantissa is `2^35 - 1`, and the max exponent is `2^5 - 1` or `31`. According to the pack algorithm, when exponent larger than 30, the result will exceed `u128`, so we use `30` as the max value of exponent, the max value of `amount` is

> max\_amount = (2^35 - 1) \* 10^30 = 34359738367000000000000000000000000000

For the `fee`, the max mantissa is `2^11 - 1`, and the max exponent is `2^5 - 1` or `31`, which make the max value of `fee` is

> max\_fee = (2^11 - 1) \* 10^31 = 20470000000000000000000000000000000

## Numerical precision loss

According to the formula, it can be seen that the compression algorithm will be numerical precision loss. For the numbers smaller than `2^128` will be changed after compression and cannot be recovered. For example, a `fee` integer is `(2^10+1)*10^2+1 = 102501` where the `mantissa` is `2^10+1=101` and the `exponent` is `2`, the pack result will be `(2^10+1)*10^2 = 102500` which results in a `1` numerical precision loss.

`version: 4457a91`


# ChangePubKey

## ChangePubKey encode

| Name         | Rule                                                                                         |
| ------------ | -------------------------------------------------------------------------------------------- |
| type         | 1 byte with value `0x06`                                                                     |
| chainId      | 1 byte                                                                                       |
| accountId    | 4 bytes                                                                                      |
| subAccountId | 1 byte                                                                                       |
| newPkHash    | 20 bytes                                                                                     |
| feeToken     | 2 bytes                                                                                      |
| fee          | 2 bytes, refer to the `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| nonce        | 4 bytes                                                                                      |
| ts           | 4 bytes                                                                                      |

39 bytes in total.

## Example

```json
{
  "type": "ChangePubKey",
  "chainId": 1,
  "accountId": 39,
  "subAccountId": 2,
  "newPkHash": "0xbfb4f4a68dc9e49f7785082a8c12354ed663b6e0",
  "feeToken": 3,
  "fee": "1285000000000000",
  "nonce": 4,
  "signature": {
    "pubKey": "0xed53a138751ed1e456f46e74eff3463d2420e488a4f608bde0f28d13c7104d29",
    "signature": "3b91c0421df4295281596746722ae20ccf270c5fc0561f93a0219db1faea6518f033e778dd552f90a9a6afd06427428b2ac4ea6f6893a3f162b32683d1108a02"
  },
  "ethAuthData": {
    "type": "EthECDSA",
    "ethSignature": "0x8e548e3727a94533b3963877b87966e308e6eef7762f78de567ff14b4e0e87780d37a845501ffd2cdbc7d6f0d620c14589212761f1637ea8214b0b6bac10aa9b1b"
  },
  "ts": 1675650037
}
encode_bytes = [6, 1, 0, 0, 0, 39, 2, 191, 180, 244, 166, 141, 201, 228, 159, 119, 133, 8, 42, 140, 18, 53, 78, 214, 99, 182, 224, 0, 3, 160, 172, 0, 0, 0, 4, 99, 224, 99, 245]
```


# Withdraw

## Withdraw encode

| Name             | Rule                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------ |
| type             | 1 byte with value `0x03`                                                                         |
| toChainId        | 1 byte                                                                                           |
| accountId        | 4 bytes                                                                                          |
| subAccountId     | 1 byte                                                                                           |
| to               | 32 bytes, extend to 32 bytes with `0x00` prefix                                                  |
| l2SourceToken    | 2 bytes                                                                                          |
| l1TargetToken    | 2 bytes                                                                                          |
| amount           | 16 bytes, refer to the `amount` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| fee              | 2 bytes, refer to the `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm)     |
| nonce            | 4 bytes                                                                                          |
| withdrawToL1     | 1 byte                                                                                           |
| withdrawFeeRatio | 2 bytes                                                                                          |
| callData         | No limit, be used to send to layer1 to call a smart contract                                     |
| ts               | 4 bytes                                                                                          |

72 bytes in total.

## Example

```json
{
  "toChainId": 1,
  "accountId": 10,
  "subAccountId": 1,
  "to": "0xafaff3ad1a0425d792432d9ecd1c3e26ef2c42e9",
  "l2SourceToken": 18,
  "l1TargetToken": 18,
  "amount": "10000",
  "callData": null,
  "fee": "3",
  "nonce": 1,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  },
  "withdrawToL1": 0,
  "withdrawFeeRatio": 0,
  "ts": 1693472232
}
excode_bytes = [35, 38, 100, 21, 162, 218, 169, 88, 46, 176, 84, 204, 61, 64, 69, 248, 70, 224, 44, 240, 208, 221, 29, 8, 236, 225, 227, 255, 131, 200, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```


# Transfer

## Transfer encode

| Name             | Rule                                                                                            |
| ---------------- | ----------------------------------------------------------------------------------------------- |
| type             | 1 byte with value `0x04`                                                                        |
| accountId        | 4 bytes                                                                                         |
| fromSubAccountId | 1 byte                                                                                          |
| to               | 32 bytes, extended to 32 bytes with prefix `0x00` prefix                                        |
| toSubAccountId   | 1 byte                                                                                          |
| token            | 2 bytes                                                                                         |
| amount           | 5 bytes, refer to the `amount` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| feeAmount        | 2 bytes, refer to the `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm)    |
| nonce            | 4 bytes                                                                                         |
| ts               | 4 bytes                                                                                         |

56 bytes in total.

## Example

```json
{
  "accountId": 10,
  "fromSubAccountId": 1,
  "toSubAccountId": 1,
  "to": "0xafaff3ad1a0425d792432d9ecd1c3e26ef2c42e9",
  "token": 18,
  "amount": "10000",
  "fee": "3",
  "nonce": 1,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  },
  "ts": 1693472232
}
encode_bytes = [ 4, 0, 0, 0, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 175, 243, 173, 26, 4, 37, 215, 146, 67, 45, 158, 205, 28, 62, 38, 239, 44, 66, 233, 1, 0, 18, 0, 0, 4, 226, 0, 0, 96, 0, 0, 0, 1, 100, 240, 85, 232 ]
```


# ForcedExit

<table><thead><tr><th width="248">Name</th><th>Rule</th></tr></thead><tbody><tr><td>type</td><td>1 byte with the value "7"</td></tr><tr><td>toChainId</td><td>1 byte</td></tr><tr><td>initiatorAccountId</td><td>4 bytes</td></tr><tr><td>initiatorSubAccountId</td><td>1 byte</td></tr><tr><td>target</td><td>20 bytes</td></tr><tr><td>targetSubAccountId</td><td>1 byte</td></tr><tr><td>l3SourceToken</td><td>2 bytes</td></tr><tr><td>l1TargetToken</td><td>2 bytes</td></tr><tr><td>initiatorNonce</td><td>4 bytes</td></tr><tr><td>exitAmount</td><td>Refer to the SDK <strong>serializeAmountFull</strong>, 16 bytes</td></tr><tr><td>ts</td><td>4 bytes</td></tr></tbody></table>

56 bytes in total.

## Example

```json
{
  "type": "ForcedExit",
  "toChainId": 1,
  "initiatorAccountId": 7,
  "initiatorSubAccountId": 3,
  "initiatorNonce":4,
  "target": "0x3498f456645270ee003441df82c718b56c0e6666",
  "targetSubAccountId": 2,
  "l2SourceToken": 1,
  "l1TargetToken": 17,
  "exitAmount": "4100000000000000",
  "withdrawToL1": 1,
  "ts": 1646102148,
  "nonce": 0,
  "signature": {
    "pubKey": "0x0dd4f603531bd78bbecd005d9e7cc62a794dcfadceffe03e269fbb6b72e9c724",
    "signature": "a8719d0f771f34a177bbf199ab7b0decd03b5db29edf173ed980d19c7864c5a3761111620ab1982ef1bb7459d5a919727e51b895799e2706ddd5a5328146eb01"
  }
}
encode_bytes = [7, 1, 0, 0, 0, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 152, 244, 86, 100, 82, 112, 238, 0, 52, 65, 223, 130, 199, 24, 181, 108, 14, 102, 102, 2, 0, 1, 0, 17, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 144, 237, 163, 148, 64, 0, 1, 98, 29, 134, 132]
```


# OrderMatching

## Order encode

| Name         | Rule                                                                                            |
| ------------ | ----------------------------------------------------------------------------------------------- |
| type         | 1 byte with value `0xff`                                                                        |
| accountId    | 4 bytes                                                                                         |
| subAccountId | 1 byte                                                                                          |
| slotId       | 2 bytes                                                                                         |
| nonce        | 4 bytes                                                                                         |
| baseTokenId  | 2 bytes                                                                                         |
| quoteTokenId | 2 bytes                                                                                         |
| price        | 15 bytes                                                                                        |
| isSell       | 1 byte                                                                                          |
| feeRates     | 2 bytes                                                                                         |
| hasSubsidy   | 1 byte                                                                                          |
| amount       | 5 bytes, refer to the `amount` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |

39 bytes in total.

## OrderMatching encode

| Name              | Rule                                                                                         |
| ----------------- | -------------------------------------------------------------------------------------------- |
| type              | 1 byte with the value `0x08`                                                                 |
| accountId         | 4 bytes                                                                                      |
| subAccountId      | 1 byte                                                                                       |
| orderBytesHash    | 32 bytes, refer to Rust SDK `rescue_hash_orders`                                             |
| feeToken          | 2 bytes                                                                                      |
| fee               | 2 bytes, refer to the `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| expectBaseAmount  | 16 bytes                                                                                     |
| expectQuoteAmount | 16 bytes                                                                                     |

74 bytes in total.

## Example

```json
{
  "type": "OrderMatching",
  "accountId": 4,
  "subAccountId": 1,
  "taker": {
    "accountId": 11,
    "subAccountId": 1,
    "slotId": 5844,
    "nonce": 24,
    "baseTokenId": 42,
    "quoteTokenId": 1,
    "amount": "373400000000000000000",
    "price": "1210900000000000000",
    "isSell": 1,
    "feeRates": [5, 10],
    "hasSubsidy": 1,
    "signature": {
      "pubKey": "0x1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
      "signature": "3a5c5c23a74cc04d256f03eb1671acd3959d707252ed52b16cb7b2ffe332a804986e09e0d62bcf49fc9231b38f07b71199769a7343eddc8b43ed9dd2ef8a4405"
    }
  },
  "maker": {
    "accountId": 11,
    "subAccountId": 1,
    "slotId": 5915,
    "nonce": 14,
    "baseTokenId": 42,
    "quoteTokenId": 1,
    "amount": "5165400000000000000000",
    "price": "1210900000000000000",
    "isSell": 0,
    "feeRates": [5, 10],
    "hasSubsidy": 0,
    "signature": {
      "pubKey": "0x1aedae58e43fe6661db7f834ae438930443908d108fdf621bfd4741fedfcd82f",
      "signature": "9579e54f53aa709e72c7e4de9815d258cf92bb3e9c4b9d03c2f79a7a49b5bda062d7e81b278eb62f2452294d178728b460efdb80017c83748dd190e41e05b802"
    }
  },
  "fee": "405000000000000",
  "feeToken": 1,
  "expectBaseAmount": "373400000000000000000",
  "expectQuoteAmount": "452150060000000000000",
  "signature": {
    "pubKey": "0x84bf4edbe1f7056f079ba4c38359427f43d529fbab2e94e6d6b7a18efbf2fb87",
    "signature": "1242830780b17dd362e8d31952deab6d8b5d81cadd62779b2caab0821baa030a770afa9a2c249d8f45000c4b9c6f01ef6b002682760e5bc4e5d39ef7f511ce03"
  }
}
encode_bytes = [8, 0, 0, 0, 4, 1, 37, 108, 168, 155, 185, 27, 201, 224, 122, 31, 189, 115, 53, 97, 11, 151, 14, 133, 10, 198, 175, 169, 42, 38, 200, 180, 166, 37, 230, 119, 110, 0, 1, 50, 172, 0, 0, 0, 0, 0, 0, 0, 20, 61, 247, 73, 164, 90, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 130, 215, 179, 249, 239, 142, 192, 0]
```


# ContractMatching

## Contract encode

| Name         | Rule                                                             |
| ------------ | ---------------------------------------------------------------- |
| type         | 1 byte, `0xfe`                                                   |
| accountId    | 4 bytes                                                          |
| subAccountId | 1 byte                                                           |
| slotId       | 2 bytes, use the lower 2 bytes of u32                            |
| nonce        | 3 bytes, encode to 4 bytes in big endian, keep the `bytes[1..3]` |
| pairId       | 1 byte, encode to 2 bytes in big endian, keep the lower byte     |
| direction    | 1 byte                                                           |
| size         | 5 bytes                                                          |
| price        | 15 bytes                                                         |
| feeRates     | 2 bytes                                                          |
| hasSubsidy   | 1 byte                                                           |

## ContractMatching encode

| Name         | Rule                                                                                     |
| ------------ | ---------------------------------------------------------------------------------------- |
| type         | 1 byte, `0x09`                                                                           |
| accountId    | 4 bytes                                                                                  |
| subAccountId | 1 byte                                                                                   |
| maker,taker  | 31 bytes                                                                                 |
| fee          | 2 bytes, refer to `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| feeToken     | 2 bytes                                                                                  |

41 bytes in total, where the `maker` and `taker` encode as bellow:

* [Encode](#contract-encode) the items in `maker` into a bytes list in order;
* [Encode](#contract-encode) the taker and append to the bytes list;
* pass the bytes list to the `rescue_hash_orders` function in SDK, and get the 31 bytes result.

## Example

```json
{
  "type": "ContractMatching",
  "accountId": 1,
  "subAccountId": 2,
  "maker": [
    {
      "accountId": 1,
      "subAccountId": 2,
      "slotId": 1,
      "nonce": 2,
      "pairId": 3,
      "size": "100",
      "price": "200",
      "direction": 0,
      "feeRates": [
        10,
        20
      ],
      "hasSubsidy": 0,
      "signature": {
        "pubKey": "0x99575738f142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
        "signature": "957826468392052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
      }
    }
  ],
  "taker": {
    "accountId": 2,
    "subAccountId": 3,
    "slotId": 2,
    "nonce": 3,
    "pairId": 4,
    "size": "100",
    "price": "200",
    "direction": 1,
    "feeRates": [
      100,
      200
    ],
    "hasSubsidy": 0,
    "signature": {
      "pubKey": "0x43cbec0bf142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
      "signature": "366e759d61a5052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
    }
  },
  "fee": "100",
  "feeToken": 2,
  "signature": {
    "pubKey": "0x54dc0c0bf142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
    "signature": "1234567861a5052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
  }
}
encode_bytes = [9, 0, 0, 0, 1, 2, 94, 132, 152, 149, 63, 148, 7, 42, 244, 97, 249, 239, 244, 227, 182, 160, 60, 184, 251, 76, 217, 159, 248, 7, 140, 72, 246, 187, 137, 19, 213, 0, 2, 12, 128]
```


# Funding

## Encode

| Name              | Rule                                                                                     |
| ----------------- | ---------------------------------------------------------------------------------------- |
| type              | 1 byte, `0x0d`                                                                           |
| accountId         | 4 bytes                                                                                  |
| subAccountId      | 1 byte                                                                                   |
| accountIdNonce    | 4 bytes                                                                                  |
| fundingAccountIds | 4 bytes(when length is 1) or 31 bytes(when length > 1)                                   |
| fee               | 2 bytes, refer to `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| feeToken          | 2 bytes                                                                                  |

The encoding process of `fundingAccountIds` is as blew:

* If the length is 1, encode the item directly in big endian;
* If the length > 1, encode the item in big endian into a bytes list in order;
* Pass the bytes list to the `rescue_hash` function in Rust SDK, and get the 31 bytes result.

## Example

For the `fundingAccountIds` length is 1:

```json
{
  "type": "Funding",
  "accountId": 1,
  "subAccountId": 2,
  "subAccountNonce": 3,
  "fundingAccountIds": [ 1 ],
  "fee": "0",
  "feeToken": 0,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
```

the encode result is:

```json
[13, 0, 0, 0, 1, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0]
```

For the `fundingAccountIds` length is larger than 1:

```json
{
  "type": "Funding",
  "accountId": 1,
  "subAccountId": 2,
  "subAccountNonce": 3,
  "fundingAccountIds": [ 1, 2, 3 ],
  "fee": "0",
  "feeToken": 0,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
encode_bytes = [13, 0, 0, 0, 1, 2, 0, 0, 0, 3, 229, 21, 12, 161, 198, 143, 182, 230, 55, 168, 20, 44, 52, 201, 150, 10, 189, 128, 111, 32, 198, 206, 155, 157, 175, 56, 77, 76, 234, 70, 83, 0, 0, 0, 0]
```


# Liquidation

## Encode ContractPrice

| Name        | Rule                                                                              |
| ----------- | --------------------------------------------------------------------------------- |
| pariId      | 1 byte                                                                            |
| marketPrice | 15 bytes, encode in big endian, then pass to the `pad_front` function in Rsut SDK |

## Encode OrderPriceInfo

| Name        | Rule                                                                             |
| ----------- | -------------------------------------------------------------------------------- |
| tokenId     | 2 byte, change to `u16`, then encode in big endian                               |
| marketPrice | 15 bytes, encode in big endian, then pass to the`pad_front` function in Rust SDK |

## Encode Liquidation

| Name                 | Rule                                                                                     |
| -------------------- | ---------------------------------------------------------------------------------------- |
| type                 | 1 byte, `0x0d`                                                                           |
| accountId            | 4 bytes                                                                                  |
| subAccountId         | 1 byte                                                                                   |
| accountIdNonce       | 4 bytes                                                                                  |
| oraclePrices         | 31 bytes                                                                                 |
| liquidationAccountId | 4 bytes                                                                                  |
| fee                  | 2 bytes, refer to `fee` pack method in [BigUint pack algorithm](#biguint-pack-algorithm) |
| feeToken             | 2 bytes                                                                                  |

49 bytes in total, where the `oraclePrices` encode process is as blew:

* Encode the `oraclePrices` into a bytes list in order;
* Pass the bytes list to the SDK `rescue_hash` function then get the 31 bytes result.

## Example

```json
{
  "type": "Liquidation",
  "accountId": 1,
  "subAccountId": 2,
  "subAccountNonce": 3,
  "oraclePrices": {
    "contractPrices": [
      {
        "pairId": 1,
        "marketPrice": "123"
      }
    ],
    "marginPrices": [
      {
        "tokenId": 1,
        "price": "456"
      }
    ]
  },
  "liquidationAccountId": 3,
  "fee": "1450",
  "feeToken": 3,
  "signature": {
    "pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
encode_bytes = [10, 0, 0, 0, 1, 2, 0, 0, 0, 3, 141, 200, 177, 63, 187, 15, 209, 184, 131, 185, 181, 117, 121, 115, 86, 252, 98, 58, 122, 70, 129, 240, 191, 202, 67, 248, 16, 60, 117, 39, 91, 0, 0, 0, 3, 0, 3, 181, 64]
```


# AutoDeleveraging

## AutoDeleveraging encode

| Name            | Rule                                                                                                                                                                                                                    |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type            | 1byte with the value `0x0b`                                                                                                                                                                                             |
| accountId       | 4 bytes                                                                                                                                                                                                                 |
| subAccountId    | 1 byte                                                                                                                                                                                                                  |
| subAccountNonce | 4 bytes                                                                                                                                                                                                                 |
| oraclePrices    | 31 bytes, encode the `ContractPrice` and `MarginPrice` in order, pass the bytes to Rust SDK `rescue_hash` method                                                                                                        |
| adlAccountId    | 4 bytes                                                                                                                                                                                                                 |
| pairId          | 1 byte                                                                                                                                                                                                                  |
| adlSize         | 5 bytes, refer to `amount` pack method in [BigUint pack algorithm](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/private-key-and-signature/algorithm.md#biguint-pack-algorithm) |
| adlPrice        | 15 bytes, encode to big endian bytes, then pass to the`pad_front` function in Rust SDK                                                                                                                                  |
| fee             | 2 bytes, refer to `fee` pack method in [BigUint pack algorithm](https://github.com/zkLinkProtocol/zklink-docs-gitbook/blob/main/developer/api-and-sdk/private-key-and-signature/algorithm.md#biguint-pack-algorithm)    |
| feeToken        | 2 bytes                                                                                                                                                                                                                 |

## ContractPrice encode

| Name        | Rule                                                                              |
| ----------- | --------------------------------------------------------------------------------- |
| pariId      | 1 byte                                                                            |
| marketPrice | 15 bytes, encode in big endian, then pass to the `pad_front` function in Rsut SDK |

## MarginPrice encode

| Name        | Rule                                                                             |
| ----------- | -------------------------------------------------------------------------------- |
| tokenId     | 2 byte, change to `u16`, then encode in big endian                               |
| marketPrice | 15 bytes, encode in big endian, then pass to the`pad_front` function in Rust SDK |

### Example

For the auto deleveraging as below:

```json
{
  "type": "AutoDeleveraging",
  "accountId": 1,
  "subAccountId": 1,
  "subAccountNonce": 2,
  "oraclePrices": {
    "contractPrices": [
      {
        "pairId": 1,
        "marketPrice": "100"
      }
    ],
    "marginPrices": [
      {
        "tokenId": 2,
        "price": "200"
      }
    ]
  },
  "adlAccountId": 2,
  "pairId": 4,
  "adlSize": "10",
  "adlPrice": "200",
  "fee": "120",
  "feeToken": 4,
  "signature": {
    "pubKey": "0x43cbec0bf142a942df9db99d27bd4ceeb8f4e75f9444b4cee4e3170965854404",
    "signature": "366e759d61a5052073e13147ed3e8e1642dfea10cd423bbb9a795932a15a4c122fa5e71c35a7d59198fa2d7ed28bb1f44e5c5392049607347855243ddc027d00"
  }
}
encode_bytes = [11, 0, 0, 0, 1, 1, 0, 0, 0, 2, 2, 43, 79, 252, 219, 58, 192, 163, 157, 224, 84, 133, 108, 165, 194, 196, 21, 224, 35, 204, 189, 183, 18, 177, 165, 127, 136, 194, 46, 70, 172, 0, 0, 0, 2, 4, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 4, 15, 0]
```


# UpdateGlobalVar

## Parameter Encode

### feeAccount

| Name       | Rule           |
| ---------- | -------------- |
| type       | 1 byte, `0x00` |
| feeAccount | 4 byte         |

5 bytes in total

### insuranceFundAccount

| Name      | Rule           |
| --------- | -------------- |
| type      | 1 byte, `0x01` |
| accountId | 4 bytes        |

5 bytes in total

### marginInfo

| Name     | Rule                                                |
| -------- | --------------------------------------------------- |
| type     | 1 byte, `0x02`                                      |
| marginId | 1 bytes                                             |
| tokenId  | 2 bytes, downcast to u16, then encode in big endian |
| ratio    | 1 byte                                              |

### contractInfo

| Name                  | Rule                                                      |
| --------------------- | --------------------------------------------------------- |
| type                  | 1 byte, `0x03`                                            |
| pariId                | 1 bytes, downcast to u8 as 1 byte                         |
| symbol                | 15 bytes, expand to 15 bytes with `0x00` at the beginning |
| initialMarginRate     | 2 bytes                                                   |
| maintenanceMarginRate | 2 bytes                                                   |

### fundingInfos

| Name  | Rule                                                                  |
| ----- | --------------------------------------------------------------------- |
| type  | 1 byte, `0x04`                                                        |
| infos | 18 bytes \* the length of fundingRates, encode `fundingInfo` in order |

where `fundingInfo` encode rule is:

| Name        | Rule                                               |
| ----------- | -------------------------------------------------- |
| pariId      | 1 bytes, downcast to u8 as 1 byte                  |
| price       | 15 bytes, refer to the Rust SDK `pad_front` method |
| fundingRate | 2 bytes                                            |

18 bytes in total, where `fundingRate` encode is as following:

* Get the absolute result as `u16` type，then encode as 2 bytes in big endian.
* If fundingRate < 0: `bytes[0] |= 0b1000_0000`

## UpdateGlobalVar Encode

| Name         | Rule                          |
| ------------ | ----------------------------- |
| type         | 1 byte, `0x0c`                |
| fromChainId  | 1 byte                        |
| subAccountId | 4 bytes                       |
| parameter    | refer to the Parameter encode |
| serialId     | 8 bytes                       |

## Example

With FundingInfo encode:

```json
{
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "fundingInfos": {
      "infos": [
        {
          "pairId": 0,
          "price": "1000000000000000000",
          "fundingRate": 32767
        },
        {
          "pairId": 1,
          "price": "1000000000000000",
          "fundingRate": 0
        },
        {
          "pairId": 2,
          "price": "1000000000000",
          "fundingRate": -1
        },
        {
          "pairId": 3,
          "price": "1000000000",
          "fundingRate": 1
        }
      ]
    }
  },
  "serialId": 0
}
encode_bytes = [12, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182, 179, 167, 100, 0, 0, 127, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 141, 126, 164, 198, 128, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 212, 165, 16, 0, 128, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 154, 202, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
```

With FeeAccount encode:

```json
{
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "feeAccount": {
      "accountId": 10
    }
  },
  "serialId": 0
}
encode_bytes = [12, 1, 1, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]
```

with insuranceFundAccount encode:

```json
{
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "insuranceFundAccount": {
      "accountId": 9
    }
  },
  "serialId": 0
}
encode_bytes = [12, 1, 1, 1, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0]
```

With MarginInfo encode:

```json
{
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "marginInfo": {
      "marginId": 1,
      "tokenId": 9,
      "ratio": 0
    }
  },
  "serialId": 0
}
encode_bytes = [12, 1, 1, 2, 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```

With ContractInfo encode:

```json
{
  "fromChainId": 1,
  "subAccountId": 1,
  "parameter": {
    "contractInfo": {
      "pairId": 2,
      "symbol": "BTCUSDC",
      "initialMarginRate": 6,
      "maintenanceMarginRate": 8
    }
  },
  "serialId": 0
}
encode_bytes = [12, 1, 1, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 66, 84, 67, 85, 83, 68, 67, 0, 6, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0]
```


# SDK

[Go](/developer/sdk/changelog) [Javascript](/developer/sdk/changelog-1) [Dart](/developer/sdk/changelog-2)


# Go

**2023-12-07 v3.0.0**

* Initialize SDK


# Types

### H256

Hex string of `[32]uint8` with prefix `0x`

### ZkLinkAddress

String format of L1 address, it's 20 bytes length or 32 bytes length

### ZkLinkTx

Json string format of all Transaction types.

### TxLayer1Signature

Json string format of L1 signature, it is an Enum type that contains 3 L1 signature type, for example:

```js
// the Ethereum signature
{
    "type": "EthereumSignature",
    "signature": "0x91dc468f37b6ef35cd0972881d37636f0c8f8dc974608ee9bf2e20ec03c546876092999bb802e6d673bb9fc858d750fa3e578b6bd2f3fe5a8e74ca23504a42661c"
}

// the EIP1271 signature
{
    "type": "EIP1271Signature",
    "signature": "0x91dc468f37b6ef35cd0972881d37636f0c8f8dc974608ee9bf2e20ec03c546876092999bb802e6d673bb9fc858d750fa3e578b6bd2f3fe5a8e74ca23504a42661c"
}

// the starknet signature
{
    "type": "StarknetSignature",
    "signature": "0x91dc468f37b6ef35cd0972881d37636f0c8f8dc974608ee9bf2e20ec03c546876092999bb802e6d673bb9fc858d750fa3e578b6bd2f3fe5a8e74ca23504a42661c"
}

```


# Signature

### Type EthSigner

Ethereum private key, opaque type.

#### Func NewEthSigner

```go
func NewEthSigner(privateKey string) (*EthSigner, error)
```

Create a Ethereum private key signer from hex string.

**input:**

* privateKey: hex string of private key

**return:** (\*EthSigner, error)

#### Func (\*EthSigner) SignMessage

```
func (*EthSigner) SignMessage(message []uint8) (PackedEthSignature, error)
```

Sign the message bytes

**input:**

* message: `[]uint8`

**output:** (String format of `PackedEthSignature`, error)

#### Func (\*EthSigner) GetAddress

```go
func (*EthSigner) GetAddress() Address
```

Get the address of Ethereum

**output:** Hex string format(with '0x' prefix) of Ethereum address.

#### example

```
func TestEthSigner(t *testing.T) {
    s := "0xb32593e347bf09436b058fbeabc17ebd2c7c1fa42e542f5f78fc3580faef83b7"
    signer, err := sdk.NewEthSigner(s)
    assert.Nil(t, err)
    msg := []byte("hello world")
    signature, err := signer.SignMessage(msg)
    assert.Nil(t, err)

    assert.Equal(t, signature, "0xa9aa0710adb18f84d4bed8057382fc433c3dcff1bddf3b2b1c2cb11386ef3be4172b5d0688143759d4e744acc434ae4f96575c7fa9096971fd02fb3d2aaa77121c")
    address := signer.GetAddress()
    assert.Equal(t, address, "0x9e372368c25056d44045e445d72d7b91ce3ee3b1")
}
```

### Type StarkSigner

The signer of Starknet, opaque type.

#### NewStarkSigner

```go
func NewStarkSigner() *StarkSigner
```

Create a random Starknet signer

**output:** `*StarkSigner`

#### func StarkSignerNewFromHexStr

```go
func StarkSignerNewFromHexStr(hexStr string) (*StarkSigner, error)
```

Create a Starknet signer from hex string

**input:**

* hexStr: hex string of private key(with or without `0x` prefix)

#### func(\*StarkSigner) SignMessage

```go
func (*StarkSigner) SignMessage(message []uint8) (StarkECDSASignature, error)
```

Sign message bytes

**input:**

* message: `[]uint8`

#### example

```go
func TestStarkSigner(t *testing.T) {
    s := "0x02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"
    signer, err := sdk.StarkSignerNewFromHexStr(s)
    assert.Nil(t, err)
    msg := []byte("hello world")
    signature, err := signer.SignMessage(msg)
    assert.Nil(t, err)
    assert.Equal(t, signature, "0x0226424352505249f119fd6913430aad28321afcff18036139b6fa77c4fad6cc071f3cf1b6bc80b84f261c74613ed3d90e5d11b1cc391b2bbddc70b9b4cc31f9067799101a3d9e6421c4d3950983b004dcfb9061a77a0e3bc2f9032ac8675b3e")
}
```

### Type ZkLinkSigner

`ZkLinkSigner` includes the L1 private key(Eth or Starknet) and L3 private key, opaque type.

#### func NewZkLinkSigner

```go
func NewZkLinkSigner() (*ZkLinkSigner, error)
```

Create a random seeded ZkLinkSigner

```go
signer, err := sdk.NewZkLinkSigner()
```

#### func ZkLinkSignerNewFromHexEthSigner

```go
func ZkLinkSignerNewFromHexEthSigner(ethHexPrivateKey string) (*ZkLinkSigner, error)
```

Creat a `ZkLinkSigner` from eth hex private key.

**input:**

* hexPrivateKey: Eth hex private key string

```go
s := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
signer, err = sdk.ZkLinkSignerNewFromHexEthSigner(s)
```

#### func ZkLinkSignerNewFromHexStarkSigner

```go
func ZkLinkSignerNewFromHexStarkSigner(hexPrivateKey string) (*ZkLinkSigner, error)
```

Create a `ZkLinkSigner` from Starknet hex private key.

**input:**

* hexPrivateKey: Starknet hex private key string

#### func ZkLinkSignerNewFromBytes

```go
func ZkLinkSignerNewFromBytes(slice []uint8) (*ZkLinkSigner, error)
```

Change the bytes to ZkLinkSigner

**input:**

* slice: \[]uint8

```go
s := "0x02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"
signer, err = sdk.ZkLinkSignerNewFromHexStarkSigner(s)
```

####

#### func (\*ZkLinkSigner) PublicKey

```go
func (*ZkLinkSigner) PublicKey() PackedPublicKey
```

Get the public key of L3 private key

#### func (\*ZkLinkSigner) SignMusig

```go
func (*ZkLinkSigner) SignMusig(msg []uint8) (ZkLinkSignature, error)
```

Sign a bytes formatted message with L3 private key in ZkLinkSigner.

**input:**:

* msg: message bytes

#### Example

```go
func TestZkLinkSigner(t *testing.T) {
    signer, err := sdk.NewZkLinkSigner()
	assert.Nil(t, err)
	assert.NotNil(t, signer)
	s := "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
	signer, err = sdk.ZkLinkSignerNewFromHexEthSigner(s)
	pub_key := signer.PublicKey()
	assert.Equal(t, pub_key, "0x7b173e25e484eed3461091430f81b2a5bd7ae792f69701dcb073cb903f812510")
	pubkey_hash := sdk.GetPublicKeyHash(pub_key)
	assert.Equal(t, pubkey_hash, "0xd8d5fb6a6caef06aa3dc2abdcdc240987e5330fe")
	msg := []uint8{0,1,2,3,4,5,6}
	signature, err := signer.SignMusig(msg)
	assert.Nil(t, err)
	assert.NotNil(t, signature)
	is_ok := sdk.VerifyMusig(signature, msg)
	assert.Equal(t, is_ok, true)
}
```

#### func SignChangePubkeyWithEthEcdsaAuth

```go
func (*Signer) SignChangePubkeyWithEthEcdsaAuth(tx *ChangePubKey) (TxSignature, error)
```

**input:** tx: [ChangePubKey](/developer/sdk/changelog/transactions/1-change-pubkey#changepubkey)

Sign the `ChangePubkey` and get the `TxSignature` result, for example:

```go
privateKey := "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4"
chainId := sdk.ChainId(1)
accountId := sdk.AccountId(2)
subAccountId := sdk.SubAccountId(4)
newPkHash:= sdk.PubKeyHash("0xd8d5fb6a6caef06aa3dc2abdcdc240987e5330fe")
feeToken := sdk.TokenId(1)
fee := big.NewInt(100)
nonce := sdk.Nonce(100)
ethSignature := sdk.PackedEthSignature("0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b")
// get current timestamp
now := time.Now()
timeStamp := sdk.TimeStamp(now.Unix())

// create ChangePubKey transaction type without signed
builder := sdk.ChangePubKeyBuilder{
    chainId,
    accountId,
    subAccountId,
    newPkHash,
    feeToken,
    *fee,
    nonce,
    &ethSignature,
    timeStamp,
}
tx := sdk.NewChangePubKey(builder)
signer, err := sdk.NewSigner(privateKey, sdk.L1TypeEth)
if err != nil {
    return
}
txSignature, err := signer.SignChangePubkeyWithEthEcdsaAuth(tx)
    fmt.Println("tx signature: %s", txSignature)
```

### func (\*Signer) SignChangePubkeyWithOnchainAuthData

```go
func (*Signer) SignChangePubkeyWithOnchainAuthData(tx *ChangePubKey) (TxSignature, error)
```

Sign `ChangePubkey` with `OnChain` auth data

### func (\*Signer) SignChangePubkeyWithCreate2dataAuth

```go
func (*Signer) SignChangePubkeyWithCreate2dataAuth(tx *ChangePubKey, crate2data Create2Data) (TxSignature, error) {
```

Sign `ChangePubkey` with `Create2Data` auth data

### Function

#### func GetPublicKeyHash

```go
func GetPublicKeyHash(publicKey PackedPublicKey) PubKeyHash;
```

Get the public key hash of L3 PublicKey

**arguments:**

* publicKey: string of L3 PublicKey

**return:** String of PubKeyHash

```go
assert.Equal(t, pub_key, "0x7b173e25e484eed3461091430f81b2a5bd7ae792f69701dcb073cb903f812510")
pubkey_hash := sdk.GetPublicKeyHash(pub_key)
```

#### func EthSignatureOfChangePubkey

```go
func EthSignatureOfChangePubkey (tx *ChangePubKey, ethSigner *EthSigner) (PackedEthSignature, error)
```

Create the Ethereum signature of [ChangePubKey](/developer/api-and-sdk/transaction/change_pubkey)

#### func ZklinkMainNetUrl

```go
func ZklinkMainNetUrl() string
```

Get the ZkLink main net url.

#### func ZklinkTestNetUrl

```go
func ZklinkTestNetUrl() string
```


# Utils

#### func isTokenAmountPackable

```go
func IsTokenAmountPackable(amount BigUint) bool
```

Checks whether the token amount can be packed (and thus used in the transaction)

#### func isFeeAmountPackable

```go
func IsFeeAmountPackable(fee BigUint) bool
```

Checks whether the fee amount can be packed (and thus used in the transaction)

#### func closestPackableTokenAmount

```go
func ClosestPackableTokenAmount(amount BigUint) BigUint
```

Returns the closest possible packable token amount. Returned amount is always less or equal to the provided amount.

#### func closestPackableFeeAmount

```go
func ClosestPackableFeeAmount(fee BigUint) BigUint
```

Returns the closest possible packable fee amount. Returned amount is always less or equal to the provided amount.

#### Example

```go
amount := *big.NewInt(1234567899808787)
fmt.Println("Original amount: ", amount)
amount = sdk.ClosestPackableTokenAmount(amount)
fmt.Println("Converted amount:s", amount)
fee := *big.NewInt(10000567777)
fmt.Println("Original fee: ", fee)
fee = sdk.ClosestPackableFeeAmount(fee)
fmt.Println("Converted fee: ", fee)
```


# Transactions


# ChangePubKey

### Type Create2Data

```go
type Create2Data struct {
	CreatorAddress ZkLinkAddress
	SaltArg        H256
	CodeHash       H256
}
```

### Type ChangePubKeyAuthDataEthCreate2

```go
type ChangePubKeyAuthDataEthCreate2 struct {
	Data Create2Data
}
```

### Type ChangePubKeyAuthDataEthEcdsa

```go
type ChangePubKeyAuthDataEthEcdsa struct {
	EthSignature PackedEthSignature
}
```

### Type ChangePubKeyAuthDataOnchain

```go
type ChangePubKeyAuthDataOnchain struct {}
```

### func CreateSignedChangePubkey

```go
func CreateSignedChangePubkey(zklinkSigner *ZkLinkSigner, tx *ChangePubKey, ethAuthData ChangePubKeyAuthData) (*ChangePubKey, error)
```

Create a signed [ChangePubkey](/developer/api-and-sdk/transaction/change_pubkey)

**input:**

* zklinkSigner: zklink [signer](#type-zklinksigner)
* tx: unsigned transaction [ChangePubkey](/developer/api-and-sdk/transaction/change_pubkey)
* ethAuthData: `ChangePubKeyAuthData` is a interface which can be [ChangePubKeyAuthDataOnchain](#changepubkeyauthdataonchain), [ChangePubKeyAuthDataEthCreate2](#changepubkeyauthdataethcreate2) or [ChangePubKeyAuthDataEthEcdsa](#changepubkeyauthdataethecdsa)

### type ChangePubKeyBuilder

The ChangePubKeyBuilder is used to build the type [ChangePubKey](#changepubkey)

```go
type ChangePubKeyBuilder struct {
	ChainId       ChainId
	AccountId     AccountId
	SubAccountId  SubAccountId
	NewPubkeyHash PubKeyHash
	FeeToken      TokenId
	Fee           BigUint
	Nonce         Nonce
	EthSignature  *PackedEthSignature
	Timestamp     TimeStamp
}
```

### type ChangePubKey

[ChangePubkey](/developer/api-and-sdk/transaction/change_pubkey) transaction type, it's a opaque data type.

#### func NewChangePubKey

Create a [ChangePubkey](#type-changepubkey)

```go
func NewChangePubKey(builder ChangePubKeyBuilder) *ChangePubKey
```

**input:**

* builder: [ChangePubKeyBuilder](#type-changepubkeybuilder)

#### func (\*ChangePubKey) GetSignature

```go
func (*ChangePubKey) GetSignature() ZkLinkSignature
```

Get the L3 signature of the [ChangePubKey](#type-changepubkey)

#### func (\*ChangePubKey) GetBytes

```go
func (*ChangePubKey) GetBytes() []uint8
```

Get the encoded bytes of [ChangePubKey](#type-changepubkey), which is used to create the L3 signature.

#### func (\*ChangePubKey) TxHash

```go
func (*ChangePubKey) TxHash() []uint8
```

Get the Transaction Hash of [ChangePubKey](#type-changepubkey)

#### func (\*ChangePubKey) JsonStr

```go
func (*ChangePubKey) JsonStr() string
```

Get the json str of [ChangePubKey](#type-changepubkey)

#### func (\*ChangePubKey) IsValid

```go
func (*ChangePubKey) IsValid() bool
```

Check if all the fields in ChangePubKey are valid. For example, if the `ChainId` is exceeded the maximum ChainId, it will return false.

#### func (\*ChangePubKey) IsOnchain

```go
func (*ChangePubKey) IsOnchain() bool
```

Check if the transaction's auth data is OnChain.

#### func (\*ChangePubKey) IsSignatureValid

```go
func (*ChangePubKey) IsSignatureValid() bool
```

Check if the L3 signature is valid or not.

#### func (\*ChangePubKey) SubmitterSignature

```go
func (*ChangePubKey) SubmitterSignature(signer *ZkLinkSigner) (ZkLinkSignature, error)
```

Create the submitter signature.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*ChangePubKey) ToZklinkTx

```go
func (*ChangePubKey) ToZklinkTx() ZkLinkTx
```

Change the ChangePubKey transaction type to [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx) type.

####


# Withdraw

### type WithdrawBuilder

```go
type WithdrawBuilder struct {
	AccountId        AccountId
	SubAccountId     SubAccountId
	ToChainId        ChainId
	ToAddress        ZkLinkAddress
	L2SourceToken    TokenId
	L1TargetToken    TokenId
	Amount           BigUint
	Fee              BigUint
	Nonce            Nonce
	WithdrawFeeRatio uint16
	WithdrawToL1     bool
	Timestamp        TimeStamp
}
```

The builder is used to build the [Withdraw](/developer/sdk/changelog/transactions#type-withdraw) transaction.

### type Withdraw

[Withdraw](/developer/api-and-sdk/transaction/withdraw) transaction type, it's a opaque data type.

#### func NewWithdraw(builder WithdrawBuilder)

```go
func NewWithdraw(builder WithdrawBuilder) *Withdraw
```

Create a new [Withdraw](#type-withdraw) transaction.

**input:** builder: [WithdrawBuilder](#type-withdrawbuilder)

#### func (\*Withdraw) GetBytes

```go
func (_self *Withdraw) GetBytes() []uint8
```

Get the encoded bytes used to create the L3 signature.

#### func (\*Withdraw) TxHash

```go
func (*Withdraw) TxHash() []uint8
```

Get the transaction hash of [Withdraw](#type-withdraw) transaction

#### func (\*Withdraw) IsValid

```go
func (*Withdraw) IsValid() bool
```

Check if all the fields in [Withdraw](#type-withdraw) are valid. For example, if the `ChainId` is exceeded the maximum ChainId, it will return false.

#### func (\*Withdraw) CreateSignedTx

```go
func (*Withdraw) CreateSignedTx(signer *ZkLinkSigner) (*Withdraw, error)
```

The ZkLinkSigner will sign the \[Withdraw] transaction, replace the default signature in the transaction.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*Withdraw) GetSignature

```go
func (_self *Withdraw) GetSignature() ZkLinkSignature
```

Get L3 signature inside the transaction.

#### func (\*Withdraw) IsSignatureValid

```go
func (*Withdraw) IsSignatureValid() bool
```

Check if the L3 signature in the Withdraw transaction is valid or not.

#### func (\*Withdraw) EthSignature

```go
func (*Withdraw) EthSignature(ethSigner *EthSigner, l2SourceTokenSymbol string) (PackedEthSignature, error)
```

Create the Ethereum signature. **input:**:

* ethSigner: the [Ethereum signer](/developer/sdk/changelog/signer#type-ethsigner)
* l2SourceTokenSymbol: the symbol string of l2 token, for example: "USD"

#### func (\*Withdraw) SubmitterSignature

```go
func (_self *Withdraw) SubmitterSignature(signer *ZkLinkSigner) (ZkLinkSignature, error)
```

Create a submitter signature.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*Withdraw) ToZklinkTx

```go
func (*Withdraw) ToZklinkTx() ZkLinkTx
```

Change the Withdraw transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# Transfer

### type TransferBuilder

```go
type TransferBuilder struct {
	AccountId        AccountId
	ToAddress        ZkLinkAddress
	FromSubAccountId SubAccountId
	ToSubAccountId   SubAccountId
	Token            TokenId
	Amount           BigUint
	Fee              BigUint
	Nonce            Nonce
	Timestamp        TimeStamp
}
```

Builder is used to build [Transfer](#type-transfer) transaction

### type Transfer

[Transfer](/developer/api-and-sdk/transaction/transfer) transaction type, it's a opaque data type.

#### func NewTransfer(builder TransferBuilder)

```go
func NewTransfer(builder TransferBuilder) *Transfer
```

Create a new [Transfer](#type-transfer) transaction.

Get the signature in the [Transfer](#type-transfer) transaction.

#### func (\*Transfer) GetBytes

```go
func (*Transfer) GetBytes() []uint8
```

Get the encoded bytes used to create the L3 signature.

#### func (\*Transfer) TxHash

```go
func (*Transfer) TxHash() []uint8
```

Get the transaction hash of [Transfer](#type-transfer) transaction.

#### func (\*Transfer) JsonStr

```go
func (*Transfer) JsonStr() string
```

Get the json string of the [Transfer](#type-transfer) transaction.

#### func (\*Transfer) IsValid

```go
func (*Transfer) IsValid() bool
```

Check if all the fields in Withdraw are valid. For example, if the `ChainId` is exceeded the maximum ChainId, it will return false.

#### func (\*Transfer) CreateSignedTx

```go
func (*Transfer) CreateSignedTx(signer *ZkLinkSigner) (*Transfer, error)
```

Sign the Transfer transaction with the [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner), L1 signature and L3 signature will be created.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*Transfer) GetSignature

```go
func (*Transfer) GetSignature() ZkLinkSignature
```

#### func (\*Transfer) IsSignatureValid

```go
func (*Transfer) IsSignatureValid() bool
```

Check if the L3 signature in the transaction is valid or not.

#### func (\*Transfer) GetEthSignMsg

```go
func (*Transfer) GetEthSignMsg(tokenSymbol string) string
```

Get the message that used to create the Ethereum signature.

#### func (\*Transfer) EthSignature

```go
func (*Transfer) EthSignature(ethSigner *EthSigner, tokenSymbol string) (TxLayer1Signature, error)
```

Create Ethereum signature, returns a [TxLayer1Signature](/developer/sdk/changelog/basic_types#txlayer1signature)

**input:**

* ethSigner: [EthSigner](/developer/sdk/changelog/signer#type-ethsigner)
* tokenSymbol: the symbol string of the token, for example, `USDT`

#### func (\*Transfer) SubmitterSignature

```go
func (*Transfer) SubmitterSignature(signer *ZkLinkSigner) (ZkLinkSignature, error)
```

Create the submitter signature.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*Transfer) ToZklinkTx

```go
func (*Withdraw) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# ForcedExit

### type ForcedExitBuilder

```go
type ForcedExitBuilder struct {
    ToChainId             ChainId
    InitiatorAccountId    AccountId
    InitiatorSubAccountId SubAccountId
    Target                ZkLinkAddress
    TargetSubAccountId    SubAccountId
    L2SourceToken         TokenId
    L1TargetToken         TokenId
    InitiatorNonce        Nonce
    ExitAmount            BigUint
    WithdrawToL1          bool
    Timestamp             TimeStamp
}
```

Builder used to create ForcedExit transaction.

### type ForcedExit

[ForcedExit](/developer/api-and-sdk/transaction/forced_exit) transaction type, it's a opaque data type.

#### func NewForcedExit

```go
func NewForcedExit(builder ForcedExitBuilder) *ForcedExit
```

Create a new [ForcedExit](#type-forcedexit) transaction.

#### func (\*ForcedExit) GetBytes

```go
func (_self *ForcedExit) GetBytes() []uint8
```

Get the encoded bytes used to create the L3 signature.

#### func (\*ForcedExit) TxHash

```go
func (*ForcedExit) TxHash() []uint8
```

Get the transaction hash of [ForcedExit](#type-forcedexit) transaction.

#### func (\*ForcedExit) JsonStr

```go
func (*ForcedExit) JsonStr() string
```

Get the json string of the [ForcedExit](#type-forcedexit) transaction.

#### func (\*ForcedExit) IsValid

```go
func (_self *ForcedExit) IsValid() bool
```

Check if all the fields in Withdraw are valid. For example, if the `ChainId` is exceeded the maximum ChainId, it will return false.

#### func (\*ForcedExit) CreateSignedTx

```go
func (*ForcedExit) CreateSignedTx(signer *ZkLinkSigner) (*ForcedExit, error)
```

Sign the Transfer transaction with the [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner), L1 signature and L3 signature will be created.

#### func (\*ForcedExit) GetSignature

```go
func (*ForcedExit) GetSignature() ZkLinkSignature
```

Get the signature in the [Transfer](#type-transfer) transaction.

#### func (\*ForcedExit) IsSignatureValid

```go
func (*ForcedExit) IsSignatureValid() bool
```

Check if the L3 signature in the Transfer transaction is valid or not.

#### func (\*ForcedExit) SubmitterSignature

```go
func (*ForcedExit) SubmitterSignature(signer *ZkLinkSigner) (ZkLinkSignature, error)
```

Create the submitter signature.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*ForcedExit) ToZklinkTx

```go
func (*ForcedExit) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# OrderMatching

### ContractPrice

```go
type ContractPrice struct {
    PairId      PairId
    MarketPrice BigUint
}
```

* **PairId:** The contract pair id defined by zkLink.
* **MarketPrice:** The market price of the contract pair

### SpotPrice

```go
type SpotPriceInfo struct {
	TokenId TokenId
	Price   BigUint
}
```

* **TokenId:** The token id defined by zkLink.
* **price:** The spot price of the token.

### type Order

The spot order type of taker and maker. it's a opaque data type.

#### func NewOrder

```go
func NewOrder(
    accountId AccountId,
    subAccountId SubAccountId,
    slotId SlotId,
    nonce Nonce,
    baseTokenId TokenId,
    quoteTokenId TokenId,
    amount BigUint,
    price BigUint,
    isSell bool,
    hasSubsidy bool,
    makerFeeRate uint8,
    takerFeeRate uint8,
    signature *ZkLinkSignature
) *Order
```

Create a new Order.

**input:**

* accountId: the user account id
* subAccountId: the user sub account id
* slotId: the slot id of order
* nonce: the nonce of user account
* baseTokenId: the token id of the base token of trade pair, for example, "BTC" token id of "BTCUSDT" pair
* quoteTokenId: the token id of the quote token of trade pari, for example, "USDT" token id of "BTCUSDT" pair
* amount: the amount of base token
* price: the price of base token
* isSell: sell token or not
* hasSubsidy: subsidy only works for maker and makerFeeRate
* makeFeeRate: the fee maker rate, 100 means 1%, max is 2.56%
* takerFeeRate: the fee taker rate, 100 means 1%, max is 2.56%
* signature: optional, the L3 signature of the Order

#### func (\*Order) GetSignature

```go
func (*Order) GetSignature() ZkLinkSignature
```

Get the L3 signature of the Order

#### func (\*Order) GetSignature

```go
func (*Order) GetSignature() ZkLinkSignature {
```

Get the Order signature.

#### func (\*Order) GetBytes

```go
func (*Order) GetBytes() []uint8
```

Get the encoded bytes to create the L3 signature.

#### func \*Order) JsonStr

```go
func (*Order) JsonStr() string
```

Get the json string of the Order.

#### func (\*Order) IsValid

```go
func (*Order) IsValid() bool
```

Check if the Order is valid or not.

#### func (\*Order) IsSignatureValid

```go
func (*Order) IsSignatureValid() bool
```

Check if the L3 signature is valid or not.

#### func (\*Order) CreateSignedOrder

```go
func (*Order) CreateSignedOrder(zklinkSigner *ZkLinkSigner) (*Order, error)
```

Returns a new order with L3 signature.

**input:**

* zklinkSigner: [zkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

### OrderMatchingBuilder

```go
type OrderMatchingBuilder struct {
    AccountId         AccountId
    SubAccountId      SubAccountId
    Taker             *Order
    Maker             *Order
    Fee               BigUint
    FeeToken          TokenId
    ContractPrices    []ContractPrice
    MarginPrices      []SpotPriceInfo
    ExpectBaseAmount  BigUint
    ExpectQuoteAmount BigUint
}
```

The builder is used to bo build [OrderMatching](/developer/sdk/changelog/transactions/5-order-matching) transaction.

### type OrderMatching

[OrderMatching](/developer/sdk/changelog/transactions/5-order-matching) transaction type, it's a opaque data type.

#### func NewOrderMatching

```go
func NewOrderMatching(builder OrderMatchingBuilder) *OrderMatching
```

Create a new [OrderMatching](#type-ordermatching) transaction.

#### func (\*OrderMatching) GetBytes

```go
func (*OrderMatching) GetBytes() []uint8
```

Get the encoded bytes used to create the L3 signature.

#### func (\*OrderMatching) TxHash() \[]uint8

```go
func (*OrderMatching) TxHash() []uint8
```

Get the transaction hash of [OrderMatching](#type-ordermatching) transaction.

#### func (\*OrderMatching) JsonStr

```go
func (*OrderMatching) JsonStr() string
```

Get the json string of the [OrderMatching](#type-ordermatching) transaction.

#### func (\*OrderMatching) IsValid() bool

```go
func (*OrderMatching) IsValid() bool
```

Check if all the fields in OrderMatching are valid. For example, if the `ChainId` is exceeded the maximum ChainId, it will return false.

#### func (\*OrderMatching) CreateSignedTx

```go
func (*OrderMatching) CreateSignedTx(signer *ZkLinkSigner) (*OrderMatching, error)
```

Sign the Transfer transaction with the [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner), L1 signature and L3 signature will be created.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*OrderMatching) GetSignature

```go
func (*OrderMatching) GetSignature() ZkLinkSignature
```

Get the L3 signature of OrderMatching transaction.

#### func (\*OrderMatching) IsSignatureValid

```go
func (*OrderMatching) IsSignatureValid() bool
```

Check if the L3 signature in the transaction is valid or not.

#### func (\*OrderMatching) ToZklinkTx

```go
func (*OrderMatching) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# ContractMatching

### type ContractBuilder

```go
type ContractBuilder struct {
    AccountId    AccountId
    SubAccountId SubAccountId
    SlotId       SlotId
    Nonce        Nonce
    PairId       PairId
    Size         BigUint
    Price        BigUint
    Direction    bool
    TakerFeeRate uint8
    MakerFeeRate uint8
    HasSubsidy   bool
}
```

Builder used to build [Contract](#type-contract)

### type Contract

The [Contract](/developer/api-and-sdk/transaction/contract_matching) struct of taker and maker in perpetual contract, it's a opaque data type.

#### func NewContract

```go
func NewContract(builder ContractBuilder) *Contract
```

Create a new Contract.

#### func (\*Contract) IsLong

```go
func (*Contract) IsLong() bool
```

Return true if the contract opens a long position.

#### func (\*Contract) IsShort

```go
func (*Contract) IsShort() bool
```

Return true if the contract opens a short position.

#### func (\*Contract) GetSignature

```go
func (_self *Contract) GetSignature() ZkLinkSignature
```

Get the L3 signature of the contract.

#### func (\*Contract) IsSignatureValid

```go
func (*Contract) IsSignatureValid() bool
```

Check if the signature is valid or not.

#### func (\*Contract) GetBytes

```golang
func (*Contract) GetBytes() []uint8 
```

Get the encoded bytes that used to create the L3 signature.

#### func (\*Contract) CreateSignedContract

```go
func (*Contract) CreateSignedContract(zklinkSigner *ZkLinkSigner) (*Contract, error)
```

Create a new contract with L3 signature.

**input:**

* zklinkSigner: [zklinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

### type ContractMatchingBuilder

```go
type ContractMatchingBuilder struct {
    AccountId    AccountId
    SubAccountId SubAccountId
    Taker        *Contract
    Maker        []*Contract
    Fee          BigUint
    FeeToken     TokenId
}
```

### type ContractMatching

The [ContractMatching](/developer/api-and-sdk/transaction/contract_matching) transaction in perpetual contract, it's a opaque data type.

#### NewContractMatching(builder ContractMatchingBuilder)

```go
func NewContractMatching(builder ContractMatchingBuilder) *ContractMatching
```

Create a new ContractMatching transaction.

#### func (\*ContractMatching) GetBytes

```go
func (_self *ContractMatching) GetBytes() []uint8
```

Get the encoded bytes that used to create the L3 signature. See more in [Private Key and Signature](/developer/api-and-sdk/private_key/contract_matching).

#### func (\*ContractMatching) TxHash

```go
func (*ContractMatching) TxHash() []uint8
```

Get the transaction hash of the transaction.

#### func (\*ContractMatching) JsonStr

```go
func (*ContractMatching) JsonStr() string
```

Get the json string of the the transaction.

#### func (\*ContractMatching) IsValid

```go
func (*ContractMatching) IsValid() bool
```

Check if the transaction is valid or not.

#### func (\*ContractMatching) CreateSignedTx

```go
func (*ContractMatching) CreateSignedTx(signer *ZkLinkSigner) (*ContractMatching, error)
```

Create a new transaction with L3 signature.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*ContractMatching) GetSignature

```go
func (*ContractMatching) GetSignature() ZkLinkSignature
```

Get the L3 signature of the transaction.

#### func (\*ContractMatching) IsSignatureValid

```go
func (*ContractMatching) IsSignatureValid() bool
```

Check if the inside L3 signature is valid or not.

#### func (\*ContractMatching) ToZklinkTx

```go
func (*ContractMatching) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# AutoDeleveraging

### type AutoDeleveragingBuilder

```go
type AutoDeleveragingBuilder struct {
	AccountId       AccountId
	SubAccountId    SubAccountId
	SubAccountNonce Nonce
	ContractPrices  []ContractPrice
	MarginPrices    []SpotPriceInfo
	AdlAccountId    AccountId
	PairId          PairId
	AdlSize         BigUint
	AdlPrice        BigUint
	Fee             BigUint
	FeeToken        TokenId
}
```

Builder that used to build AutoDeleveraging transaction.

### type AutoDeleveraging

[AutoDeleveraging](/developer/api-and-sdk/transaction/auto_deleveraging) transaction type, it's a opaque data type.

#### func NewAutoDeleveraging

```go
func NewAutoDeleveraging(builder AutoDeleveragingBuilder) *AutoDeleveraging
```

Create a new AutoDeleveraging transaction.

#### func (\*AutoDeleveraging) GetBytes

```go
func (*AutoDeleveraging) GetBytes() []uint8
```

Get the encoded bytes to create the L3 signature. See more in [Private Key and Signature](/developer/api-and-sdk/private_key/auto_deleveraging)

#### func (\*AutoDeleveraging) TxHash

```go
func (*AutoDeleveraging) TxHash() []uint8
```

Get the transaction hash of the transaction.

#### func (\*AutoDeleveraging) JsonStr

```go
func (*AutoDeleveraging) JsonStr() string
```

Get the json string of the transaction.

#### func (\*AutoDeleveraging) IsValid

```go
func (*AutoDeleveraging) IsValid() bool
```

Check if the transaction is valid.

#### func (\*AutoDeleveraging) CreateSignedTx

```go
func (*AutoDeleveraging) CreateSignedTx(signer *ZkLinkSigner) (*AutoDeleveraging, error)
```

Create a new AutoDeleveraging transaction with L3 signature inside.

**input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*AutoDeleveraging) GetSignature

```go
func (*AutoDeleveraging) GetSignature() ZkLinkSignature
```

Get L3 signature of the transaction.

#### func (\*AutoDeleveraging) IsSignatureValid

```go
func (*AutoDeleveraging) IsSignatureValid() bool
```

Check if the inside L3 signature is valid or not.

#### func \*AutoDeleveraging) ToZklinkTx

```go
func (*AutoDeleveraging) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# Funding

### type FundingBuilder

```go
type FundingBuilder struct {
	AccountId         AccountId
	SubAccountId      SubAccountId
	SubAccountNonce   Nonce
	FundingAccountIds []AccountId
	Fee               BigUint
	FeeToken          TokenId
}
```

Builder that used to build the [Funding](#type-funding) transaction.

### type Funding

[Funding](/developer/api-and-sdk/transaction/funding) transaction type, it's a opaque data type.

#### func NewFunding(builder FundingBuilder)

```go
func NewFunding(builder FundingBuilder) *Funding
```

Create a new [Funding](#type-funding) transaction.

#### func (\*Funding) GetBytes

```go
func (*Funding) GetBytes() []uint8
```

Get the encoded bytes to create the L3 signature. See more in [Private Key and Signature](/developer/api-and-sdk/private_key/funding)

#### func (\*Funding) TxHash

```go
func (*Funding) TxHash() []uint8
```

Get the transaction hash of the transaction.

#### func (\*Funding) JsonStr

```go
func (*Funding) JsonStr() string
```

Get the json string of the transaction.

#### func (\*Funding) IsValid

```go
func (*Funding) IsValid() bool
```

Check if the transaction is valid or not.

#### func (\*Funding) CreateSignedTx

```go
func (*Funding) CreateSignedTx(signer *ZkLinkSigner) (*Funding, error)
```

Create a new AutoDeleveraging transaction with L3 signature inside. **input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*Funding) GetSignature

```go
func (*Funding) GetSignature() ZkLinkSignature
```

Get L3 signature of the transaction.

#### func (\*Funding) IsSignatureValid

```go
func (*Funding) IsSignatureValid() bool
```

Check if the inside L3 signature is valid or not.

#### func (\*Funding) ToZklinkTx

```go
func (*Funding) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# Liquidation

### type LiquidationBuilder

```go
type LiquidationBuilder struct {
    AccountId            AccountId
    SubAccountId         SubAccountId
    SubAccountNonce      Nonce
    ContractPrices       []ContractPrice
    MarginPrices         []SpotPriceInfo
    LiquidationAccountId AccountId
    Fee                  BigUint
    FeeToken             TokenId
}
```

The builder used to create the [Liquidation](#type-liquidation) transaction.

### type Liquidation

[Liquidation](/developer/api-and-sdk/transaction/liquidation) transaction type, it's a opaque data type.

#### func NewLiquidation(builder LiquidationBuilder)

```go
func NewLiquidation(builder LiquidationBuilder) *Liquidation
```

Create a new [Liquidation](#type-liquidation) transaction.

#### func (\*Liquidation) GetBytes

```go
func (*Liquidation) GetBytes() []uint8
```

Get the encoded bytes to create the L3 signature. See more in [Private Key and Signature](/developer/api-and-sdk/private_key/liquidation)

#### func (\*Liquidation) TxHash

```go
func (*Liquidation) TxHash() []uint8
```

Get the transaction hash of the transaction.

#### func (\*Liquidation) JsonStr

```go
func (*Liquidation) JsonStr() string
```

Get the json string of the transaction.

#### func (\*Liquidation) IsValid

```go
func (*Liquidation) IsValid() bool
```

Check if the transaction is valid.

#### func (\*Liquidation) CreateSignedTx

```go
func (*Liquidation) CreateSignedTx(signer *ZkLinkSigner) (*Liquidation, error)
```

Create a new Liquidation transaction with L3 signature inside. **input:**

* signer: [ZkLinkSigner](/developer/sdk/changelog/signer#type-zklinksigner)

#### func (\*Liquidation) GetSignature

```go
func (*Liquidation) GetSignature() ZkLinkSignature
```

Get L3 signature of the transaction.

#### func (\*Liquidation) IsSignatureValid

```go
func (*Liquidation) IsSignatureValid() bool
```

Check if the inside L3 signature is valid or not.

#### func (\*Liquidation) ToZklinkTx

```go
func (*Liquidation) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# UpdateGlobalVar

### Parameter

Parameter is an interface which contains 5 types of struct

#### type ParameterFeeAccount

```go
type ParameterFeeAccount struct {
	AccountId AccountId
}
```

This parameter is used to modify the collect-fee account.

#### type ParameterInsuranceFundAccount

```go
type ParameterInsuranceFundAccount struct {
	AccountId AccountId
}
```

This parameter is used to modify the insurance fund account.

#### type ParameterMarginInfo

```go
type ParameterMarginInfo struct {
	MarginId MarginId
	TokenId  TokenId
	Ratio    uint8
}
```

This parameter is used to modify the margin info in the specified index.

#### type ParameterFundingInfos

```go
type ParameterFundingInfos struct {
	Infos []FundingInfo
}
```

This parameter is used to ppdate the funding rates to accumulated funding rates of the Global Vars for all position(contract pair) in this period.

**type FundingInfo**

```go
type FundingInfo struct {
	PairId      PairId
	Price       BigUint
	FundingRate int16
}
```

#### type ParameterContractInfo

```go
type ParameterContractInfo struct {
	PairId                PairId
	Symbol                string
	InitialMarginRate     uint16
	MaintenanceMarginRate uint16
}
```

This parameter is used to modify the info of every perpetual contract pair.

### type UpdateGlobalVarBuilder

```go
type UpdateGlobalVarBuilder struct {
    FromChainId  ChainId
    SubAccountId SubAccountId
    Parameter    Parameter
    SerialId     uint64
}
```

The builder is used to build new [UpdateGlobalVar](#type-updateglobalvar) transaction.

### type UpdateGlobalVar

[UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var) transaction type, it's a opaque data type.

#### func NewUpdateGlobalVar

```go
func NewUpdateGlobalVar(builder UpdateGlobalVarBuilder) *UpdateGlobalVar
```

Create a new [UpdateGlobalVar](#type-updateglobalvar) transaction.

#### func (\*UpdateGlobalVar) GetBytes

```go
func (*UpdateGlobalVar) GetBytes() []uint8
```

Get the encoded bytes to create the L3 signature. See more in [Private Key and Signature](/developer/api-and-sdk/private_key/funding)

#### func (\*UpdateGlobalVar) TxHash

```go
func (*UpdateGlobalVar) TxHash() []uint8
```

Get the transaction hash of the transaction.

#### func (\*UpdateGlobalVar) JsonStr

```go
func (*UpdateGlobalVar) JsonStr() string
```

Get the json string of the transaction.

#### func (\*UpdateGlobalVar) IsValid

```go
func (*UpdateGlobalVar) IsValid() bool
```

Check if the transaction is valid or not.

#### func (\*UpdateGlobalVar) ToZklinkTx

```go
func (*UpdateGlobalVar) ToZklinkTx() ZkLinkTx
```

Change the transaction to the [ZkLinkTx](/developer/sdk/changelog/basic_types#zklinktx)


# Js

**2023-12-07 v3.0.0**

* Initialize SDK


# Signature

### Type JsonRpcSigner(for browser)

L1 private key.

#### constructor

```javascript
/**
* @param {provider}
*/
newRpcSignerWithProvider(provider)
```

#### Example

```javascript
await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = window.ethereum;
const signer = new wasm.newRpcSignerWithProvider(provider);
```

#### func initZklinkSigner

```javascript
/**
* @param {string | undefined} [signature]
* @returns {Promise<void>}
*/
initZklinkSigner(signature)
```

Initialize ZkLink L3 private key

#### func address

```javascript
/**
* @returns {string}
*/
address()
```

Return address

#### func signatureSeed

```javascript
/**
* @returns {string}
*/
signatureSeed()
```

Return signature seed

### Type Signer(for nodejs)

L1 private key.

#### constructor

```javascript
/**
* @param {string} private_key: hex string of private key(with or without `0x` prefix)
* @param {L1Type.Eth | L1Type.Starknet}
* @param {string | undefined} [starknet_chain_id]
* @param {string | undefined} [starknet_addr]
*/
Signer(private_key, l1_type, starknet_chain_id, starknet_addr)
```

Create a Eth or Starknet private key signer.

#### func getPubkey

```javascript
/**
* @returns {string}
*/
getPubkey()
```

Return hex string of public key.

#### func getPubkeyHash

```javascript
/**
* @returns {string}
*/
getPubkeyHash()
```

Return hex string of public key hash.

#### func signMusig

```javascript
/**
* @param {Uint8Array} msg
* @returns {TxZkLinkSignature}
*/
signMusig(msg)
```

Sign and create [ZkLinkSignature](/developer/api-and-sdk/basic-types#zklinksignature) from raw message.

#### func signChangePubkeyWithOnchain

```javascript
/**
* @param {ChangePubKey} tx
* @returns {json object} json string of tx
*/
signChangePubkeyWithOnchain(tx)
```

#### func signChangePubkeyWithEthEcdsaAuth

```javascript
/**
* @param {ChangePubKey} tx
* @returns {json object} json string of tx
*/
signChangePubkeyWithEthEcdsaAuth(tx)
```

#### func signChangePubkeyWithCreate2DataAuth

```javascript
/**
* @param {ChangePubKey} tx
* @param {Create2Data} create2_data
* @returns {json string of tx}
*/
signChangePubkeyWithCreate2DataAuth(tx, create2_data)
```

#### Example

```javascript
const private_key = "00f0dfe9e420b857beb5165c4dbe4b21561dc4ca0206ca97f6ee7ad53bc79cab";
const new_pubkey_hash = "0x8255f5a6d0d2b34a19f381e448ed151cc3a59b9e";
const ts  = Math.floor(Date.now() / 1000);
try {
    let tx_builder = new ChangePubKeyBuilder(
        16,21,0,new_pubkey_hash,140,"1",
        0,"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b",
        ts);
    let tx = newChangePubkey(tx_builder);
    let addr = "0x04A69b67bcaBfA7D3CCb96e1d25C2e6fC93589fE24A6fD04566B8700ff97a71a";
    const signer = new Signer(private_key, L1Type.Starknet, "SN_GOERLI", addr);
    let creator_address = "0x6E253C951A40fAf4032faFbEc19262Cd1531A5F5";
    let salt = "0x0000000000000000000000000000000000000000000000000000000000000000";
    let code_hash = "0x4f063cd4b2e3a885f61fefb0988cc12487182c4f09ff5de374103f5812f33fe7";
    let tx_signature = signer.signChangePubkeyWithCreate2DataAuth(tx, new Create2Data(creator_address, salt, code_hash));
    console.log(tx_signature);
} catch (error) {
    console.error(error);
}
```

#### func signWithdraw

```javascript
/**
* @param {Withdraw} tx
* @param {string} token_symbol
* @param {string | undefined} [chain_id]
* @param {string | undefined} [addr]
* @returns {json object} json string of tx
*/
signWithdraw(tx, token_symbol, chain_id, addr)
```

#### func signTransfer

```javascript
* @param {Transfer} tx
* @param {string} token_symbol
* @param {string | undefined} [chain_id]
* @param {string | undefined} [addr]
* @returns {json object} json string of tx
*/
signTransfer(tx, token_symbol, chain_id, addr)
```

#### func signForcedExit

```javascript
/**
* @param {ForcedExit} tx
* @returns {json object} json string of tx
*/
signForcedExit(tx)
```

#### func createSignedOrder

```javascript
/**
* @param {Order} order
* @returns {Order} signed order
*/
createSignedOrder(order)
```

#### func signOrderMatching

```javascript
/**
* @param {OrderMatching} tx
* @returns {json object} json string of tx
*/
signOrderMatching(tx)
```

#### Example

```javascript
const private_key = "be725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4";
try {
    const signer = new Signer(private_key, L1Type.Eth);
    const contract_price1 = new ContractPrice(0,"1");
    const contract_price2 = new ContractPrice(1,"1");
    const contract_price3 = new ContractPrice(2,"1");
    const contract_price4 = new ContractPrice(3,"1")
    let contract_prices = [];
    contract_prices.push(contract_price1.jsonValue());
    contract_prices.push(contract_price2.jsonValue());
    contract_prices.push(contract_price3.jsonValue());
    contract_prices.push(contract_price4.jsonValue());

    let margin_prices = [];
    const margin_price1 = new SpotPriceInfo(17,"1");
    const margin_price2 = new SpotPriceInfo(141,"1");
    const margin_price3 = new SpotPriceInfo(142,"1");
    margin_prices.push(margin_price1.jsonValue());
    margin_prices.push(margin_price2.jsonValue());
    margin_prices.push(margin_price3.jsonValue());
    let maker_order = new Order(5,20,1,1,18,17,"10000000000000","10000000000",true,5,3);
    let maker = signer.createSignedOrder(maker_order);
    console.log(maker);
    let taker_order = new Order(5,20,1,1,18,17,"10000000000000","10000000000",false,5,3);
    let taker = signer.createSignedOrder(taker_order);

    let tx_builder = new OrderMatchingBuilder(5,20,taker,maker,"11",17,contract_prices,margin_prices,"4343433","3957485749");
    let tx = newOrderMatching(tx_builder);
    console.log(tx);
    let tx_signature = signer.signOrderMatching(tx);
    console.log(tx_signature);
} catch (error) {
    console.error(error);
}
```

#### func createSignedContract

```javascript
/**
* @param {Contract} contract
* @returns {Contract} signed contract
*/
createSignedContract(contract)
```

#### func signContractMatching

```javascript
/**
* @param {ContractMatching} tx
* @returns {json object} json string of tx
*/
signContractMatching(tx)
```

#### func signAutoDeleveraging

```javascript
/**
* @param {AutoDeleveraging} tx
* @returns {json object} json string of tx
*/
signAutoDeleveraging(tx)
```

#### func signFunding

```javascript
/**
* @param {Funding} tx
* @returns {json object} json string of tx
*/
```

#### func signLiquidation

```javascript
/**
* @param {Liquidation} tx
* @returns {json object} json string of tx
*/
```

#### func getZkLinkSigner

```javascript
/**
* @returns {ZkLinkSigner}
*/
getZkLinkSigner()
```

### Type ZkLinkSigner

`ZkLinkSigner` includes the L1 private key(Eth or Starknet) and L3 private key.

#### func ethSig

```javascript
/**
* @param {string} sig
* @returns {ZkLinkSigner}
*/
ethSig(sig)
```

Creat a [ZkLinkSigner](#type-zklinksigner) from eth personal sign.

**input:**

* sig: hex string of eth personal sign(with or without `0x` prefix)

#### func starknetSig

```javascript
/**
* @param {string} sig
* @returns {ZkLinkSigner}
*/
starknetSig(sig)
```

Creat a [ZkLinkSigner](#type-zklinksigner) from starknet signature.

**input:**

* sig: hex string of starknet signature(with or without `0x` prefix)


# Utils

#### func isTokenAmountPackable

```javascript
/**
* @param {string} amount
* @returns {boolean}
*/
isTokenAmountPackable(amount: string)
```

Checks whether the token amount can be packed (and thus used in the transaction)

#### func isFeeAmountPackable

```javascript
/**
* @param {string} fee
* @returns {boolean}
*/
isFeeAmountPackable(fee: string)
```

Checks whether the fee amount can be packed (and thus used in the transaction)

#### func closestPackableTransactionAmount

```javascript
/**
* @param {string} amount
* @returns {string}
*/
closestPackableTransactionAmount(amount: string)
```

Returns the closest possible packable token amount. Returned amount is always less or equal to the provided amount.

#### func closestPackableTransactionFee

```javascript
/**
* @param {string} fee
* @returns {string}
*/
closestPackableTransactionFee(fee: string)
```

Returns the closest possible packable fee amount. Returned amount is always less or equal to the provided amount.

#### Example

```javascript
let amount = "1234567899808787";
console.log("Original amount: " + amount);
console.assert(isTokenAmountPackable(amount) == false);
amount = wasm.closestPackableTransactionAmount(amount);
console.assert(isTokenAmountPackable(amount));
console.log("Converted amount: " + amount);
let fee = "10000567777";
console.log("Original fee: " + fee);
console.assert(isFeeAmountPackable(fee) == false);
fee = wasm.closestPackableTransactionFee(fee)
console.assert(isFeeAmountPackable(fee));
console.log("Converted fee: " + fee);
```


# Transactions


# ChangePubKey

### type ChangePubKeyBuilder

#### constructor

```javascript
/**
* @param {number} chain_id
* @param {number} account_id
* @param {number} sub_account_id
* @param {string} new_pubkey_hash
* @param {number} fee_token
* @param {string} fee
* @param {number} nonce
* @param {string | undefined} [eth_signature]
* @param {number | undefined} [ts]
*/
ChangePubKeyBuilder(chain_id, account_id, sub_account_id, new_pubkey_hash, fee_token, fee, nonce, eth_signature, ts)
```

### type ChangePubKey

[ChangePubkey](/developer/api-and-sdk/transaction/change_pubkey) transaction type.

#### constructor

```javascript
/**
* @param {ChangePubKeyBuilder} builder
*/
newChangePubkey(builder)
```

#### func getChangePubkeyMessage

```javascript
/**
* @param {number} chainId
* @param {string} address
* @returns {string}
*/
getChangePubkeyMessage(chainId, address)
```

Get the EIP-712 structured data of [ChangePubKey](#type-changepubkey)

#### func getEthSignMsg

```javascript
/**
* @param {number} nonce
* @param {number} account_id
* @returns {string}
*/
getEthSignMsg(nonce, account_id)
```

Get the Ethereum sign message

#### func setEthAuthData

```javascript
/**
* @param {string} sig
* @returns {any}
*/
setEthAuthData(String sig)
```

Set Ethereum authentication data with given EthECDSA signature

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)

#### Example

```javascript
const new_pubkey_hash = "0x8255f5a6d0d2b34a19f381e448ed151cc3a59b9e";
const ts  = Math.floor(Date.now() / 1000);
let zklinkSigner = ZkLinkSigner.ethSig("0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
let tx_builder = new ChangePubKeyBuilder(
    16,21,0,new_pubkey_hash,140,"10",
    0,"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b",
    ts);
let tx = newChangePubkey(tx_builder);
tx.sign(zklinkSigner);
console.log("ETH Signed Message:\n" + tx.getEthSignMsg(100, 1));
tx.setEthAuthData("0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b");
console.log(tx.jsValue())
```


# Withdraw

### type WithdrawBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {number} to_chain_id
* @param {string} to_address
* @param {number} l2_source_token
* @param {number} l1_target_token
* @param {string} amount
* @param {string | undefined} call_data
* @param {string} fee
* @param {number} nonce
* @param {boolean} withdraw_to_l1
* @param {number} withdraw_fee_ratio
* @param {number | undefined} [ts]
*/
WithdrawBuilder(account_id, sub_account_id, to_chain_id, to_address, l2_source_token, l1_target_token, amount, call_data, fee, nonce, withdraw_to_l1, withdraw_fee_ratio, ts)
```

### type Withdraw

[Withdraw](/developer/api-and-sdk/transaction/withdraw) transaction type.

#### constructor

```javascript
/**
* @param {WithdrawBuilder} builder
*/
newWithdraw(builder)
```

#### func getEthSignMsg

```javascript
/**
* @param {string} token_symbol
* @returns {string}
*/
getEthSignMsg(token_symbol)
```

Get the Ethereum sign message

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# Transfer

### type TransferBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {string} to_address
* @param {number} from_sub_account_id
* @param {number} to_sub_account_id
* @param {number} token
* @param {string} fee
* @param {string} amount
* @param {number} nonce
* @param {number | undefined} [ts]
*/
TransferBuilder(account_id, to_address, from_sub_account_id, to_sub_account_id, token, fee, amount, nonce, ts)
```

### type Transfer

[Transfer](/developer/api-and-sdk/transaction/transfer) transaction type.

#### constructor

```javascript
/**
* @param {TransferBuilder} builder
*/
newTransfer(builder)
```

#### func getEthSignMsg

```javascript
/**
* @param {string} token_symbol
* @returns {string}
*/
getEthSignMsg(token_symbol)
```

Get the Ethereum sign message

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# ForcedExit

### type ForcedExitBuilder

#### constructor

```javascript
/**
* @param {number} to_chain_id
* @param {number} initiator_account_id
* @param {number} initiator_sub_account_id
* @param {number} target_sub_account_id
* @param {string} target
* @param {number} l2_source_token
* @param {number} l1_target_token
* @param {string} exit_amount
* @param {number} initiator_nonce
* @param {boolean} withdraw_to_l1
* @param {number | undefined} [ts]
*/
ForcedExitBuilder(to_chain_id, initiator_account_id, initiator_sub_account_id, target_sub_account_id, target, l2_source_token, l1_target_token, exit_amount, initiator_nonce, withdraw_to_l1, ts)
```

### type ForcedExit

[ForcedExit](/developer/api-and-sdk/transaction/forced_exit) transaction type.

#### constructor

```javascript
/**
* @param {ForcedExitBuilder} builder
*/
newForcedExit(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# OrderMatching

### type ContractPrice

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {string} market_price
*/
ContractPrice(pair_id, market_price)
```

**input:**

* pair\_id: The contract pair id defined by zkLink.
* market\_price: The market price of the contract pair

### type SpotPriceInfo

#### constructor

```javascript
/**
* @param {number} token_id
* @param {string} price
*/
SpotPriceInfo(token_id, price)
```

**input:**

* token\_id: The token id defined by zkLink.
* price: The spot price of the token.

### type Order

The [Order](/developer/api-and-sdk/transaction/order_matching) struct of taker and maker.

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {number} slot_id
* @param {number} nonce
* @param {number} base_token_id
* @param {number} quote_token_id
* @param {string} amount
* @param {string} price
* @param {boolean} is_sell
* @param {number} maker_fee_rate
* @param {number} taker_fee_rate
* @param {boolean} has_subsidy
*/
Order(account_id, sub_account_id, slot_id, nonce, base_token_id, quote_token_id, amount, price, is_sell, maker_fee_rate, taker_fee_rate, has_subsidy)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign order with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)

### type OrderMatchingBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {Order} taker
* @param {Order} maker
* @param {string} fee
* @param {number} fee_token
* @param {ContractPrice[]} contract_prices
* @param {SpotPriceInfo[]} margin_prices
* @param {string} expect_base_amount
* @param {string} expect_quote_amount
*/
OrderMatchingBuilder(account_id, sub_account_id, taker, maker, fee, fee_token, contract_prices, margin_prices, expect_base_amount, expect_quote_amount)
```

### type OrderMatching

[OrderMatching](/developer/api-and-sdk/transaction/order_matching) transaction type.

#### constructor

```javascript
/**
* @param {OrderMatchingBuilder} builder
*/
newOrderMatching(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# ContractMatching

### type ContractPrice

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {string} market_price
*/
ContractPrice(pair_id, market_price)
```

**input:**

* pair\_id: The contract pair id defined by zkLink.
* market\_price: The market price of the contract pair

### type SpotPriceInfo

#### constructor

```javascript
/**
* @param {number} token_id
* @param {string} price
*/
SpotPriceInfo(token_id, price)
```

**input:**

* token\_id: The token id defined by zkLink.
* price: The spot price of the token.

### type ContractBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {number} slot_id
* @param {number} nonce
* @param {number} pair_id
* @param {string} size
* @param {string} price
* @param {boolean} direction
* @param {number} maker_fee_rate
* @param {number} taker_fee_rate
* @param {boolean} has_subsidy
*/
ContractBuilder(account_id, sub_account_id, slot_id, nonce, pair_id, size, price, direction, maker_fee_rate, taker_fee_rate, has_subsidy)
```

### type Contract

The [Contract](/developer/api-and-sdk/transaction/contract_matching) struct of taker and maker in perpetual contract.

#### constructor

```javascript
/**
* @param {ContractBuilder} builder
*/
newContract(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign contract with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)

### type ContractMatchingBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {Contract} taker
* @param {Contract[]} maker
* @param {string} fee
* @param {number} fee_token
* @param {ContractPrice[]} contract_prices
* @param {SpotPriceInfo[]} margin_prices
*/
ContractMatchingBuilder(account_id, sub_account_id, taker, maker, fee, fee_token, contract_prices, margin_prices)
```

### type ContractMatching

[ContractMatching](/developer/api-and-sdk/transaction/contract_matching) transaction type.

#### constructor

```javascript
/**
* @param {ContractMatchingBuilder} builder
*/
newContractMatching(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# AutoDeleveraging

### type ContractPrice

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {string} market_price
*/
ContractPrice(pair_id, market_price)
```

**input:**

* pair\_id: The contract pair id defined by zkLink.
* market\_price: The market price of the contract pair

### type SpotPriceInfo

#### constructor

```javascript
/**
* @param {number} token_id
* @param {string} price
*/
SpotPriceInfo(token_id, price)
```

**input:**

* token\_id: The token id defined by zkLink.
* price: The spot price of the token.

### type AutoDeleveragingBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {number} sub_account_nonce
* @param {ContractPrice[]} contract_prices
* @param {SpotPriceInfo[]} margin_prices
* @param {number} adl_account_id
* @param {number} pair_id
* @param {string} adl_size
* @param {string} adl_price
* @param {string} fee
* @param {number} fee_token
*/
AutoDeleveragingBuilder(account_id, sub_account_id, sub_account_nonce, contract_prices, margin_prices, adl_account_id, pair_id, adl_size, adl_price, fee, fee_token)
```

### type AutoDeleveraging

[AutoDeleveraging](/developer/api-and-sdk/transaction/auto_deleveraging) transaction type.

```javascript
/**
* @param {AutoDeleveragingBuilder} builder
*/
newAutoDeleveraging(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# Funding

### type FundingBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {number} sub_account_nonce
* @param {Uint32Array} funding_account_ids
* @param {string} fee
* @param {number} fee_token
*/
FundingBuilder(account_id, sub_account_id, sub_account_nonce, funding_account_ids, fee, fee_token)
```

### type Funding

[Funding](/developer/api-and-sdk/transaction/funding) transaction type.

#### constructor

```javascript
/**
* @param {FundingBuilder} builder
*/
newFunding(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# Liquidation

### type ContractPrice

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {string} market_price
*/
ContractPrice(pair_id, market_price)
```

**input:**

* pair\_id: The contract pair id defined by zkLink.
* market\_price: The market price of the contract pair

### type SpotPriceInfo

#### constructor

```javascript
/**
* @param {number} token_id
* @param {string} price
*/
SpotPriceInfo(token_id, price)
```

**input:**

* token\_id: The token id defined by zkLink.
* price: The spot price of the token.

### type LiquidationBuilder

#### constructor

```javascript
/**
* @param {number} account_id
* @param {number} sub_account_id
* @param {number} sub_account_nonce
* @param {ContractPrice[]} contract_prices
* @param {SpotPriceInfo[]} margin_prices
* @param {number} liquidation_account_id
* @param {string} fee
* @param {number} fee_token
*/
LiquidationBuilder(account_id, sub_account_id, sub_account_nonce, contract_prices, margin_prices, liquidation_account_id, fee, fee_token) {
```

### type Liquidation

[Liquidation](/developer/api-and-sdk/transaction/liquidation) transaction type.

#### constructor

```javascript
/**
* @param {LiquidationBuilder} builder
*/
newLiquidation(builder)
```

#### func sign

```javascript
/**
* @param {ZkLinkSigner} signer
* @returns {any}
*/
sign(signer)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-1/signer#type-zklinksigner)


# UpdateGlobalVar

### type ContractPrice

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {string} market_price
*/
ContractPrice(pair_id, market_price)
```

**input:**

* pair\_id: The contract pair id defined by zkLink.
* market\_price: The market price of the contract pair

### type SpotPriceInfo

#### constructor

```javascript
/**
* @param {number} token_id
* @param {string} price
*/
SpotPriceInfo(token_id, price)
```

**input:**

* token\_id: The token id defined by zkLink.
* price: The spot price of the token.

### type FundingInfo

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {number} funding_rate
* @param {string} price
*/
FundingInfo(pair_id, funding_rate, price)
```

#### type MarginInfo

#### constructor

```javascript
/**
* @param {number} margin_id
* @param {number} token_id
* @param {number} ratio
*/
MarginInfo(margin_id, token_id, ratio)
```

#### type ContractInfo

#### constructor

```javascript
/**
* @param {number} pair_id
* @param {string} symbol
* @param {number} initial_margin_rate
* @param {number} maintenance_margin_rate
*/
ContractInfo(pair_id, symbol, initial_margin_rate, maintenance_margin_rate)
```

### type Parameter

The [Parameter](/developer/api-and-sdk/transaction/update_global_var) struct of [UpdateGlobalVar](#type-updateglobalvar).

#### constructor

```javascript
/**
* @param {number} insurance_fund_account
*/
Parameter(ParameterType.InsuranceFundAccount, insurance_fund_account)

/**
* @param {number} fee_account
*/
Parameter(ParameterType.FeeAccount, fee_account)

/**
* @param {FundingInfo[]} funding_infos
*/
Parameter(ParameterType.FundingInfos, funding_infos)

/**
* @param {MarginInfo} margin_info
*/
Parameter(ParameterType.MarginInfo, margin_info)

/**
* @param {ContractInfo} contract_info
*/
Parameter(ParameterType.ContractInfo, contract_info)
```

### type UpdateGlobalVarBuilder

#### constructor

```javascript
/**
* @param {number} from_chain_id
* @param {number} sub_account_id
* @param {Parameter} parameter
* @param {number} serial_id
*/
UpdateGlobalVarBuilder(from_chain_id, sub_account_id, parameter, serial_id)
```

### type UpdateGlobalVar

[UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var) transaction type.

#### constructor

```javascript
/**
* @param {UpdateGlobalVarBuilder} builder
*/
newUpdateGlobalVar(builder)
```

#### Example

```javascript
const margin_info = new MarginInfo(2,17,10).jsValue();
const parameter = new Parameter(ParameterType.MarginInfo,margin_info)
console.log(parameter);

let tx_builder = new UpdateGlobalVarBuilder(1,8,parameter,1000);
console.log(tx_builder);
let tx = newUpdateGlobalVar(tx_builder);
console.log(tx.jsValue());
```


# Dart

**2024-04-30 v0.0.1**

* Initialize SDK


# Signature

### Type ZkLinkSigner

`ZkLinkSigner` includes the L1 private key(Eth or Starknet) and L3 private key.

#### func ethSig

```dart
ZkLinkSigner ethSig(String sig)
```

Creat a [ZkLinkSigner](#type-zklinksigner) from eth personal sign.

**input:**

* sig: hex string of eth personal sign(with or without `0x` prefix)

#### func starknetSig

```dart
ZkLinkSigner starknetSig(String sig)
```

Creat a [ZkLinkSigner](#type-zklinksigner) from starknet signature.

**input:**

* sig: hex string of starknet signature(with or without `0x` prefix)

#### func getPubkey

```dart
String getPubkey()
```

Return hex string of public key.

#### func getPubkeyHash

```dart
String getPubkeyHash()
```

Return hex string of public key hash.

#### func signMusig

```dart
ZkLinkSignature signMusig(List<int> msg)
```

Sign and create [ZkLinkSignature](/developer/api-and-sdk/basic-types#zklinksignature) from raw message.

### Type Signer

L1 private key.

#### func ethSigner

```dart
Signer ethSigner(String ethPrivateKey)
```

Create a Ethereum private key signer.

**input:**

* ethPrivateKey: hex string of private key(with or without `0x` prefix)

#### func starknetSigner

```dart
Signer starknetSigner(String ethPrivateKey, String starknetChainId, String starknetAddr)
```

Create a Starknet signer.

**input:**

* ethPrivateKey: hex string of starknet private key
* starknetChainId: chain id of starknet
* starknetAddr: starknet address

#### func signChangePubkeyWithOnchain

```dart
String signChangePubkeyWithOnchain(ChangePubKey tx)
```

#### func signChangePubkeyWithEthEcdsaAuth

```dart
String signChangePubkeyWithEthEcdsaAuth(ChangePubKey tx)
```

#### func signChangePubkeyWithCreate2DataAuth

```dart
String signChangePubkeyWithCreate2DataAuth(
    ChangePubKey tx,
    String creatorAddress,
    String saltArg,
    String codeHash,
```

#### Example

```dart
var signer = Signer.ethSigner(ethPrivateKey: "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4");
var tx = ChangePubKey(
    chainId: 1,
    accountId: 2,
    subAccountId: 4,
    newPubkeyHash: "0xd8d5fb6a6caef06aa3dc2abdcdc240987e5330fe",
    feeToken: 1,
    fee: "100",
    nonce: 100,
);
print(signer.signChangePubkeyWithCreate2DataAuth(
    tx: tx,
    creatorAddress: '0x6E253C951A40fAf4032faFbEc19262Cd1531A5F5',
    saltArg: '0x0000000000000000000000000000000000000000000000000000000000000000',
    codeHash: '0x4f063cd4b2e3a885f61fefb0988cc12487182c4f09ff5de374103f5812f33fe7',
));
```

#### func signWithdraw

```dart
String signWithdraw(
    Withdraw tx,
    String tokenSymbol,
    String? chainId,
    String? addr,
)
```

#### func signTransfer

```dart
String signTransfer(
    Transfer tx,
    String tokenSymbol,
    String? chainId,
    String? addr,
)
```

#### func signForcedExit

```dart
String signForcedExit(ForcedExit tx)
```

#### func createSignedOrder

```dart
Order createSignedOrder(Order order)
```

#### func signOrderMatching

```dart
String signOrderMatching(OrderMatching tx)
```

#### Example

```dart
var signer = Signer.ethSigner(ethPrivateKey: "0xbe725250b123a39dab5b7579334d5888987c72a58f4508062545fe6e08ca94f4");
var maker = signer.createSignedOrder(order: Order(
    accountId: 5,
    subAccountId: 1,
    slotId: 1,
    nonce: 1,
    baseTokenId: 18,
    quoteTokenId: 17,
    amount: "10000000000000",
    price: "10000000000",
    isSell: true,
    makerFeeRate: 5,
    takerFeeRate: 3,
    hasSubsidy: false,
));
var taker = signer.createSignedOrder(order: Order(
    accountId: 6,
    subAccountId: 1,
    slotId: 1,
    nonce: 1,
    baseTokenId: 18,
    quoteTokenId: 17,
    amount: "10000000000000",
    price: "10000000000",
    isSell: false,
    makerFeeRate: 5,
    takerFeeRate: 3,
    hasSubsidy: false,
));
var contractPrices = [
    ContractPrice(pairId: 1, marketPrice: "100"),
    ContractPrice(pairId: 2, marketPrice: "200"),
    ContractPrice(pairId: 3, marketPrice: "300"),
    ContractPrice(pairId: 4, marketPrice: "400"),
];
var marginPrices = [
    SpotPriceInfo(tokenId: 11, price: "100"),
    SpotPriceInfo(tokenId: 12, price: "200"),
    SpotPriceInfo(tokenId: 13, price: "300"),
];
var tx = OrderMatching(
    accountId: 10,
    subAccountId: 1,
    taker: taker,
    maker: maker,
    fee: "1000000000",
    feeToken: 18,
    contractPrices: contractPrices,
    marginPrices: marginPrices,
    expectBaseAmount: "10000000000000000",
    expectQuoteAmount: "10000000000000000",
);
print(signer.signOrderMatching(tx: tx));
```

#### func createSignedContract

```dart
Contract createSignedContract(Contract contract)
```

#### func signContractMatching

```dart
String signContractMatching(ContractMatching tx)
```

#### func signAutoDeleveraging

```dart
String signAutoDeleveraging(AutoDeleveraging tx)
```

#### func signFunding

```dart
String signFunding(Funding tx)
```

#### func signLiquidation

```dart
String signLiquidation(Liquidation tx)
```


# Utils

#### func isTokenAmountPackable

```dart
bool isTokenAmountPackable(String amount)
```

Checks whether the token amount can be packed (and thus used in the transaction)

#### func isFeeAmountPackable

```dart
bool isFeeAmountPackable(String fee)
```

Checks whether the fee amount can be packed (and thus used in the transaction)

#### func closestPackableTokenAmount

```dart
String closestPackableTokenAmount(String amount)
```

Returns the closest possible packable token amount. Returned amount is always less or equal to the provided amount.

#### func closestPackableFeeAmount

```dart
String closestPackableFeeAmount(String fee)
```

Returns the closest possible packable fee amount. Returned amount is always less or equal to the provided amount.

#### Example

```dart
var amount = "1234567899808787";
print("Original amount: " + amount);
expect(isTokenAmountPackable(amount: amount), false);
amount = closestPackableTokenAmount(amount: amount);
expect(isTokenAmountPackable(amount: amount), true);
print("Converted amount: " + amount);
var fee = "10000567777";
print("Original fee: " + fee);
expect(isFeeAmountPackable(fee: fee), false);
fee = closestPackableFeeAmount(fee: fee);
expect(isFeeAmountPackable(fee: fee), true);
print("Converted fee: " + fee);
```


# Transactions


# ChangePubKey

[ChangePubkey](/developer/api-and-sdk/transaction/change_pubkey) transaction type.

```dart
ChangePubkey(
    int chainId,
    int accountId,
    int subAccountId,
    String newPubkeyHash,
    int feeToken,
    String fee,
    int nonce,
    String? ethSignature,
    int? ts,
)
```

## func getEthSignMsg

```dart
String getEthSignMsg(int nonce, int accountId)
```

Get the Ethereum sign message

## func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

## func toJson

```dart
String toJson()
```

Get the json str of [ChangePubKey](#type-changepubkey)

## func toEip712RequestPayload

```dart
String toEip712RequestPayload(int chainId, String address)
```

Get the EIP-712 structured data of [ChangePubKey](#type-changepubkey)

## func setEthAuthData

```dart
void setEthAuthData(String sig)
```

Set Ethereum authentication data with given EthECDSA signature

## Example

```dart
var zklinkSigner = ZkLinkSigner.ethSig(sig: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
String pubkeyHash = zklinkSigner.getPubkeyHash();
print(pubkeyHash);
var tx = ChangePubKey(
    chainId: 1,
    accountId: 2,
    subAccountId: 4,
    newPubkeyHash: pubkeyHash,
    feeToken: 1,
    fee: "100",
    nonce: 100
);
tx.sign(zkLinkSigner: zklinkSigner);
print(tx.toEip712RequestPayload(chainId: 1, address: "0xa97153dd89c6f8F3BeA66190a6e62020aC7213de"));
String ethSignMsg = tx.getEthSignMsg(nonce: 100, accountId: 1);
tx.setEthAuthData(sig: "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b");
print(tx.toJson());
```


# Withdraw

[Withdraw](/developer/api-and-sdk/transaction/withdraw) transaction type.

```dart
Withdraw(
	int accountId,
	int subAccountId,
	int toChainId,
	String toAddress,
	int l2SourceToken,
	int l1TargetToken,
	String amount,
	String? callData,
	String fee,
	int nonce,
	bool withdrawToL1,
	int withdrawFeeRatio,
	int? ts,
)
```

## func getEthSignMsg

```dart
String getEthSignMsg(String tokenSymbol)
```

Get the Ethereum sign message

## func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

## func toJson

```dart
String toJson()
```

Get the json str of [Withdraw](#type-withdraw)


# Transfer

[Transfer](/developer/api-and-sdk/transaction/transfer) transaction type.

```dart
Transfer(
	accountId,
	String toAddress,
	int fromSubAccountId,
	int toSubAccountId,
	int token,
	String fee,
	String amount,
	int nonce,
	int? ts,
)
```

## func getEthSignMsg

```dart
String getEthSignMsg(String tokenSymbol)
```

Get the Ethereum sign message

## func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

## func toJson

```dart
String toJson()
```

Get the json str of [Transfer](#type-transfer)


# ForcedExit

[ForcedExit](/developer/api-and-sdk/transaction/forced_exit) transaction type.

```dart
ForcedExit(
    int toChainId,
    int initiatorAccountId,
    int initiatorSubAccountId,
    int targetSubAccountId,
    String target,
    int l2SourceToken,
    int l1TargetToken,
    String exitAmount,
    int initiatorNonce,
    bool withdrawToL1,
    int? ts,
)
```

## func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

## func toJson

```dart
String toJson()
```

Get the json str of [ForcedExit](#type-forcedexit)


# OrderMatching

### type ContractPrice

```dart
ContractPrice(
    int pairId,
    String marketPrice,
)
```

**input:**

* pairId: The contract pair id defined by zkLink.
* marketPrice: The market price of the contract pair

### type SpotPriceInfo

```dart
SpotPriceInfo(
    int tokenId,
    String price,
)
```

**input:**

* tokenId: The token id defined by zkLink.
* price: The spot price of the token.

### type Order

The [Order](/developer/api-and-sdk/transaction/order_matching) struct of taker and maker.

```dart
Order(
    int accountId,
    int subAccountId,
    int slotId,
    int nonce,
    int baseTokenId,
    int quoteTokenId,
    String amount,
    String price,
    bool isSell,
    int makerFeeRate,
    int takerFeeRate,
    bool hasSubsidy,
)
```

#### func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign order with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

#### func toJson

```dart
String toJson()
```

Get the json str of [Order](#type-order)

### type OrderMatching

[OrderMatching](/developer/api-and-sdk/transaction/order_matching) transaction type.

```dart
OrderMatching(
    int accountId,
    int subAccountId,
    Order taker,
    Order maker,
    String fee,
    int feeToken,
    List<ContractPrice> contractPrices,
    List<SpotPriceInfo> marginPrices,
    String expectBaseAmount,
    String expectQuoteAmount,
)
```

#### func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

#### func toJson

```dart
String toJson()
```

Get the json str of [OrderMatching](#type-ordermatching)


# ContractMatching

### type ContractPrice

```dart
ContractPrice(
    int pairId,
    String marketPrice,
)
```

**input:**

* pairId: The contract pair id defined by zkLink.
* marketPrice: The market price of the contract pair

### type SpotPriceInfo

```dart
SpotPriceInfo(
    int tokenId,
    String price,
)
```

**input:**

* tokenId: The token id defined by zkLink.
* price: The spot price of the token.

### type Contract

The [Contract](/developer/api-and-sdk/transaction/contract_matching) struct of taker and maker in perpetual contract.

```dart
Contract(
    int accountId,
    int subAccountId,
    int slotId,
    int nonce,
    int pairId,
    String size,
    String price,
    bool direction,
    int makerFeeRate,
    int takerFeeRate,
    bool hasSubsidy,
)
```

#### func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign contract with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

#### func toJson

```dart
String toJson()
```

Get the json str of [Contract](#type-contract)

### type ContractMatching

[ContractMatching](/developer/api-and-sdk/transaction/contract_matching) transaction type.

```dart
ContractMatching(
    int accountId,
    int subAccountId,
    Contract taker,
    List<Contract> maker,
    String fee,
    int feeToken,
    List<ContractPrice> contractPrices,
    List<SpotPriceInfo> marginPrices,
)
```

#### func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

#### func toJson

```dart
String toJson()
```

Get the json str of [ContractMatching](#type-contractmatching)


# AutoDeleveraging

### type ContractPrice

```dart
ContractPrice(
    int pairId,
    String marketPrice,
)
```

**input:**

* pairId: The contract pair id defined by zkLink.
* marketPrice: The market price of the contract pair

### type SpotPriceInfo

```dart
SpotPriceInfo(
    int tokenId,
    String price,
)
```

**input:**

* tokenId: The token id defined by zkLink.
* price: The spot price of the token.

### type AutoDeleveraging

[AutoDeleveraging](/developer/api-and-sdk/transaction/auto_deleveraging) transaction type.

```dart
AutoDeleveraging(
    int accountId,
	int subAccountId,
	int subAccountNonce,
	List<ContractPrice> contractPrices,
	List<SpotPriceInfo> marginPrices,
	int adlAccountId,
	int pairId,
	String adlSize,
	String adlPrice,
	String fee,
	int feeToken,
)
```

#### func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

#### func toJson

```dart
String toJson()
```

Get the json str of [AutoDeleveraging](#type-autodeleveraging)


# Funding

[Funding](/developer/api-and-sdk/transaction/funding) transaction type.

```dart
Funding(
    int accountId,
	int subAccountId,
	int subAccountNonce,
	List<int> fundingAccountIds,
	String fee,
	int feeToken,
)
```

## func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

## func toJson

```dart
String toJson()
```

Get the json str of [Funding](#type-funding)


# Liquidation

### type ContractPrice

```dart
ContractPrice(
    int pairId,
    String marketPrice,
)
```

**input:**

* pairId: The contract pair id defined by zkLink.
* marketPrice: The market price of the contract pair

### type SpotPriceInfo

```dart
SpotPriceInfo(
    int tokenId,
    String price,
)
```

**input:**

* tokenId: The token id defined by zkLink.
* price: The spot price of the token.

### type Liquidation

[Liquidation](/developer/api-and-sdk/transaction/liquidation) transaction type.

```dart
Liquidation(
    int accountId,
	int subAccountId,
	int subAccountNonce,
	List<ContractPrice> contractPrices,
	List<SpotPriceInfo> marginPrices,
	int adlAccountId,
	int pairId,
	String adlSize,
	String adlPrice,
	String fee,
	int feeToken,
)
```

#### func sign

```dart
void sign(ZkLinkSigner zkLinkSigner)
```

Sign transaction with given [ZkLinkSigner](/developer/sdk/changelog-2/signer#type-zklinksigner)

#### func toJson

```dart
String toJson()
```

Get the json str of [Liquidation](#type-liquidation)


# UpdateGlobalVar

### type ContractPrice

```dart
ContractPrice(
    int pairId,
    String marketPrice,
)
```

**input:**

* pairId: The contract pair id defined by zkLink.
* marketPrice: The market price of the contract pair

### type SpotPriceInfo

```dart
SpotPriceInfo(
    int tokenId,
    String price,
)
```

**input:**

* tokenId: The token id defined by zkLink.
* price: The spot price of the token.

### type FundingInfo

```dart
FundingInfo(
    int pairId,
    String price,
	int fundingRate,
)
```

### type Parameter

The [Parameter](/developer/api-and-sdk/transaction/update_global_var) struct of [UpdateGlobalVar](#type-updateglobalvar).

#### func insuranceFundAccount

```dart
insuranceFundAccount(int accountId)
```

#### func feeAccount

```dart
feeAccount(int accountId)
```

#### func marginInfo

```dart
marginInfo(
	int marginId,
	String? symbol,
	int tokenId,
	int ratio,
)
```

#### func contractInfo

```dart
contractInfo(
	int pairId,
    String symbol,
	int initialMarginRate,
	int maintenanceMarginRate,
)
```

#### func feeAccount

```dart
feeAccount(int accountId)
```

#### func fundingInfos

```dart
fundingInfos(List<FundingInfo> infos)
```

### type UpdateGlobalVar

[UpdateGlobalVar](/developer/api-and-sdk/transaction/update_global_var) transaction type.

```dart
UpdateGlobalVar(
    int fromChainId,
	int subAccountId,
	Parameter parameter,
	double serialId,
)
```

#### func toJson

```dart
String toJson()
```

Get the json str of [UpdateGlobalVar](#type-updateglobalvar)

#### Example

```dart
var tx = UpdateGlobalVar(
	fromChainId: 1,
	subAccountId: 2,
	parameter: Parameter.feeAccount(accountId: 8),
	serialId: 101
);
print(tx.toJson());
```


# Connected Networks


# Mainnet

<table data-full-width="false"><thead><tr><th width="133">Network</th><th width="86">zkLink ChainID</th><th width="92">ChainId</th><th width="130">Supported</th><th width="93">Dunkirk</th><th width="92">Deposit Confirmations</th><th width="78">Est.</th><th>Comment</th></tr></thead><tbody><tr><td>Ethereum Mainnet</td><td>4</td><td>1</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>64</td><td>12.8m</td><td>--</td></tr><tr><td>zkSync Era</td><td>5</td><td>324</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>60</td><td>1m</td><td>--</td></tr><tr><td>Scroll</td><td>6</td><td>534351</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>-</td><td></td><td>--</td></tr><tr><td>Linea</td><td>7</td><td>59144</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>5</td><td>1m</td><td>--</td></tr><tr><td>Bsc</td><td>3</td><td>56</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>20</td><td>1m</td><td>--</td></tr><tr><td>Polygon</td><td>1</td><td>137</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>300</td><td>10m</td><td>--</td></tr><tr><td>Avalanche</td><td>2</td><td>43114</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>30</td><td>1m</td><td>--</td></tr><tr><td>StarkNet</td><td></td><td>--</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>-</td><td></td><td>--</td></tr><tr><td>Polygon zkEVM</td><td>8</td><td>1101</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>-</td><td></td><td>--</td></tr><tr><td>Arbitrum One</td><td>9</td><td>42161</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>20</td><td>1m</td><td>--</td></tr><tr><td>Optimism</td><td>10</td><td>10</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>30</td><td>1m</td><td>--</td></tr><tr><td>Base</td><td>11</td><td>8453</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>30</td><td>1m</td><td>--</td></tr><tr><td>opBNB</td><td>15</td><td>204</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>60</td><td>1m</td><td>--</td></tr></tbody></table>


# Testnet

<table data-full-width="false"><thead><tr><th width="124">Network</th><th width="85">zkLinkChainID</th><th width="93">ChainId</th><th width="120">Supported</th><th width="84">Dunkirk</th><th width="97">Deposit Confirmations</th><th>Est.</th><th>Comment</th></tr></thead><tbody><tr><td>Goerli Testnet</td><td>4</td><td>5</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>64</td><td>12.8m</td><td>--</td></tr><tr><td>zkSync Era Testnet</td><td>5</td><td>280</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>60</td><td>1m</td><td>--</td></tr><tr><td>Scroll Alpha Testnet</td><td>6</td><td>534353</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>--</td><td>--</td><td>Lack of support for Sha2-256</td></tr><tr><td>Linea Goerli Testnet</td><td>7</td><td>59140</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>5</td><td>1m</td><td>--</td></tr><tr><td>Bsc Testnet</td><td>3</td><td>97</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>20</td><td>1m</td><td>--</td></tr><tr><td>Polygon Testnet</td><td>1</td><td>80001</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>300</td><td>10m</td><td>--</td></tr><tr><td>Avax Testnet</td><td>2</td><td>43113</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>30</td><td>1m</td><td>--</td></tr><tr><td>StarkNet</td><td></td><td>--</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>--</td><td></td><td>--</td></tr><tr><td>Polygon zkEVM</td><td>8</td><td>1101</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td>--</td><td></td><td>--</td></tr><tr><td>Arbitrum Testnet</td><td>9</td><td>421613</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>20</td><td>1m</td><td>--</td></tr><tr><td>Optimism<br>Testnet</td><td>10</td><td>420</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>30</td><td>1m</td><td>--</td></tr><tr><td>Base<br>Testnet</td><td>11</td><td>84531</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>30</td><td>1m</td><td>--</td></tr><tr><td>OKX X1</td><td>12</td><td>5001</td><td>Compressed Mode Only</td><td><mark style="color:green;">✔</mark></td><td></td><td></td><td>--</td></tr><tr><td>Manta Pacific</td><td>13</td><td>3441005</td><td><mark style="color:green;">✔</mark></td><td><mark style="color:green;">✔</mark></td><td>6</td><td>1m</td><td>--</td></tr><tr><td>Taiko</td><td>14</td><td>167005</td><td></td><td></td><td>12</td><td>1m</td><td>--</td></tr></tbody></table>


# DApps & Deployment Addresses




---

[Next Page](/llms-full.txt/1)

