type
Post
status
Published
date
Feb 18, 2025
slug
summary
Sui 训练营 Task 3 的学习笔记,重点讲解 Publisher Authority 和 Sui Object Display,这一节的任务比较简单,所以代码里实现了一些其他实用的小功能。
tags
Move
category
Web3
icon
password
Property
Feb 18, 2025 02:55 AM
本文目标
- 完成 NFT 相关知识的学习
- 完成可以 mint NFT 的合约上链
- 给自己地址 mint 一个 NFT
- 理解 Publisher Authority
- 理解 Sui Object Display
介绍 NFT
近年来,一项突破性技术席卷了艺术、娱乐和数字收藏品世界——非同质化代币(NFT)。 这些数字资产彻底改变了我们在数字时代对所有权和真实性的看法。
NFT 是基于区块链技术的独特数字代币,这与比特币和以太坊等加密货币背后的技术相同。 NFT 的独特之处在于它们的个体性;每个代币代表一个独一无二的项目,无论是数字艺术作品、音乐、视频片段、虚拟房地产、游戏内物品,甚至是推文和表情包。 通过加密签名来验证代币的真实性和所有权,实现了这一独特性,使其防篡改并且可以在公共账本上验证。
NFT 为艺术家、创作者和收藏家开辟了激动人心的机会,使他们能够以前所未有的方式货币化和交易数字创作。 它们还引发了关于技术、所有权和数字文化未来的讨论。随着 NFT 不断发展并扩展到各个行业,它们正在重塑我们对数字资产的认知和互动方式,展示了区块链技术在加密货币之外的潜力。
NFT(非同质化代币)通过智能合约和唯一标识符在区块链上表示。其工作原理如下:
- 智能合约:NFT 是通过智能合约创建和管理的,这些合约是具有预定义规则和条件的自执行协议。 Sui等区块链平台上的智能合约负责 NFT 的创建、转移和所有权。这些合约包含了管理 NFT 行为的逻辑,例如如何创建、购买、出售和转移。
- 唯一标识符:每个 NFT 都有一个唯一标识符,将其与区块链上的其他所有代币区分开来。这个标识符通常是一长串字符,关联到特定的 NFT。 它通常被称为“代币 ID”或“代币索引”。这个标识符确保了 NFT 的唯一性,并允许它在区块链上轻松跟踪。
- 元数据:NFT 通常包括元数据,即与代币关联的数字资产的附加信息。 元数据可以包括创作者的详细信息、资产的描述、其属性以及实际数字文件的链接(例如图像、视频或音频文件)。 由于区块链的大小限制,元数据通常存储在链外(区块链外),并在 NFT 的智能合约中包含对这些元数据的引用。 这允许用户在不将全部内容存储在区块链上的情况下访问和显示关于 NFT 的信息。
- 所有权和转移:NFT 的所有权在区块链上跟踪。当创建 NFT 时,智能合约会记录初始所有者的钱包地址。 当 NFT 转移给另一方时,智能合约中的所有权信息会更新,以反映新所有者的钱包地址。这个转移过程是安全和透明的,因为它记录在区块链的公共账本上。
- 互操作性:NFT 通常在各种区块链平台上创建和交易,每个平台都有自己的一套标准。 为了确保不同平台之间的互操作性,出现了一些标准和协议,允许 NFT 在多个生态系统中被识别和使用。例如,以太坊上的 NFT 可以在遵循相同标准的各种 NFT 市场和平台上支持。
在 Sui 区块链上,使用对象创建和管理 NFT 非常容易。每个 NFT 都可以是一个对象,它本身就是唯一的,并且可以包含由创建者/开发者定义的任何元数据。 在接下来的课程中,我们将详细讨论如何在 Sui 上实现 NFT。
NFT 标准 - 集合和代币对象
为了理解如何实现 NFT,让我们定义 NFT 的核心组件——创作者、收藏品、代币(NFT):
创作者
创作者是负责生产和铸造 NFT 的个人或实体。他们可以是艺术家、音乐家、游戏开发者、内容创作者或任何生成独特数字内容的人,这些内容可以被代币化为 NFT。
创作者使用区块链平台和智能合约来铸造 NFT,定义每个代币的属性、所有权和相关规则。他们还可以为 NFT 指定属性和元数据,以向买家和收藏家提供附加信息和背景。
NFT 收藏品
NFT 收藏品是具有共同主题、风格或创作者的非同质化代币(NFT)组或集合。它们是独特数字资产的策划集合,通常围绕特定类型、艺术家、项目或类别组织。
例如,一个收藏品可能以数字艺术为中心,展示由各种艺术家创作的 NFT。另一个收藏品可能围绕虚拟房地产展开,提供虚拟世界中的独特虚拟土地。 每个收藏品中的 NFT 都是独特的,但它们根据共同的主题或关联被分组在一起。
NFT 代币
NFT 代币被分组到收藏品中。一旦创作者创建了一个收藏品,他们可以允许用户在同一收藏品中铸造 NFT 代币,每个代币都有唯一的标识符和属性。 是否限制一个收藏品可以铸造的 NFT 代币数量由创作者通过智能合约的实现方式来定义。
实现
在 Move 中,我们可以将 NFT 收藏品和代币表示为对象。一个收藏品对象可以有以下字段:
creator
:收藏品创作者的地址
name
:收藏品的名称,如“SuiFrens”
description
:收藏品的描述
limit
:可以在收藏品中铸造的代币数量
url
:收藏品的 URL
一个 NFT 代币通常有以下字段:
collection
:收藏品对象的地址
name
:代币的名称,例如“SuiFren #1234”
url
:代币图像的 URL
attributes
:代币的属性列表,如出生日期、世代等,就像我们在之前的课程中看到的那样。
NFT 代币还可以有其他属性,如显示信息、版税等,我们将在以后的课程中讨论更多。
创建 NFT
在 Sui 中,一切都可以被当做 NFT,因为对象(Object)是独一无二,可被拥有的。因此创建 NFT 只需要一个新的类型就可以。
module mynft::display_nft { use std::string::{Self, utf8, String}; // use sui::object::{Self, ID, UID}; use sui::tx_context:: sender; use sui::package; use sui::display; /// 一个允许任何人铸造NFT的示例 /// An example NFT that can be minted by anybody public struct MyNFT has key, store { id: UID, /// Name for the token 代币(NFT)名 name: string::String, /// Description of the token 代币(NFT)描述 description: string::String, /// URL for the token 代币(NFT)链接 image_url: String, // TODO: allow custom attributes } public struct DISPLAY_NFT has drop {} fun init(otw: DISPLAY_NFT, ctx: &mut TxContext){ let keys = vector[ utf8(b"name"), utf8(b"description"), utf8(b"image_url"), ]; let values = vector[ utf8(b"{name}"), utf8(b"{description}"), utf8(b"{image_url}"), ]; let publisher = package::claim(otw, ctx); let mut display = display::new_with_fields<MyNFT>(&publisher, keys, values, ctx); display::update_version(&mut display); transfer::public_transfer(publisher, sender(ctx)); transfer::public_transfer(display, sender(ctx)); } // ===== Public view functions ===== 公共视图函数 /// 获取NFT的名称 /// Get the NFT's `name` public fun name(nft: &MyNFT): &string::String { &nft.name } /// 获取NFT的介绍 /// Get the NFT's `description` public fun description(nft: &MyNFT): &string::String { &nft.description } /// 获取 NFT 的链接 /// Get the NFT's `url` public fun url(nft: &MyNFT): &string::String { &nft.image_url } // ===== Entrypoints ===== 入口函数 /// 创建新的NFT /// Create a new nft public entry fun mint(name:String, description:String, image_url: String, ctx: &mut TxContext) { let id = object::new(ctx); let nft = MyNFT {id, name, description, image_url}; transfer::public_transfer(nft, sender(ctx)); } /// 转移 NFT 给新的所有者 /// Transfer `nft` to `recipient` public entry fun transfer( nft: MyNFT, recipient: address, _: &mut TxContext ) { transfer::public_transfer(nft, recipient) } /// 更新 NFT 的介绍 /// Update the `description` of `nft` to `new_description` public entry fun update_description( nft: &mut MyNFT, new_description: vector<u8>, _: &mut TxContext ) { nft.description = string::utf8(new_description) } /// 永久删除 NFT /// Permanently delete `nft` public entry fun burn(nft: MyNFT, _: &mut TxContext) { let MyNFT { id, name: _, description: _, image_url: _ } = nft; object::delete(id) } }
重点需要讲解的部分是:
fun init(otw: DISPLAY_NFT, ctx: &mut TxContext){ let keys = vector[ utf8(b"name"), utf8(b"description"), utf8(b"image_url"), ]; let values = vector[ utf8(b"{name}"), utf8(b"{description}"), utf8(b"{image_url}"), ]; let publisher = package::claim(otw, ctx); let mut display = display::new_with_fields<MyNFT>(&publisher, keys, values, ctx); display::update_version(&mut display); transfer::public_transfer(publisher, sender(ctx)); transfer::public_transfer(display, sender(ctx)); }
Publisher Authority
我们看一下
sui::package::claim
的源码:public fun claim<OTW: drop>(otw: OTW, ctx: &mut TxContext): Publisher { assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); let type_name = type_name::get_with_original_ids<OTW>(); Publisher { id: object::new(ctx), package: type_name.get_address(), module_name: type_name.get_module(), } }
这个函数通过
OTW
获得了包的一些信息,并存入 Publisher
对象中。Publisher
对象:此类型只能在生成模块的交易中通过使用其一次性见证来创建,因此可以使用它来识别发布类型来源包的地址。
public struct Publisher has key, store { id: sui::object::UID, package: std::ascii::String, module_name: std::ascii::String, }
参考:
Sui Object Display
Sui Object Display 是一个模板引擎,允许通过链上对类型显示进行配置以供生态系统在链下处理数据。它可以将模板中字符串替换为真实数据。
看一下
sui::display::new_with_fields<T:key>
的源码:public fun new_with_fields<T: key>( pub: &Publisher, fields: vector<String>, values: vector<String>, ctx: &mut TxContext, ): Display<T> { let len = fields.length(); assert!(len == values.length(), EVecLengthMismatch); let mut i = 0; let mut display = new<T>(pub, ctx); while (i < len) { display.add_internal(fields[i], values[i]); i = i + 1; }; display }
这个函数通过
Publisher
对象获得来源包的信息,并通过一组键值对保存 NFT 的信息,最后生成了一个 Display
对象以及
sui::display::update_version<T: key>(display: &mut Display<T>
的源码:public entry fun update_version<T: key>(display: &mut Display<T>) { display.version = display.version + 1; event::emit(VersionUpdated<T> { version: display.version, fields: *&display.fields, id: display.id.to_inner(), }) }
这个函数更新了
Display
对象,并记录了版本信息,发射了一个事件。什么是事件?事件是一种让模块向应用程序前端传达区块链上发生的事情的方式,前端可以“监听”某些事件并在事件发生时采取行动。如果没有事件,“链下”组件(智能合约被视为“链上”)很难监控票是否被创建、延期或兑换。它们需要查询每笔交易的结果,并手动检查结果以查看哪些对象发生了变化以及具体如何变化。这非常不容易,而事件可以帮助解决这个问题!
参考:
Display
对象:public struct Display<phantom T: key> has key, store { id: sui::object::UID, ///Contains fields for display. Currently supported fields are: /// name, link, image and description. fields: sui::vec_map::VecMap<std::string::String, std::string::String>, ///Version that can only be updated manually by the Publisher. version: u16, }
参考:
铸造 NFT
随便找了一个图片

交易成功的截图

参考文章
在Sui 区块链上创建、部署和管理 NFT 的完整教程
致谢:
有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
- Author:无常 Anitya
- URL:https://anitya.fun/article/19cb6ca0-c778-80d1-9f85-d20ee67e237b
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts