---
# System prepended metadata

title: 'Hello, Zinc!'

---

# Hello, Zinc!
### Intro
Zinc 是一套程式語言用來開發
1. Smart contract on zkSync.
2. General-purpose zero-knowledge proof circuits.

有鑒於現存的 ZKP frameworks 缺乏支持 smart contract 的特定功能。以及近期的新興 smart contract 語言，例如 Simplicity or Libra's Move，其設計上比起開發可讀性，更重視 safety 以及程式本身的正規可驗證性。

>The goal of Zinc is to make writing safe zero-knowledge circuits and ZKP-based smart contracts easy.

### Zinc 特點

- Type safety
    * 字串跟整數無法交互運算 
- Type inference
    * 根據數值直接決定型別
- Immutability
- Movable resources as a first-class citizen
- Module definition and import
- Expressive syntax
- Industrial-grade compiler optimizations
- Flat learning curve for Rust/JS/Solidity/C++ developers
- **Turing incompleteness: no recursion or unbounded looping**

### 語法使用
以下使用的版本為 zinc 0.2.3

1. const and variable
```
let x = 5566;
x = 2266; //  compile error!

let mut y = 5566;
y = 2266; // ok!
```
2. types
- Unit `()`
  * 類似 void
  * 沒辦法做運算也不能被 cast
  ```
  fn check(value: bool) {
    // several statements
  };
  let y = check(true); // y is ()
  ```
- Boolean: true/false, 0/1
  * 基於 type safety，不能 cast 為 integer 做運算
- Integer
  * u8 .. u248: unsigned integers
      * 8 的倍數
  * i8 .. i248: signed integers
      * 8 的倍數
  * field: the native field integer. 
      * It represents an unsigned integer of bitlength equal to the field modulus length (e.g. for BN256 the field modulus length is 254 bit).
  * decimal: 0, 1, 122, 574839572494237242
  * hexadecimal: 0x0, 0xfa, 0x0001, 0x1fffDEADffffffffffBEEFffff
  * Casting: only between integer <-> field. If the value does not fit into the target type, it is truncated.
  * If the literal type is not specified, the minimal possible bitlength is inferred.
  ```
  let a = 0; // u8
  let a: i24 = 0; // i24
  let b = 256; // u16
  let c = -1;  // i8
  let c = -129; // i16
  let d = 0xff as field; // field
  let e: field = 0; // field
  ```
- Array
  ```
  let mut fibbonaci = [0, 1, 1, 2, 3, 5, 8, 13];
  let element = fibbonaci[3];
  fibbonaci[2] = 1;
  ```
  * bit array: 
  ```
  let preimage_bits: [bool; 156]
  ```
- Tuple
  ```
  let mut tuple: (u8, field) = (0xff, 0 as field);
  tuple.0 = 42;
  dbg!("{}", tuple.1);
  ```
- Struct
  ```
  struct Arithmetic {
    x: field,
    y: field,
  }
  impl Arithmetic {
    pub fn add(self) -> field {
        self.a + self.b
    }
  }
  fn main() {
    let arithmetic = Arithmetic { a: 10 as field, b: 5 as field };
  }
  ```
- Enum
  ```
  enum Prize {
    Gold = 1,
    Silver = 2,
  }

  impl Prize {
    pub fn first() -> Self {
        Self::Gold
    }

    pub fn second() -> Self {
        Self::Silver
    }
  }

  fn main(score: field) -> field {
    let x = Prize::Gold;
    List::first() as field * score
  }
  ```
- String
  * 使用非常受限，目前只能用在 debug or require message
  ```
  dbg!("{}", 42); // format string
  require(true != false, "a very obvious fact"); // optional error message
  ``` 
- Map
  ```
  use std::collections::MTreeMap;

  contract Test {
    data: MTreeMap<u8, field>;
    
    pub fn new(owner: u160) -> Self {
        Self {
            data: MTreeMap,
        }
    }
    pub fn example(mut self) {
        let (old1, existed1) = self.data.insert(42, 9 as field);
        let (value, exists1) = self.data.get(42);
        let exists2 = self.data.contains(42);
        let (old2, existed2) = self.data.remove(42);
    }
  }
  ```
- Type alias
    ```
    type ComplexType = [(u8, [bool; 8], field); 16];
    ```
