SUI Move 实战:构建首个基于 zkLogin 的私密笔记 dApp

·

无需助记词、钱包插件,仅用 OAuth 账号即可安全进入 Web3 场景。本文手把手教你使用 SUI Move 合约、React 前端与 zkLogin 零知识登录,打造一款“链上笔记本”。

目录


1. 项目目标


2. 零信任基石:什么是 zkLogin

zkLogin 是 SUI 官方推出的无钱包登录协议:

  1. 用户走 OAuth2/OpenID,拿到 JWT 令牌
  2. SUI 节点使用 zk-SNARK 电路验证令牌合法性,自动派生 SUI 地址
  3. 零知识保证:任何人看不到 JWT 原始内容,却可验证“令牌有效”
关键词:zkLoginSUI无钱包登录JWTOAuth

3. 环境准备

3.1 获取示例仓库

git clone https://github.com/dacadeorg/zk-login-boilerplate
cd zk-login-boilerplate
yarn install

3.2 Google OAuth 创建

  1. 打开 Google Cloud 控制台
  2. 新建项目 → OAuth 2.0 凭据 → 记录 Client ID & Client Secret
  3. 回到项目根目录,新建 .env
REACT_APP_CLIENT_ID=<YOUR_CLIENT_ID>.apps.googleusercontent.com
REACT_APP_PROVER_URL=https://prover-dev.mystenlabs.com/v1
REACT_APP_REDIRECT_URL=http://localhost:3000
REACT_APP_OPENID_PROVIDER_URL=https://accounts.google.com/.well-known/openid-configuration
REACT_APP_FULLNODE_URL=http://127.0.0.1:9000
REACT_APP_PACKAGE_ID=<稍后部署生成的PackageID>

👉 跟着官方文档快速验证 OAuth 回调流程,避 99% 的坑。

3.3 本地链启动

RUST_LOG="off,sui_node=info" sui-test-validator
# 新开终端,切换网络
sui client new-env --alias localnet --rpc http://127.0.0.1:9000
sui client switch --env localnet

领取测试 SUI:

export MY_ADDR=0x5c5882d73a6e5b6ea1743fb028eff5e0
curl -X POST http://127.0.0.1:9123/gas \
  -H "Content-Type: application/json" \
  -d "{\"FixedAmountRequest\":{\"recipient\":\"$MY_ADDR\"}}"

4. Move 合约设计与部署

4.1 初始化工程

sui move new notes
cd notes

4.2 核心合约

sources/notes.move

module notes::notes {
    use std::string::String;
    use sui::table::{Self, Table};
    use sui::tx_context::{Self, TxContext};
    use sui::object::{Self, UID};
    use sui::transfer;

    #[lint_allow(self_transfer)]
    public struct Ledger has key {
        id: UID,
        notes: Table<address, vector<Note>>,
    }

    public struct Note has store, drop {
        title: String,
        body: String,
    }

    fun init(ctx: &mut TxContext) {
        transfer::share_object(Ledger {
            id: object::new(ctx),
            notes: table::new(ctx),
        });
    }

    public entry fun add_note(ledger: &mut Ledger, title: String, body: String, ctx: &mut TxContext) {
        let sender = tx_context::sender(ctx);
        let new_note = Note { title, body };
        if (table::contains(&ledger.notes, sender)) {
            let notes = table::borrow_mut(&mut ledger.notes, sender);
            vector::push_back(notes, new_note);
        } else {
            table::add(&mut ledger.notes, sender, vector[new_note]);
        }
    }

    public entry fun del_note(ledger: &mut Ledger, idx: u64, ctx: &mut TxContext) {
        let sender = tx_context::sender(ctx);
        assert!(table::contains(&ledger.notes, sender), 0);
        let notes = table::borrow_mut(&mut ledger.notes, sender);
        assert!(idx < vector::length(notes), 1);
        vector::remove(notes, idx);
    }
}

4.3 合约部署

sui client publish --gas-budget 100000000
# 终端输出记录
PACKAGE_ID=0x3d133870aa4959c2804430d8d582d907537b521cff595fce865734

更新 .envREACT_APP_PACKAGE_ID


5. React 前端整合 zkLogin

5.1 Sui 客户端 service

核心逻辑回顾:

await AuthService.generateZkLoginSignature(userSig)
// 返回 SerializedSignature,可上链

5.2 笔记 CRUD 封装

新增笔记示例:

const txb = new TransactionBlock();
txb.moveCall({
  target: `${PACKAGE_ID}::notes::add_note`,
  arguments: [
    txb.object("<Ledger_Object_Id>"),
    txb.pure.string(title),
    txb.pure.string(body),
  ],
});

5.3 UI 组件栈

👉 源码级剖析:如何把 Google 登录按钮嵌成链上地址,立即体验。


6. 测试流程

步骤命令/操作
启动本地节点sui-test-validator
启动前端yarn start
登录访问 http://localhost:3000 → Google OAuth
查看地址右上角钱包地址
领水同上 curl 命令
创建/删除笔记前端交互

7. 常见问题(FAQ)

Q1. zkLogin 在正式网是否已可用?
A:截至 2025-06 已上线主网,推荐使用官方最新 CLI:≥v1.26。

Q2. OAuth 回调出现错误码 redirect_uri_mismatch
A:回到 Google Cloud 控制台,将 http://localhost:3000 作为授权回调 URI,保存即可。

Q3. 想更换其他 OAuth(GitHub、Apple)?
A:只需生成对应 OpenID .well-known 信息,环境变量替换即可,完整兼容 zkLogin。

Q4. 升级依赖时出现 @mysten/sui.js 版本冲突?
A:使用 pnpm up --latest 解决 Node-API 差异,或锁定至 v0.52.x。

Q5. 部署失败后合约 Gas 消耗过大?
A:减少 Table/Vector 初始化大小,或在 CLI 加 --gas-budget 200000000

Q6. zkLogin 地址能否与普通钱包共存?
A:可以。将派生地址导入任何生态钱包,私钥即 OAuth 派生凭证,安全由 zk 守护。


8. 后续优化方向

  1. 二次保密:用同态加密存储笔记 body,仅持有对应 NFT 可读
  2. 批量签名:一次 JWT 换取 n 次交易,避免频繁跳转
  3. 移动适配:将 React 重打包成 React-Native,更丝滑原生体验
  4. 多网络支持:在代码层把 REACT_APP_FULLNODE_URL 设为空,通过 Vercel Edge 自动切换

尾声

到这里,一个极简且安全的 基于 zkLogin 的 SUI Move 私密笔记 dApp 已经跑通。你会惊奇地发现,Web2 用户的零门槛之旅仅在几分钟内完成。借此思路,你可以轻松延伸出链上投票、博客、游戏资产等更多场景。祝开发愉快!