---
# System prepended metadata

title: zkSBT ETH集成Spec/Workflow

---

# ZKSBT Integration Spec/Workflow/Interface


# TODO

8.22 weekly sync:

目标 :
NPO : 完成Testnet V1的测试, bug fix, 上Testnet V2, 新增功能 :
   (1) 用户自付gas fee
   (2) proof key management(增删)

POMP : 开发，集成，下周中上Testnet V1.

1. npo
    - Testnet V1 : QA Test, Bug Fix
    - Testnet V2 :
        - (1) 用户自付gas fee
        - (2) proof key management
2. pomp
    - 设计稿
    - range : 不同asset的range有产品定义，数量有限，sdk中用string表示，链上用keccak(string)
    - email project : 增加一次邮箱认证交互(前后端)，邮箱信息不上链
    - 下周一联调. 下周三提测.


8.15 weekly sync:
目标 : 本周上测试网版本，QA提侧
1. SDK :
    - generateProofKey 去掉root
    - backend verify proof.
    - 上新/升级. (后端规则代码check_eligible, 链上发交易,加mintID/(名字 zkBAB?), 前后端token名字)
    - 每种pomp是一个SBT Category : POMP-BNB-ETH, POMP-ETH-USDT. attribute调整为range.
    - [TODO]"sbt category" --> mintID.
2. Backend : 
    - NFT List 接口
    - mint立即返回(eligible : true/false)
    - mint status 接口 (minting, minted, 链上失败?)
3. Frotnend :
    - 生成proof，查询proof key
    - NPO/POMP原型变动支持.



<!-- - sbt_id 分配放链上? backend_sig 重放？
- 增加SBT type/attribute, 是否需要升级合约? -->

# zksbt Fee
- pulbic mint, privacy verify
- user 向backend申请certification，获得 sbt id, certificate signature, proof key. 此时proof key未生效.
- user 直接mint，付gas fee，以及项目方fee
- backend 同步链上信息, proof key生效.
- user 通过proof key manage协议，生成


# Design Goal



- 无私钥，根据user签名生成public address
- NPO/POMP兼容代码
- 兼容Calamari的一些接口，如mintID含义.
- zkSBT由manta server认证, 并提供mint授权
- 拿到授权的任何人，可以mint该zkSBT
- Proof Key生成机制开源，可复制, web2项目方可以使用manta的proof key
- web2项目方也可以不经过server, 自己认证user的SBT所有权

# Address
||Manta Atlantic|Manta Pacific|
|---|---|---|
|public address | public address | public address|
|private address| zkaddress | eth address|
|eth address|eth address|eth address|


# SBT Spec

<!-- 前端在没有server的情况下, 能够根据链上sbt信息，展示用户所拥有的zkSBT.
- 如何区分 zkBAB，zkBadger, POMP等SBT
- 链上存储SBT metadata (图片, URL) -->



- category  : 和mintID定义相同
```typescript
    enum SBT_CATEGORY { 
      ZKBAB = 1,
      ZKKYC = 2,
      pompETH = 12,
      pompBNB = 13
        ......
    }
```
- attribute : 更细粒度的属性，如pomp range
```typescript
    enum POMP_RANGE {
      RANGE_0 = "0",
      RANGE_1 = "1",
      RANGE_10 = "10",
      RANGE_100 = "100"
    }
```
- id : server端认证后分配



<!-- ## 签名消息格式 -->



# Proof Key

<!-- Motivation : 没有server参与的情况下，第三方是否也能作为验证机构? -->

## mint SBT生成Proof Key

mint时，有用户签名，即可生成proof key，无需依赖用户生成zkp proof.


## Proof Key管理(增/删)

需要增/删proof key, 则需要用户证明对zkSBT的所有权，证明方式有二种 :
1. 和mint类似的签名方式
    - user 签名 (public_address, sbt_id), 泄漏用户以太坊地址.
    - backend 验签，生成proof key
    - 问题 : 纯链下, 有中心化风险, proof key只能由我们自己的server产生

2. 使用zk-proof证明 :
    - backend/第三方提供随机数salt
    - user基于salt，生成zk proof
    - backend 验证zk proof, 并生成proof key = hash(zk-proof, salt)


# Workflow

1. Frontend连接钱包，初始化SDK，生成public address
```typescript
    // 初始化SDK
    const sdk = await ZKSbtSDK.create(wallet)
    const public_address = sdk.getPublicAddress()
```
2. [mint with gas fee] User向Backend发起mint SBT请求
    - Frontend签名(public address, category, attribute), 给Backend发Post Certificate
    ```typescript
        let category = 12
        let attribute = "100"
        let user_signature = await sdk.claimSbtSignature(category, attribute)
        
        Post "Certificate"
    ```
    - backend 从签名中恢复eth_addr, 分配sbt id, 签名(public Address, sbt_id),返回给Frontend
    ```typescript
        return signature(public Address, sbt_id)
    ```
    - user发起链上mint交易
    ```typescript
        await sdk.mint(category, attribute, backend_certificate.sbt_id, backend_certificate.signature)
    ```
    - backend 监听到链上event, 生成proof key
    ```solidity
        event SbtMinted(uint indexed identity, uint category, string attribute, uint id);
    ```