3. Fucntion
- public function: with `pub` keyword
  ```
  impl Data {
    pub fn sum(self) -> u8 {
        self.a + self.b + self.c + self.d
    }
  }
  ```
- const function
  * Called at compile-time, thus they may only accept and return constant expressions.
  * Useful when you need to use a lot of similar parameterized values.
  ```
  const fn cube(x: u64) -> u64 { x * x * x }

  fn main() {
    let cubed_ten = cube(10 as u64); // 1000
    let cubed_twenty = cube(20 as u64); // 8000
  }
  ```
4. Conditions
- If
  ```
   let x = 1;
   let c = if x == 1 {
     let a = 5;
     a
   } else if x == 2 {
     let b = 10;
     b
   };
  ``` 
- match
  * constant (e.g. 42)
  * path (e.g. MyEnum::ValueOne)
  * variable binding (e.g. value)
  * wildcard (_)
  ```
  const SCRUTINEE: u8 = 42;

  const MATCH: u8 = match SCRUTINEE {
    0 => 10,
    1 => 20,
    42 => 100,
    VALUE => 255 - VALUE,
  };
  ```
5. Control
- for-while loop
  ```
  for {identifier} in {range} [while {expression}] {
    ...
  }
  ```
  ```
  let x = 7;

  for i in 0..10 while i % x != 2 {
    // do something
  };
  ```
6. Debugging
Use special function `dbg!`
```
// a = 5, b = 3
fn print_sum(a: u8, b: u8) {
    dbg!("{} + {} = {}", a, b, a + b); // prints '5 + 3 = 8'
}
```

7. Testing
- Unit tests are just simple functions marked with the `#[test]`
- `#[should_panic]` such test must fail in order to succeed, e.g. by passing a false value to the require function or causing an overflow.
- `#[ignore]` such test is just ignored.
```
#[test]
fn ordinar() {
    require(2 + 2 == 4, "The laws of the Universe have been broken");
}

#[test]
#[should_panic]
fn panicking() {
    require(2 + 2 == 5, "And it's okay");
}

#[test]
#[ignore]
fn ignored() {
    require(2 + 2 > 4, "So we'll just ignore it");
}
```

8. Smart contract
- Implicit storage fields
  * contract address: u160,  ex: 0x224a0b11b36156c7fa4c4d784a8b85c93978e424
  * the contract balances: Map<u160, u248>, <address, amount>
  * Ref: https://rinkeby.zkscan.io/explorer/accounts/0x224a0b11b36156c7fa4c4d784a8b85c93978e424
- Explicit storage fields
  * 每一個 smart contract 的 storage 都會被 Zinc Zandbox server 寫入 persistent databases.
    ```
    contract Example {
        pub tokens: (u8, u64);

        data: [u8; 1000];

        //...
    }
    ```
- Constructor
    ```
    contract Example {
        pub value: u64;

        pub fn new(_value: u64) -> Self {
            Self {
                value: _value,
            }
        }
    }

    ```
- Public methods
  * The contract must have at least one public function.
    ```
    contract Example {
        //...

        pub fn deposit(mut self, amount: u64) -> bool { ...     }
    }
    ```
- Private methods
    ```
    contract Example {
        //...

        fn get_balance(address: u160) -> bool { ... }
    }
    ```
- Builtin methods
  * transfer
  * fetch
  * dbg
  * require
- Global variables
  * zksync::msg
  ```
   zksync::msg:sender //u160
   zksync::msg:recipient //u160
   zksync::msg:token_address //u160
   zksync::msg:amount //u160
  ```
- Constants 
    ```
    contract Example {
        //...

        pub const VERSION: u8 = 1; // public constant 

        const LIMIT: u8 = 255; // private constant
    }
    ```

### Hello, World!
#### Install zargo
下載對應的版本，解壓縮之後會有三個 bin: zargo, znc, zvm
實際上開發只需要 zargo
https://github.com/matter-labs/zinc/releases/tag/0.2.3
    > macos 第一次執行會被 Security&Privacy 擋住，需要先 approve

