The smart contract programming language used by Starcoin is Move, which is specially made for digital assets. Digital assets started with BTC, which has gone through a long development process, and now there are many public chains from Ether, Wavefield and so on. Starcoin is for digital assets, using the characteristics of Move can make NFT and other digital assets in the public chain of Starcoin. The three main features of Move language, Struct, Ability and Generic, can help NFT to be deployed in Starcoin, which makes it easy to customize the type of NFT, define the uniqueness of NFT and write a common NFT code.
1.Struct
Struct is similar to structures in other programming languages in that it can define fields in the form of key-values and store Structs are similar to structures in other programming languages in that they can define fields and store their contents in key-value form. This allows us to easily create our own NFTs, Tokens, and other data types with Struct.
(1) Struct Demonstration
Struct can be demonstrated with a piece of code that creates two Structs: Empty and MyStruct, Empty is empty, MyStruct contains several basic types and several custom Struct types: STC, Empty.
1 address 0x2 {
2 module StructExample1 {
3 use 0x1::STC::STC;
4
5 struct Empty{}
6
7 struct MyStruct {
8 address_field: address,
9 bool_field: bool,
10 u64_field: u64,
11 vec_field: vector<u8>,
12 inner_field: Empty,
13 coins: STC,
14 }
15 }
16 }
(2) Struct with Function
In the case of custom types, most of the use of the situation is to do the unit of storage, it is necessary to use effective means to operate Struct, you can use Function in Move to operate on Struct, for example, after creating a Struct of NFT, through the function to build, transfer, destroy NFT and so on. Code can be used to show how to manipulate the creation and destruction of Struct. In this code two Strcut have their own creation and destruction functions, for the creation and destruction of custom types in Struct need to follow the design of custom types to operate.
1 address 0x2 {
2 module StructExample2 {
3 use 0x1::STC::STC;
4 use 0x1::Vector;
5 use 0x1::Token::{Self, Token};
6
7 struct Empty{}
8
9 struct MyStruct {
10 address_field: address,
11 bool_field: bool,
12 u64_field: u64,
13 vec_field: vector<u8>,
14 inner_field: Empty,
15 coins: Token<STC>,
16 }
17
18 fun new_empty() : Empty {
19 Empty {}
20 }
21
22 fun destroy_empty(empty: Empty) {
23 let Empty{} = empty;
24 }
25
26 public fun new_struct() : MyStruct {
27 MyStruct {
28 address_field: 0x1,
29 bool_field: true,
30 u64_field: 1000000,
31 vec_field: Vector::empty(),
32 inner_field: Self::new_empty(),
33 coins: Token::zero<STC>(),
34 }
35 }
36
37 public fun destroy_struct(my: MyStruct) {
38 let MyStruct {
39 address_field: _,
40 bool_field: _,
41 u64_field: _,
42 vec_field: _,
43 inner_field: empty,
44 coins: coins,
45 } = my;
46
47 Self::destroy_empty(empty);
48 Token::destroy_zero(coins);
49 }
50 }
51 }
(3) The relationship between Struct, Function and Module
Struct and Function complement each other, if one is missing, the existence of the other one is meaningless, Module is like a whole factory that can create, modify and destroy internal Struct, Struct is like raw material, Function is a tool to manipulate raw material, you can use the tool (function) in the factory (Module) to manipulate the You can use tools (function) in the factory (Module) to manipulate the raw material (Struct) and finally generate a usable instance.
2. Ability
The Move language implements a syntax similar to rust, and is a reliable and strongly typed blockchain programming language. The Ability feature can be used to control the permissions of different types of functions with detailed control over the permissions of the assets.
●Copy :indicates whether the value can be copied or not
●Drop :indicates whether the value can be dropped at the end of the scope
●Key :indicates whether the value can be accessed as a key to the global state
●Store :Indicates whether the value can be stored to the global state
For example, if you define a type of NFT, if you do not give it the ability to copy, then you can ensure that NFT cannot be copied at will, which improves security. The same concept can also be understood with the concept of money, money in the wallet if you can just copy, discard, it will make the money becomes worthless, so by giving the ability to custom types, you can prevent a certain degree of insecurity, of course, the most important factor affecting security is the producer of the program.
(1) Demonstration of Copy
Although there are some examples of Structs that should not be given the ability to Copy, there are still some Structs that need the ability to Copy, for example, an application that needs to save address book information requires multiple copies of the correspondent’s information for distribution. The difference in functionality between Structs with Copy capability and Structs without Copy capability can be seen visually through the code.
Define two Structs, one of which is a CopyStruct with Copy capability
When destroying the two created Structs, the MoveStruct is destroyed because it does not have the ability to copy, while the CopyStruct still exists after destroying the duplicates.
1 address 0x2 {
2 module AbilityExample2 {
3 use 0x1::Debug;
4
5 struct CopyStruct has copy {value:u64}
6 struct MoveStruct {value:u64}
7
8 public fun new_copy_struct() : CopyStruct {
9 CopyStruct {value:100}
10 }
11
12 public fun destroy_copy_struct(copy_struct: CopyStruct) {
13 let CopyStruct{value:_} = copy_struct;
14 }
15
16 public fun new_move_struct() : MoveStruct {
17 MoveStruct {value:200}
18 }
19
20 public fun destroy_move_struct(move_struct: MoveStruct) {
21 let MoveStruct {value:_} = move_struct;
22 }
23
24 public fun test() {
25 let copy_struct = Self::new_copy_struct();
26 let move_struct = Self::new_move_struct();
27 Self::destroy_copy_struct(copy copy_struct);
28 //Self::destroy_move_struct(copy move_struct);
29 Self::destroy_move_struct(move_struct);
30 Debug::print(©_struct.value);
31 //Debug::print(&move_struct.value);
32 Self::destroy_copy_struct(copy_struct);
33 }
34 }
35 }
(2) Demonstration of Drop
The Ability in Move provides Drop so that custom types can also be destroyed by “_” when destroyed. This capability can be clearly understood through the code.
When destroying a MyStruct, the internal Empty is already given the ability to be dropped.
1 address 0x2 {
2 module AbilityExample1 {
3 use 0x1::STC::STC;
4 use 0x1::Vector;
5 use 0x1::Token::{Self, Token};
6
7 struct Empty has drop {}
8
9 struct MyStruct {
10 address_field: address,
11 bool_field: bool,
12 u64_field: u64,
13 vec_field: vector<u8>,
14 inner_field: Empty,
15 coins: Token<STC>,
16 }
17
18 fun new_empty() : Empty {
19 Empty {}
20 }
21
22 fun destroy_empty(empty: Empty) {
23 let Empty{} = empty;
24 }
25
26 public fun new_struct() : MyStruct {
27 MyStruct {
28 address_field: 0x1,
29 bool_field: true,
30 u64_field: 1000000,
31 vec_field: Vector::empty(),
32 inner_field: Self::new_empty(),
33 coins: Token::zero<STC>(),
34 }
35 }
36
37 public fun destroy_struct(my: MyStruct) {
38 let MyStruct {
39 address_field: _,
40 bool_field: _,
41 u64_field: _,
42 vec_field: _,
43 inner_field: empty,
44 coins: coins,
45 } = my;
46
47 Self::destroy_empty(empty);
48 Token::destroy_zero(coins);
49 }
50
51 public fun destroy_struct_v2(my: MyStruct) {
52 let MyStruct {
53 address_field: _,
54 bool_field: _,
55 u64_field: _,
56 vec_field: _,
57 inner_field: _,
58 coins: coins,
59 } = my;
60
61 Token::destroy_zero(coins);
62 }
63 }
64 }
3. Generic
When writing code in other contract languages, it is necessary to write a lot of similar code for different NFT types that may perform the same processing, doing a lot of repetitive work, and for example, to create a common framework for NFT, it is necessary to deal with different types, and a lot of repetition of similar code. Generic similar to other programming languages in the generic programming, can be achieved through a single function written, applied to a variety of types of functions, can significantly reduce the repetition of code, improve coding efficiency, while reducing the code logic clear easier to check the emergence of errors to avoid losses after the line.
(1) Demonstration of Struct generic type
Creating generic types through Struct allows a Struct to support a variety of internal types at the same time, so that there is no need to repeat Struct when using u8, u64, and other types.
For example, to define a Box with variables of type u64 inside.
struct Box{
value:u64
}
If you want to define another Box with a variable of type u8:
struct Box{
value:u8
}
**Just define a Box with a Struct generic:**
>just pass in the generic type to complete Box<u8> and Box<u64>
```move
struct Box<T>{
value:T
}
(2) Struct Generics + Ability
If you use a generic type, you can also use Ability so that you don’t lose security after using a generic type.
This code shows the definition of a Box using a generic type. The generic type can be passed in to generate the actual Struct, and the type passed in can be restricted with Ability to precisely manipulate each data type, greatly improving flexibility, which is an important feature of the Move language for the new era of blockchain NFT. Code example:
struct Box<T1:copy + drop ,T2:copy + drop + store> has copy,drop{
contents_1: T1,
contents_2: T2,
}
(3) Struct generic + Ability + Function
Through the combination of Struct, generic and Ability, and then through the Function can be achieved through the combination of these two features, write NFT generic framework, you can achieve the non-copyable, custom arbitrary type of NFT casting transaction destruction and other functions.
In this code through the function to create Box when you need to specify the generic type, you can specify directly in the function, you can also pass the generic type by passing parameters, there are multiple generic parameters can also be passed to a single generic type, the remainder of the function specified. Through the organic combination of Struct generic + Ability + Function, the contract of Move language can have extremely powerful flexibility and security, and with these functions, it can be easily transplanted to other blockchain projects to achieve fast and safe online. Code example:
1 address 0x2{
2 module Box2{
3
4 struct Box<T1:copy + drop, T2:copy + drop + store> has copy,drop {
5 contents_1: T1,
6 contents_2: T2,
7 }
8
9
10 fun create_box<T1:copy + drop, T2:copy + drop + store>(val_1:T1, val_2:T2):Box<T1, T2> {
11 Box {contents_1:val_1, contents_2:val_2}
12 }
13
14 public(script) fun create_bool_box<T2:copy + drop + store>(val_2:T2) {
15 let _ = Self::create_box<bool, T2>(false, val_2);
16 }
17
18 public(script) fun create_bool_u64_box() {
19 let _ = Self::create_box<bool, u64>(false, 100);
20 }
21 }
22 }
4. helloWorld code example using Move language features
This code prints the hello world string, but there is no String type in Move, so line 15 outputs the characters in hexadecimal of hello world. The three features of Move used in this code are.
●Lines 5 and 9 define custom types of AnyWordEvent and EventHolder via Strcut
●The two custom types are modified by Ability on lines 5 and 9
●Calling the borrow_global_mut function on line 16 by passing in the EventHolder type using Generic
1 address 0x2{
2 module HelloWorld{
3 use 0x1::Signer;
4 use 0x1::Event;
5 struct AnyWordEvent has drop,store {
6 words:vector<u8>,
7 }
8
9 struct EventHolder has key{
10 any_word_events:Event::EventHandle<AnyWordEvent>,
11 }
12
13 public (script) fun hello_world(account: &signer) acquires EventHolder {
14 let addr = Signer::address_of(account);
15 let hello_world = x"68656c6c6f20776f726c64"; // hello world
16 let holder = borrow_global_mut<EventHolder>(addr);
17 Event::emit_event<AnyWordEvent>(&mut holder.any_word_events, AnyWordEvent{words:hello_world});
18 }
19 }
20 }