4. [mint without gas fee] 链上mint SBT并得到Proof Key
    - user要求backend发起链上mint交易(backend_sig, identity, sbt_id)
    ```typescript
    const res = await backend.mintAndGetProofKey(
      sdk.getPublicAddress(),
      category,
      attribute,
      claim_sbt_signature
    )
    const proof_key = res.proof_key
    ```
    - 合约验证backend签名正确，mint sbt_id给到identity
5. user界面查看已经mint到zkSBT(链上查询)
6. user向backend(或第三方希望用zkSBT作为认证)请求增/删zkSBT的proof key
    -  user给参数(identity, sbt_id)
    -  backend 检查sbt_id 已经mint到了identity
    -  backend产生一个随机数salt
    -  user根据salt, 生成zkp proof
    -  user给backend (zkp proof)
    -  backend 验证zkp proof.
    -  backend生成proof key = hash(zk-proof, salt)
7. user 界面zkSBT显示对应的proof key和二维码

```mermaid
sequenceDiagram
    participant F	as User/Frontend
    participant B 	as Backend
    participant C 	as Contract/Blockchain
    participant R 	as Relayer
    
    F -->> F  : connect_wallet
    F -->> F  : initlize sdk
    F -->> F  : public address = sdk.getPublicAddress()

    rect rgba(0, 220, 220, .3)
    %%F -->> B : mint("ETH", ">100") request 
    %% B -->> F : "salt" to prevent atack reply
    %%F -->> B : sign_mint = sign("mint pomp ETH>100 under $salt")
    F -->> F : sign_mint_sbt = sign("public_address", "sbt spec : pomp ETH>100")
    F -->> B : (sign_mint_sbt, public_address, sbt_info)
    B -->> B : recover eth_addr, check sbt eligible
    B -->> F : allocate sbt_id ?  backend signature(identity, sbt_id) 
    end

    %% on-chain mint
    rect rgba(220, 110, 220, .3)
        F -->> R : mint(backend_sig, identity, sbt_id)
        R -->> C : mint...
        C -->> C : verify backend_sig
        C -->> C : sbt[sbt_id] = identity.
    end

    %% Proof Key generate
    rect rgba(0, 110, 220, .3)
        F -->> B : generate proof key of (identity, sbt_id)
        B -->> C : check sbt_id mint to identity
        B -->> F : salt
        F -->> B : zk-proof = prove(salt)
        B -->> B : verify(zkp)
        B -->> F : proof key = hash(zkp, salt)
    end

```

# SBT上新

管理员(后端)发交易:
- 发交易add(category/attribute, "NAME")
```solidity
    await contract.addSbt(12, 0, "ZKBAB")
```


Backend/Frontend :
- 使用上述定义(category/attribute)来mint/展示sbt

# Interface



## [Frontend](https://github.com/Manta-Network/zksbt/blob/integrate/packages/jssdk/src/sdk.ts)
```typescript
  getPublicAddress : () => bigint;
  claimSbtSignature : (category : bigint, attribute : string) => Promise<string>;
  mint : (category : bigint, attribute : string, id : bigint, sig : string) => Promise<void>;
  generateProof : (category : bigint, attribute : string, root : bigint, salt : bigint) => Promise<Proof>;
```


## [Backend](https://github.com/Manta-Network/zksbt/blob/integrate/packages/jssdk/src/backend.ts)

Post 接口 :
- mint
- certificate
- proof key manage



## Contract
```solidity=
  // sbt category --> sbt attribute --> public address --> sbt_id
  mapping(uint => mapping(string =>  mapping(uint => uint))) public sbt_minted;
  event SbtMinted(uint indexed identity, uint category, string attribute, uint id);

  function mint(
    uint[] calldata identity,
    uint[] calldata category,
    uint[] calldata attribute,
    uint[] calldata ids,
    bytes[] calldata certificate_signature
  );

  function addSbt(
    uint category,
    uint attribute,
    string calldata name
  );

  function verify(
    uint category,
    uint attribute,
    uint groupId,
    uint256 nullifierHash,
    uint256[8] calldata proof
  );

```

## TODO

1. Backend : QuerySbt 性能优化
    - 查询/展示用户已经mint的SBT, 目前是直接从链上读取，很慢
    - 一般无后端的dapp会用[subgraph](https://thegraph.com/explorer)做链上数据索引
    - zksbt有后端，并且mint默认由，因此可以代替subgraph功能，直接做index

2. Backend : mint过程中生成proof key
    - 现在的workflow，mint和生成proof key是独立的二个步骤
    - mintAndGenerateProofKey helper
    - 默认的salt值

3. Backend : 管理后台
    - 上线新的zkSBT(包括pomp新的资产支持)
    - SBT.createPomp(ASSET.ETH, RANGE.RANGE_100)

4. Backend : SearchProofKey()


5. Frontend V1.5
 
6. 合约优化
    - Sharding Merkle Tree (产研)
    - 多次mint 同一个pomp，不同的时间.
    - URL等meta信息上链？

7. 收sbt fee.
    - public mint, privacy verify

zkAddress差异化

SDK发版

合约审计