Sui Framework

  • Sui Framework 什么是 Sui Framework, 大家第一次看到 Framework的时候会觉得奇怪,不知道是什么, 简单来说就是Sui Move的标准库,官方已经封装好了一些常用的库供大家使用
  • Sui Framework 是经过了长期打磨,和安全验证的代码,阅读Framework不仅仅能掌握常用的工具库, 而且能更好的学习Sui Move,Framework每一个包和库都值得大家精心阅读和学习

move-stdlib

move stdlib 是来自Move上游的核心标准库,可以理解成最核心的标准库,基本上是需要大家都掌握的

总览,可以这样说 就是最好把这个系列的都完全掌握

模块名大概用途需要掌握程度
address.move地址长度了解
ascii.moveascii编码的字符串完全掌握
bcs.move把数据序列化成二进制掌握
bit_vector.movebit 位标记的数组掌握
debug.move调试代码,打印输出完全掌握
fixed_point32.move浮点数掌握
hash.movehash函数掌握
option.move可选值完全掌握
type_name.move获取结构的类型完全掌握
unit_test.move单元测试生成测试signers了解
vector.move数组完全掌握

address.move

基本上没什么用处
module std::address {
    public fun length(): u64 {
        32
    }
}

ascii.move

ascii 编码规则的字符串,说白了就是只有a-z A-Z 0-9这些编码的字符串,只支持早期的英文字符

// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// The `ASCII` module defines basic string and char newtypes in Move that verify
/// that characters are valid ASCII, and that strings consist of only valid ASCII characters.
module std::ascii {
    use std::vector;
    use std::option::{Self, Option};

    /// An invalid ASCII character was encountered when creating an ASCII string.
    const EINVALID_ASCII_CHARACTER: u64 = 0x10000;


   struct String has copy, drop, store {
       bytes: vector<u8>,
   }

   /// An ASCII character.
   struct Char has copy, drop, store {
       byte: u8,
   }


    /// Convert a `byte` into a `Char` that is checked to make sure it is valid ASCII.
    public fun char(byte: u8): Char {
        assert!(is_valid_char(byte), EINVALID_ASCII_CHARACTER);
        Char { byte }
    }


    /// Convert a vector of bytes `bytes` into an `String`. Aborts if
    /// `bytes` contains non-ASCII characters.
    public fun string(bytes: vector<u8>): String {
       let x = try_string(bytes);
       assert!(
            option::is_some(&x),
            EINVALID_ASCII_CHARACTER
       );
       option::destroy_some(x)
    }
 
    
    public fun try_string(bytes: vector<u8>): Option<String> {
       let len = vector::length(&bytes);
       let i = 0;
       while ({
           spec {
               invariant i <= len;
               invariant forall j in 0..i: is_valid_char(bytes[j]);
           };
           i < len
       }) {
           let possible_byte = *vector::borrow(&bytes, i);
           if (!is_valid_char(possible_byte)) return option::none();
           i = i + 1;
       };
       spec {
           assert i == len;
           assert forall j in 0..len: is_valid_char(bytes[j]);
       };
       option::some(String { bytes })
    }

    /// Returns `true` if all characters in `string` are printable characters
    /// Returns `false` otherwise. Not all `String`s are printable strings.
    public fun all_characters_printable(string: &String): bool {
       let len = vector::length(&string.bytes);
       let i = 0;
       while ({
           spec {
               invariant i <= len;
               invariant forall j in 0..i: is_printable_char(string.bytes[j]);
           };
           i < len
       }) {
           let byte = *vector::borrow(&string.bytes, i);
           if (!is_printable_char(byte)) return false;
           i = i + 1;
       };
       spec {
           assert i == len;
           assert forall j in 0..len: is_printable_char(string.bytes[j]);
       };
       true
    }
 

    public fun push_char(string: &mut String, char: Char) {
        vector::push_back(&mut string.bytes, char.byte);
    }


    public fun pop_char(string: &mut String): Char {
        Char { byte: vector::pop_back(&mut string.bytes) }
    }
 

    public fun length(string: &String): u64 {
        vector::length(as_bytes(string))
    }

    /// Get the inner bytes of the `string` as a reference
    public fun as_bytes(string: &String): &vector<u8> {
       &string.bytes
    }

    /// Unpack the `string` to get its backing bytes
    public fun into_bytes(string: String): vector<u8> {
       let String { bytes } = string;
       bytes
    }

    /// Unpack the `char` into its underlying byte.
    public fun byte(char: Char): u8 {
       let Char { byte } = char;
       byte
    }