#### Create project
    ```
    $ zargo new --type contract constant_price
    ```
    ```
    //!
    //! The 'constant_price' contract entry.
    //!

    contract ConstantPrice {
        pub value: u64;

        pub fn new(value: u64) -> Self {
            Self {
                value: value,
            }
        }
    }
    ```
#### Try to code something
- removing the redundant value auto-generated field
- adding the fee parameter
- adding two mutable methods for making exchanges and deposits
- adding an immutable method for getting the contract fee value
- declaring the Address and Balance type aliases
- declaring the TokenAddress enumeration type with zkSync token addresses

Ref: https://zinc.zksync.io/07-smart-contracts/02-minimal-example.html


#### Compile
```
$ zargo build
```
會產生
- private_key: 用來部署 smart contract
- ./data/input.json: 部署 contract 的初始化參數

#### 部署到 Zinc testnet
1. Create zkSync account
zkSync on rinkeby: https://rinkeby.zksync.io/
Mint tokens on rinkeby: https://mint.zksync.dev/mint 
> NOTE: unlock account by transfering at first time
2. Publish contract to rinkeby
```
$ zargo publish --network rinkeby --instance default
```
Response:
```
   Compiling hello_swap v0.1.0
    Finished release [optimized] target
   Uploading the instance `default` of `hello_swap v0.1.0` to network `rinkeby`
     Address 0x9035a2b7cf9365e879ec26415d97a954cd68955f
  Account ID 190788
```
#### Query contract storage
```
$ zargo query --network rinkeby --address 0x9035a2b7cf9365e879ec26415d97a954cd68955f
```
Response:

```
{
  "address": "0x9035a2b7cf9365e879ec26415d97a954cd68955f",
  "balances": [
    {
      "key": "0x0",
      "value": "64000000000000"
    }
  ],
  "fee": "100"
}
```
#### Calling a non-mutable contract method
```
$ zargo query --network rinkeby --address 0x9035a2b7cf9365e879ec26415d97a954cd68955f --method get_fee
```
Response:
```
{
  "output": "100"
}
```
#### Calling a mutable contract method
修改 ./data/input.json
```
{
  "msg": {
    "sender": "0x009a0256ca6b16455f5b3a46b7aee448f929a45b",
    "recipient": "0x9035a2b7cf9365e879ec26415d97a954cd68955f",
    "token_address": "0xeb8f08a975ab53e34d8a0330e0d34de942c95926", // USDC
    "amount": "1_E6"
  }
}
```
Request:
```
$ zargo call --network rinkeby --address 0x9035a2b7cf9365e879ec26415d97a954cd68955f --method deposit
```
Response:
```
{
  "output": {
    "result": null,
    "root_hash": "0x0"
  }
}
```
Query storage again:
```
{
  "address": "0x9035a2b7cf9365e879ec26415d97a954cd68955f",
  "balances": [
    {
      "key": "0x0",
      "value": "64000000000000"
    },
    {
      "key": "0xeb8f08a975ab53e34d8a0330e0d34de942c95926",
      "value": "1000000"
    }
  ],
  "fee": "100"
}
```
#### Calling a `exchange` method
```
$ zargo call --network rinkeby --address 0x9035a2b7cf9365e879ec26415d97a954cd68955f --method exchange
```
實際上會產生出 2 筆 tx
Ref: https://rinkeby.zkscan.io/explorer/accounts/0x009a0256ca6b16455f5b3a46b7aee448f929a45b

### Discussion
1. 如何做合約升級? proxy contract?
2. 無限 fetch 另一個 contract?

### Reference
- https://github.com/matter-labs/zinc
- zkSync wallet: https://wallet.zksync.io/
- mint Token: https://mint.zksync.dev/
- zinc v0.2.3: https://zinc.zksync.io/index.html
- zinc v0.1.5: https://zinc.matterlabs.dev/09-zargo-circuit-manager/00-overview.html
- zkSync 1.x rinkeby: https://rinkeby.zkscan.io/
- zkSync 2.0 rinkeby: https://zksync2-alpha.zkscan.io/explorer/
- EthCC: ZKSYNC — FIRST EVM-COMPATIBLE ZKROLLUP, Alex Gluchowski @ July 21st 11:00 am
    * https://ethcc.io/agenda
- 更多期待 https://medium.com/matter-labs/zksync-2-0-hello-ethereum-ca48588de179