精通 Sui DeepBook:实战 DeFi DEX 系列(3)
Source: Dev.to
Source:
理解 Note 合约
下面是本教程中将使用的 Note 合约代码。该 Note 合约是一个非常简单的概念验证,允许用户创建和删除笔记。我们添加了详细的注释,帮助你理解代码的每一部分。
Note 模块
创建一个新文件 sources/notes.move 并添加以下代码:
#[lint_allow(self_transfer)]
module dacade_zklogin::notes {
use sui::tx_context::{TxContext, Self};
use sui::transfer::Self;
use sui::object::{Self, UID};
use std::string::String;
/// Struct to store the ID of the Notes (Shared Object)
struct Notes has key {
id: UID
}
/// Struct to represent a Note
struct Note has key, store {
id: UID,
title: String,
body: String
}
/// Module initializer to create the Notes shared object
#[allow(unused_function)]
fun init(ctx: &mut TxContext) {
let notes = Notes {
id: sui::object::new(ctx),
};
// Share the Notes object so it can be accessed by everyone
transfer::share_object(notes)
}
/// Function to create a new note
/// @param title: The title of the note
/// @param body: The body of the note
/// @param ctx: The transaction context
public fun create_note(title: String, body: String, ctx: &mut TxContext) {
let note = Note {
id: object::new(ctx),
title,
body
};
// Transfer the note to the sender of the transaction
transfer::transfer(note, tx_context::sender(ctx))
}
/// Function to delete a note
/// @param note: The note object to be deleted
/// @param _ctx: The transaction context
public fun delete_note(note: Note, _ctx: &mut TxContext) {
// Unpack the Note struct to access its fields
let Note { id, title: _, body: _ } = note;
// Delete the object ID, effectively deleting the note
sui::object::delete(id)
}
}
代码拆解
合约相当直观。
结构体 – 有两个结构体:Notes 和 Note。
Notes– 一个共享对象(在init中创建并共享)。在这个简化版本中,它仅保存一个 UID。Note– 表示单个笔记。它具有key和store能力,意味着它可以被地址拥有并可以转移。它存储笔记的id、title和body。
init 函数 – 在包发布时运行一次。它创建 Notes 结构体并共享,使其对所有人可访问。
create_note 函数 – 允许任何用户创建新笔记。它接受标题和正文,创建一个 Note 对象,并将其转移给交易的发送者 (tx_context::sender(ctx))。调用者成为该笔记的所有者。
delete_note 函数 – 允许笔记的所有者删除它。它按值(消耗)接收 Note 对象,解构后删除其 UID,从而实现笔记的删除。
编写完整的测试
测试对智能合约开发至关重要。我们将编写一个测试模块,以验证我们能够正确创建和删除笔记。
创建一个新文件 sources/notes_tests.move(或将其添加到已有的测试文件中):
#[test_only]
module dacade_zklogin::notes_tests {
use dacade_zklogin::notes::{Self, Note};
use sui::test_scenario;
use std::string::{Self};
#[test]
fun test_create_and_delete_note() {
let user = @0xA;
// Start a test scenario with `user` as the sender
let scenario = test_scenario::begin(user);
// 1. Create a note
{
let ctx = test_scenario::ctx(&mut scenario);
let title = string::utf8(b"My First Note");
let body = string::utf8(b"This is the body of my note.");
notes::create_note(title, body, ctx);
};
// 2. Verify note creation and ownership
test_scenario::next_tx(&mut scenario, user);
{
Source: …
// Take the Note object from the sender's inventory
let note = test_scenario::take_from_sender(&scenario);
// If we successfully took it, the note was created and transferred to the user.
// Now, let's delete it.
// 3. Delete the note
let ctx = test_scenario::ctx(&mut scenario);
notes::delete_note(note, ctx);
};
// 4. Verify note deletion
test_scenario::next_tx(&mut scenario, user);
{
// Check that the user no longer has the note.
// `has_most_recent_for_sender` returns false if the object is no longer accessible/owned.
assert!(!test_scenario::has_most_recent_for_sender(&scenario), 0);
};
test_scenario::end(scenario);
}
}
运行测试
要运行测试,请在 contract 目录下打开终端并执行:
sui move test
您应该会看到指示测试通过的输出:
Running Move unit tests
[ PASS ] dacade_zklogin::notes_tests::test_create_and_delete_note
Test result: OK. Total tests: 1; passed: 1; failed: 0
“Note” 合约教程结束。
Source: …
发布合约
现在我们已经测试完合约,是时候将它发布到 Sui Devnet 了。
切换到 Devnet
确保你的 Sui 客户端已连接到 devnet 环境。
sui client switch --env devnet
发布
运行发布命令。我们设置了 gas 预算,以确保交易有足够的 gas 执行。
sui client publish --gas-budget 100000000
注意: 如果你还没有为地址充值,运行
sui client faucet获取一些测试 SUI。
保存重要信息
当你发布一个包时,Sui CLI 会输出交易摘要。该输出包含后续将前端应用连接到智能合约时 必须保存 的关键信息。
在输出中查找 Object Changes 部分。识别并保存以下 ID:
- Package ID – 已发布代码的 ID(在
Published Objects下列出)。 - Shared Object ID – 在
init函数中创建的Notes对象的 ID(在Created Objects中,Owner: Shared)。
示例输出分析
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0x81833f94d4019d03fdc0d63abdf179950740f513bf434ae182e1031e0568a2b7 │
│ │ Owner: Shared( 5 ) │
│ │ ObjectType: 0xfea5f1839d675fa03d5b02208adf2e6167336b4646399cb2248b9a7347a48998::notes::Notes │
│ └── │
│ ... │
│ Published Objects: │
│ ┌── │
│ │ PackageID: 0xfea5f183d675fa03d5b02208adf2e6167336b4646399cb2248b9a7347a48998 │
│ │ Version: 1 │
│ │ Digest: 93isZkd3bCKDqeMUL1wUhWnxYvJT4KLc72U6buFAPS4F │
│ │ Modules: notes │
│ └── │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
需要保存的内容
- Package ID:
0xfea5...8998(来自Published Objects部分) - Notes Shared Object ID:
0x8183...a2b7(来自Created Objects部分且 Owner 为Shared)
提示: 现在在前端项目中创建一个 .env 文件或 constants.ts 文件,并将这些值保存进去。后续在 UI 中与合约交互时需要用到它们。
恭喜你!如果你已经看到这里,给自己一个应得的赞——你已经正式佩戴上区块链专业人士的徽章了。 😄
你已经成功编写、测试并发布了你的第一个 Sui Move 智能合约。相当不错。
接下来,我们将在 DeepBook DEX 前端构建核心组件时把这些概念付诸实践,理论与实践相结合,精彩即将展开。