    /// Returns `true` if `b` is a valid ASCII character. Returns `false` otherwise.
    public fun is_valid_char(b: u8): bool {
       b <= 0x7F
    }

    /// Returns `true` if `byte` is an printable ASCII character. Returns `false` otherwise.
    public fun is_printable_char(byte: u8): bool {
       byte >= 0x20 && // Disallow metacharacters
       byte <= 0x7E // Don't allow DEL metacharacter
    }
}


bcs

bcs 大家可能比较模糊,有的人不太了解是什么东西,我举一个例子,就是你定义好一个json的数据结构,然后把它转成json字符串 字符串这个类型就是一个通用的数据类型 bsc存在的意义就是把Move的数据结构转成通用的序列化好的一种二进制 好处就是单一类型了,通用性很强,能在不同的编程语言之间传递,反序列化回来了也具有唯一的数据对应

module std::bcs {
    /// Return the binary representation of `v` in BCS (Binary Canonical Serialization) format
    native public fun to_bytes<MoveValue>(v: &MoveValue): vector<u8>;
}

bit_vector.move

数组的一种结构, [bool,length] [ture,false,ture],就是会标注index位置有没有被使用

module std::bit_vector {
    struct BitVector has copy, drop, store {
        length: u64,
        bit_field: vector<bool>,
    }
}

debug.move

提供了在开发节点,人工打印调试信息

module std::debug {
    native public fun print<T>(x: &T);

    native public fun print_stack_trace();
}

hash.move

提供了两个常用的hash函数

module std::hash {
    native public fun sha2_256(data: vector<u8>): vector<u8>;
    native public fun sha3_256(data: vector<u8>): vector<u8>;
}

option.move

一种容器类,表达的是,一个东西能为空,而且用这种类型会约束你强制处理为空的情况 简单来说一个NFT的图片,允许为空,或者必须填写

// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// This module defines the Option type and its methods to represent and handle an optional value.
module std::option {
    use std::vector;
    
    struct Option<Element> has copy, drop, store {
        vec: vector<Element>
    }
    
    /// Return an empty `Option`
    public fun none<Element>(): Option<Element> {
        Option { vec: vector::empty() }
    }

    /// Return an `Option` containing `e`
    public fun some<Element>(e: Element): Option<Element> {
        Option { vec: vector::singleton(e) }
    }
    
    /// Return true if `t` does not hold a value
    public fun is_none<Element>(t: &Option<Element>): bool {
        vector::is_empty(&t.vec)
    }

    /// Return true if `t` holds a value
    public fun is_some<Element>(t: &Option<Element>): bool {
        !vector::is_empty(&t.vec)
    }
    
}

string.move

  • 字符串的UTF-8版本
  • 提供了一些ascii转换的方法和定义
module std::string {
    use std::ascii;
    use std::vector;
    use std::option::{Self, Option};

    /// An invalid UTF8 encoding.
    const EINVALID_UTF8: u64 = 1;

    /// Index out of range.
    const EINVALID_INDEX: u64 = 2;

    /// A `String` holds a sequence of bytes which is guaranteed to be in utf8 format.
    struct String has copy, drop, store {
        bytes: vector<u8>,
    }

    /// Creates a new string from a sequence of bytes. Aborts if the bytes do not represent valid utf8.
    public fun utf8(bytes: vector<u8>): String {
        assert!(internal_check_utf8(&bytes), EINVALID_UTF8);
        String{bytes}
    }

    /// Convert an ASCII string to a UTF8 string
    public fun from_ascii(s: ascii::String): String {
        String { bytes: ascii::into_bytes(s) }
    }

    /// Convert an UTF8 string to an ASCII string.
    /// Aborts if `s` is not valid ASCII
    public fun to_ascii(s: String): ascii::String {
        let String { bytes } = s;
        ascii::string(bytes)
    }
}

type_name.move

// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Functionality for converting Move types into values. Use with care!
module std::type_name {
    use std::ascii::{Self, String};
    use std::address;
    use std::vector;

    /// ASCII Character code for the `:` (colon) symbol.
    const ASCII_COLON: u8 = 58;

    struct TypeName has copy, drop, store {
        name: String
    }

    /// Return a value representation of the type `T`.
    public native fun get<T>(): TypeName;
 

    /// Get the String representation of `self`
    public fun borrow_string(self: &TypeName): &String {
        &self.name
    }

