* 本文由Starcoin社区原创 作者:WGB 根据Starcoin & Move直播课《轻松掌握Move精髓》整理,点击查看原文,点击查看上篇。
NFT协议的实现
通过Move语言的三大特性和常用的合约module进行配合,可以非常轻松地创建NFT协议,我们可以以渐进式的方式进行NFT协议的编写。
1. NFT协议 V1
在这段代码中实现了NFT的初始化和铸造,在第6行和第8行分别创建自己的NFT和NFT列表用来存放NFT,在第12行初始化NFT的列表以便可以接收和保存NFT,在第16行的铸造NFT函数中先判断是否可以接收NFT,如果不能则通过assert的判断直接退出并返回错误代码,保证NFT不会被不可接收的账户接收。这段代码实现了非常简单的NFT协议,可以通过其他的特性和功能进行完善。
1 address 0x2 {
2 module NFTExample1 {
3 use 0x1::Signer;
4 use 0x1::Vector;
5
6 struct NFT has key, store { name: vector<u8> }
7
8 struct UniqIdList has key, store {
9 data: vector<vector<u8>>
10 }
11
12 public fun initialize(account: &signer) {
13 move_to(account, UniqIdList {data: Vector::empty<vector<u8>>()});
14 }
15
16 public fun new(account: &signer, name: vector<u8>): NFT acquires UniqIdList {
17 let account_address = Signer::address_of(account);
18 let exist = Vector::contains<vector<u8>>(&borrow_global<UniqIdList>(account_address).data, &name);
19 assert(!exist, 1);
20 let id_list = borrow_global_mut<UniqIdList>(account_address);
21 Vector::push_back<vector<u8>>(&mut id_list.data, copy name);
22 NFT { name }
23 }
24 }
25 }
2. NFT协议 V2
通过Strcut可创建自己的NFT,但是如果需要创建其他类型的NFT就需要重新写代码,所以可以使用泛型编程的思想来重新构建NFT代码,在6行和8行定义带有泛型的NFT和NFT列表,在第12行定义初始化vector<u8> 类型的NFT列表,在16行的函数的返回值和内部调用函数时使用的都是带有泛型的struct和函数,现在这个代码可以称作不完全的NFT框架,可以适合小范围测试的多个NFT。
1 address 0x2 {
2 module NFTExample2 {
3 use 0x1::Signer;
4 use 0x1::Vector;
5
6 struct NFT<T: store> has key, store { name: T }
7
8 struct UniqIdList<T: store> has key, store {
9 data: vector<T>
10 }
11
12 public fun initialize(account: &signer) {
13 move_to(account, UniqIdList {data: Vector::empty<vector<u8>>()});
14 }
15
16 public fun new(account: &signer, name: vector<u8>): NFT<vector<u8>> acquires UniqIdList {
17 let account_address = Signer::address_of(account);
18 let exist = Vector::contains<vector<u8>>(&borrow_global<UniqIdList<vector<u8>>> (account_address).data, &name);
19 assert(!exist, 1);
20 let id_list = borrow_global_mut<UniqIdList<vector<u8>>>(account_address);
21 Vector::push_back<vector<u8>>(&mut id_list.data, copy name);
22 NFT { name }
23 }
24 }
25 }
NFT协议V3
在上段代码中的new函数和initialize函数没有使用泛型参数,如果需要完成NFT的框架,就需要对这两个函数进行修改,在以下代码中把new函数和initialize函数也使用泛型进行修饰,使该NFT协议的灵活性大大提升,可以试用于多种不同的NFT测试。
address 0x2 {
module NFTExample3 {
use 0x1::Signer;
use 0x1::Vector;
?
struct NFT<T: store> has key, store { name: T }
?
struct UniqIdList<T: store> has key, store {
data: vector<T>
}
?
public fun initialize<T: store>(account: &signer) {
move_to(account, UniqIdList {data: Vector::empty<T>()});
}
?
public fun new<T: store + copy>(account: &signer, name: T): NFT<T> acquires UniqIdList {
let account_address = Signer::address_of(account);
let exist = Vector::contains<T>(&borrow_global<UniqIdList<T>>(account_address).data, &name);
assert(!exist, 1);
let id_list = borrow_global_mut<UniqIdList<T>>(account_address);
Vector::push_back<T>(&mut id_list.data, copy name);
NFT { name }
}
}
}
4. NFT协议V4
通过对NFT协议的完善,可以在协议中增加Event,用来增加通知的功能可以在钱包中通知NFT的铸造通知。这段代码可以说是比较完整的简单NFT协议,可以再增加移动、销毁等功能,并增加图片显示等,配合前端应用可以制作出精美的NFT。
address 0x2 {
module NFTExample4 {
use 0x1::Vector;
use 0x1::Event;
?
struct NFT<T: store> has key, store { name: T }
?
struct UniqIdList<T: store + drop> has key, store {
data: vector<T>,
nft_events: Event::EventHandle<NFTEvent<T>>,
}
?
struct NFTEvent<T: store + drop> has drop, store {
name: T,
}
?
public fun initialize<T: store + drop>(account: &signer) {
move_to(account, UniqIdList {data: Vector::empty<T>(), nft_events: Event::new_event_handle<NFTEvent<T>>(account)});
}
?
public fun new<T: store + copy + drop>(_account: &signer, account_address:address, name: T): NFT<T> acquires UniqIdList {
let exist = Vector::contains<T>(&borrow_global<UniqIdList<T>>(account_address).data, &name);
assert(!exist, 1);
let id_list = borrow_global_mut<UniqIdList<T>>(account_address);
Vector::push_back<T>(&mut id_list.data, copy name);
let new_name = copy name;
Event::emit_event(&mut id_list.nft_events, NFTEvent { name:new_name });
NFT { name }
}
}
}
问答环节
在Starcoin的社区中有许多的开发者或关注者也在提出各种各样的问题,对于这些问题也有可靠的回答。
- 问:投票时候币只有WithdrawEvent但是没有DepositEvent,这和老师刚讲的钱只能move有什么区别呢? 是move到vote合约的意思吗?
- 答:对,Move的语义就是转移,在投票时所投的Token就是通过Move转移到投票合约中
- 问:move上有类似ERC20这样的标准吗?
- 答:有的,但是不是Move中的,是Starcoin的stdlib中定义的类似ERC20的协议。但是在以太坊上的eth和ERC20的协议的Token的权限有所不同,但是Starcoin上的Token都是一样的。
- 问:Move有自定义异常和异常捕获吗?发现预期的异常得能处理吧
- 答:可以的,比如交易丢掉或者回返在output中
- 问:泛型后面ability是要和定义的一样,还是子集就行
- 答:泛型字段的里的泛型可以和整体的Struct不完全相同,可以大于等于整体
|