Sui NFT应用实例:将NFT变成咖啡
近期在台北智慧城市峰会和博览会中,展示了使用NFT购买咖啡的系统。
在2023年3月28–31日举行的台北智慧城市峰会暨博览会中,参与者向大家演示了如何使用NFT兑换一杯香醇的咖啡。此系统由Sui基金会、MomentX以及Suia共同创建,演示了如何使用在Sui网络上的NFT兑换真实的商品或是服务。
展开来说,即参与者会被提示与虚拟AI助理聊天,AI助理询问参与者是否想要一杯现做的咖啡。如果参与者给出肯定的回复,AI助理将会展示一个二维码,扫码后,系统将会为其创建一个NFT,该NFT可在附近的咖啡铺兑换咖啡。
更重要的是,当参与者获得了他们的咖啡,系统将会在Sui网络上传送另外一个交易,将其NFT状态从未使用改成已使用。
Sui Object如何将NFT兑换为咖啡
在Sui上,所有的NFT皆为Object,而实际上Object具有非常强大的功能。在此实例中,Object代码中的一个URL指向一个NFT图片,该URL会根据NFT是否被使用而发生变化。以下代码展示了CoffeeNFT的Object。
struct CoffeeNFT has key, store {
id: UID,
name: String,
description: String,
url: String,
redeemed: bool,
}
以上代码代表了NFT在Sui上的标准实现。其中最值得注意的是,赎回区块与一般Object不同。我们由此做出判断该NFT是否已经被使用,而前面提及的指向NFT照片的URL则会根据此处的状态进行发生变化。
需要注意的是,该对象本可以使用链上图片文件,而不是像其他区块链上的 NFT 一样,包含一个指向图片文件的 URL,这是Sui 支持的一项功能,可增强永久性。此外,该对象代码依赖于Move 的旧版本,在.28 版本发布和引入对象显示标准之前。我们将在本文末尾提供一个最新示例,说明如何编写此代码。
赠送NFT
系统使用 gift_nft
函数,将原始NFT交给参会者。当用户扫描虚拟助手出示的二维码时,就会调用该函数。
public entry fun gift_nft(
global: &mut Global,
to: address,
name: vector<u8>,
description: vector<u8>,
ctx: &mut TxContext,
) {
assert!(tx_context::sender(ctx) == global.admin, ENOT_AUTHORIZED);
let nft = CoffeeNFT {
id: object::new(ctx),
name: utf8(name),
description: utf8(description),
url: global.url_init,
redeemed: false,
};
let coffee_nft_config = CoffeeNFTConfig {
merchant_white_list: vec_set::empty(),
merchant_redeemed: none(),
};
table::add(&mut global.nfts, object::id(&nft), coffee_nft_config);
transfer(nft, to)
}
当系统使用以下代码初始化NFT时 let nft = CoffeeNFT { ... }
会将url设置为 global.url_init
并将其兑换为 错误
。如图所示,该模块还包括一些检查,以确保用户不能兑换可能已不存在的咖啡。 redeem_request
函数如下:
public entry fun redeem_request(
global: &mut Global,
nft_id: ID,
ctx: &mut TxContext,
) {
let merchant = tx_context::sender(ctx);
assert!(vec_set::contains(&global.merchants, &merchant), EMERCHANT_NOT_AUTHORIZED);
let nft_config = table::borrow_mut(&mut global.nfts, nft_id);
assert!(option::is_none(&nft_config.merchant_redeemed), ENFT_ALREADY_REDEEMED);
assert!(!vec_set::contains(&nft_config.merchant_allow_list, &merchant), EMERCHANT_ALREADY_AUTHORIZED);
vec_set::insert(&mut nft_config.merchant_allow_list, merchant);
}
该函数包括三个断言。第一个 EMERCHANT_NOT_AUTHORIZED
断言调用此函数的用户是管理员确定的允许列表中的商家。第二个 ENFT_ALREADY_REDEEMED
断言NFT尚未被赎回。第三个也是最后一个, EMERCHANT_ALREADY_AUTHORIZED
断言NFT尚未获得商家授权。如果符合上述三项条件,则 redeem_request
函数将被成功执行。
可用库存统计
广告有时会在特价商品上注明 "售完即止"。通过这种方式使用NFT,我们可以在链上充分执行限量供应的概念!
最后,如果仍有可用库存,且用户希望赎回NFT,系统会调用 redeem_nft
函数,如下面的代码所示。
public entry fun redeem_confirm(
global: &mut Global,
nft: &mut CoffeeNFT,
merchant: address,
_ctx: &mut TxContext,
) {
// check if the merchant authorized to redeem
let nft_config = table::borrow_mut(&mut global.nfts, object::id(nft));
assert!(vec_set::contains(&nft_config.merchant_white_list, &merchant), EMERCHANT_NOT_AUTHORIZED);
// check stock
let stock = vec_map::get_mut(&mut global.stocks, &merchant);
assert!(*stock > 0, ENOT_ENOUGH_STOCK);
// redeem
// update nft config
nft_config.merchant_redeemed = some(merchant);
// update stock
*stock = *stock - 1;
// update nft
nft.redeemed = true;
nft.url = global.url_redeemed;
}
上述函数将库存量减1,并将NFT的状态更改为 redeemed
并显示新的图像URL。这样,NFT就能让参会者和咖啡摊直观地确认NFT已被兑换。
更新Object Display
如上所述,博览会上使用的程序代码依赖于早期版本的Move ,特别是与对象显示有关的部分。根据当前的对象显示标准编写的程序可以如下所示。
module momentx::coffee_nft {
use sui::tx_context::{sender, TxContext};
use std::string::{utf8, String};
use sui::transfer;
use sui::object::UID;
use sui::package;
use sui::display;
struct CoffeeNFT has key, store {
id: UID,
name: String,
description: String,
img_url: String,
redeemed: bool,
}
struct COFFEE_NFT has drop {}
fun init(otw: COFFEE_NFT, ctx: &mut TxContext) {
let keys = vector[
utf8(b"name"),
utf8(b"description"),
utf8(b"image_url"),
utf8(b"redeemed")
];
let values = vector[
utf8(b"{name}"),
utf8(b"{description}"),
utf8(b"ipfs://{img_url}"),
utf8(b"{redeemed}"),
];
let publisher = package::claim(otw, ctx);
let display = display::new_with_fields<CoffeeNFT>(
&publisher, keys, values, ctx
);
display::update_version(&mut display);
transfer::public_transfer(publisher, sender(ctx));
transfer::public_transfer(display, sender(ctx));
}
}
让NFT发挥实际价值
在上面的例子中,我们为NFT分配了真实世界的消费价值(一杯咖啡),并创建了一种机制来显示NFT是否已被兑换为其分配的价值。这种用法超越了区块链上典型的NFT交易,展示了真实世界的使用案例。此外,我们还在系统中内置了库存或存货的概念,认识到现实世界中物品数量有限的现实。
作为一个更广泛的概念,上述示例说明了Sui上的NFT如何成为具有互动功能的数字门票,其功能远远超出了目前用于电影院、音乐会和飞机等场所的数字门票或通行证。我们的NFT门票具有内置安全性、可控转让性和可编程显示功能。
有关其他Sui/Move 学习资源,请查看以下链接!