    /// Get Address string (Base16 encoded), first part of the TypeName.
    public fun get_address(self: &TypeName): String {
        // Base16 (string) representation of an address has 2 symbols per byte.
        let len = address::length() * 2;
        let str_bytes = ascii::as_bytes(&self.name);
        let addr_bytes = vector[];
        let i = 0;

        // Read `len` bytes from the type name and push them to addr_bytes.
        while (i < len) {
            vector::push_back(
                &mut addr_bytes,
                *vector::borrow(str_bytes, i)
            );
            i = i + 1;
        };

        ascii::string(addr_bytes)
    }

    /// Get name of the module.
    public fun get_module(self: &TypeName): String {
        // Starts after address and a double colon: `<addr as HEX>::`
        let i = address::length() * 2 + 2;
        let str_bytes = ascii::as_bytes(&self.name);
        let module_name = vector[];

        loop {
            let char = vector::borrow(str_bytes, i);
            if (char != &ASCII_COLON) {
                vector::push_back(&mut module_name, *char);
                i = i + 1;
            } else {
                break
            }
        };

        ascii::string(module_name)
    }

    /// Convert `self` into its inner String
    public fun into_string(self: TypeName): String {
        self.name
    }
}

sui-framework

sui 独有的标准库,和其他链的不一样

模块名大概用途需要掌握程度
address.move提供了一些地址和其他类型的转换掌握
bag.movemap结构,值可以类型不一样完全掌握
bcs.move在核心标准库上做了补充完全掌握
borrow.move掌握
clock.move获取链上时间完全掌握
coin.move类似ERC20标准完全掌握
display.moveNFT展现标准完全掌握
dynamic_field.move动态属性掌握
dynamic_object_field.move动态对象属性掌握
event.move打印日志完全掌握
hex.movehex编码完全掌握
linked_table.movetable的一种掌握
math.move常用数学工具函数完全掌握
object.move对象工具库完全掌握
object_bag.movemap结构,值是对象类型可以不一样完全掌握
object_table.movemap结构,值是对象类型必须一样完全掌握
package.move包管理和升级掌握
pay.move对Coin的快捷处理函数,完全掌握
prover.move用不上自行了解了解
sui.moveSUI 的定义了解
table.movemap结构,值类型必须一样完全掌握
table_vec.move用table实现的数组掌握
transfer.move转移对象所有权,完全掌握
tx_context.move取得当前交易钱包信息的上下文完全掌握
types.move类型工具,目前只有判断OWT类型完全掌握
vec_map.move底层是vec数组的map掌握
vec_set.move底层是vec数组的Set掌握
versioned.move版本管理的工具类掌握
kiosk 目录NFT交易的基础工具类完全掌握
crypto 目录高阶的加密算法了解
test.move测试相关工具库完全掌握

borrow.move

  • 一个简单的库,支持烫手山芋的借用机制。
  • 在可编程事务中,可以在内部借用值
  • 一个事务,使用它并在最后放回。“Borrow”是个烫手山芋
  • 确保返回的对象没有被替换为另一个对象。

如何理解呢? 就是用确定一个对象在不同的合约之间传递到还回来的时候没有被改变id

clock.move

  • 提供了一个获取链上时间的方法,Sui上链上的时间在 0x6对象实例,只有这一个唯一的对象实例
module sui::clock {
    use sui::object::{Self, UID};

    struct Clock has key {
        id: UID,
        timestamp_ms: u64,
    }


    public fun timestamp_ms(clock: &Clock): u64 {
        clock.timestamp_ms
    }
}

hex.move

base16编码 就是把二进制的数据转成16进制表示让肉眼方便阅读和简短,比如 address

linked_table.move

链表数据结构 类似于sui::table,但值是链接在一起的,允许有序插入和删除

math.move

  • 最大值,最小值,平均值,差值,指数,开平方

集合的类型如何选择?

  • bag 和 table的选择

如果值类型一样就选table,如果值类型不一样就选bas

  • object_table 和 table的选择

如果值确定是 object就选 object_table ,否则选 table, table范围更广泛

  • object_bag 和 bag

如果值确定是 object就选 object_bag ,否则选 table, bag范围更广泛

  • vec相关的和 table 和bag

大小已知而且小于1000用 vec ,大小未知 数据比较大 用 table

vec相关的集合

  • 使用vec相关的集合都要非常的小心, 不能存储大量的数据, 理论上必须小于1000,而且最好不要提供让用户来自行添加数据,也就是不确定长度的,很容易产生gas不足的安全攻击