sui-move基础:letsmove-task2

  • Avem
  • 更新于 1天前
  • 阅读 136

任务要求完成两个Coin合约的上链部署上链网络:mainnet需求完成Coin相关知识的学习完成MyCoin的学习并部署主网完成FaucetCoin的学习并部署主网提交MyCoin和FaucetCoin合约发布packageid

任务要求

  • 完成两个Coin合约的上链部署
  • 上链网络: mainnet

需求

  • 完成 Coin相关知识的学习

  • 完成 My Coin 的学习并部署主网

  • 完成 Faucet Coin 的学习并部署主网

  • 提交 My CoinFaucet Coin 合约发布 package id

  • 发送 My Coin  给地址 0x7b8e0864967427679b4e129f79dc332a885c6087ec9e187b53451a9006ee15f2

  • Faucet Coin 需要至少用两个地址mint

写在前面(这里都是本人踩过的坑)

task2任务需要在mainnet上进行操作,相比于在testnet上,部署package需要支付一定的gas,前提条件是部署合约的账户地址必须有sui,才可以支付gas,成功部署。

如果账户地址里没有足够的币,就会部署失败

如果发现Cannot find gas coin for signer address的error message ,可以执行 sui keytool import --alias name " " secp256k1的命令去用有gas的账户的助记词导入账户地址到本机,再执行 sui client switch --address ADDRESS切换地址,支持别名切换,如果你想看本机存储的所有地址可以执行 sui keytool list命令。

如果出现无法正常连接sui仓库的问题,执行 sui client publish --skip-fetch-latest-git-deps 命令,用本地之前下好的sui官方仓库完成package的部署。如果sui仓库的代码下载缓慢或者超时,可以试试将项目中的move.toml中的[dependencies]的Sui的git地址从github修改为gitee. ![[无法连接sui仓库.png]]

好了,以上就是我完成task2期间遇到的bug和踩的一些坑,希望对您有所帮助,接下来我们一起来看代码吧。

代码讲解

My coin的代码

module my_coin::prts;  
use sui::coin::create_currency;  
use std::option::{none, some};  
use sui::transfer::{public_freeze_object, public_transfer};  
use sui::url::Url;  
use sui::url;  

public struct PRTS has drop{}  

fun init(prts:PRTS, ctx: &mut TxContext) {  

    let no = none<Url>();           
    let url = url::new_unsafe_from_bytes(b"https://patchwiki.biligame.com/images/arknights/thumb/0/0f/t5ygg18f380pcqvwt22rrplk11pv734.png/180px-%E9%BE%99%E9%97%A8%E5%B8%81.png");  
    let yes = some<Url>(url);       
    let(treasury,coin_metadata) =  
        create_currency(prts,8,b"PRTS",b"Longmen_Coin",b"Currency issued by Longmen, with wide-ranging uses.",yes,ctx);  

    public_freeze_object(coin_metadata);   

    public_transfer(treasury,ctx.sender());

}  

公共结构体PRTS

  1. 首先我们来看一下公共结构体PRTS,就是我们的主角,我自己定义的加密货币。

public struct PRTS has drop{}

代码定义了一个公共结构体PRTS,has drop()赋予了它可以丢弃或者忽略自己的实例的能力。

那什么是能力呢?根据move book文档Move 基础篇中的能力:介绍,能力是一种允许类型具有特定行为的方式,它是声明结构体的一部分,赋予结构体实例允许的行为。

能力分为四种,分别为copy,drop,key,store,分别代表结构体实例可以被复制可以被丢弃忽略可以被用做用作存储中的键,has store的结构体可以被拥有key能力的结构体包裹(变成它的一个字段),除引用外,所有内置类型都具有copydropstore能力。引用具有copydrop能力。没有能力的结构体不能被丢弃复制存储,所以就得在程序中一直传递,像一个烫手山芋一样,所以我们称这种结构体为 Hot Potato

为什么sui需要能力呢,因为 Move 旨在表达数字资产和资源,不能被随意复制,随意丢弃,我们要确保代码的安全性和资源的正确使用。

所以has drop 属性表示 PRTS 实例可以被销毁(当不再需要时)。

init函数

接下来我们来看看init函数吧

fun init(prts:PRTS, ctx: &mut TxContext) {  

    let no = none<Url>();           
    let url = url::new_unsafe_from_bytes(b"https://patchwiki.biligame.com/images/arknights/thumb/0/0f/t5ygg18f380pcqvwt22rrplk11pv734.png/180px-%E9%BE%99%E9%97%A8%E5%B8%81.png");  
    let yes = some<Url>(url);       
    let(treasury,coin_metadata) =  
        create_currency(prts,8,b"PRTS",b"Longmen_Coin",b"Currency issued by Longmen, with wide-ranging uses.",yes,ctx);  

    public_freeze_object(coin_metadata);   

    public_transfer(treasury,ctx.sender()); 
}  

init函数用来对模块进行初始化的操作,所有模块的init函数都会在发布过程中被调用,prts模块的init函数的作用是初始化自定义加密货币并进行铸造。init函数保证在模块发布时只调用一次。因此,它是放置初始化模块对象、设置环境和配置的代码的好地方。详细的可以去move book中的模块初始化部分自行了解。

fun init(prts:PRTS, ctx: &mut TxContext)

init函数接受一个或两个参数:一次性见证(One Time Witness,简称 OTW)(可选)和 交易上下文(TxContext)。TxContext始终是最后一个参数。显而易见参数 prts 就是一个OTW, ctx是可变型的TxContext

那什么是见证者呢,见证者是一种资源或者类型,具有某种能力,拥有见证者,你就可以具备执行某些操作的权限,说白了就是参数你传了见证者实例,你就可以执行函数。特定函数需要特定的见证者,才可以证明你就具有操作函数的权限。在代码中,prts就是一次性见证者的实例,他代表的就是我们的PRTS货币类型,一次性见证者意味着见证者实例只能用一次,用完就得销毁,它保证了一个prts实例初始化一次PRTS类型货币以及init函数中的其他操作。

我们再来谈谈事务上下文TxContext,在sui官方库中 module sui::tx_context;

public struct TxContext has drop {  
    /// The address of the user that signed the current transaction  
    sender: address,  
    /// Hash of the current transaction  
    tx_hash: vector<u8>,  
    /// The current epoch number  
    epoch: u64,  
    /// Timestamp that the epoch started at  
    epoch_timestamp_ms: u64,  
    /// Counter recording the number of fresh id's created while executing  
    /// this transaction. Always 0 at the start of a transaction    ids_created: u64,  
}

它拥有四个参数,sender为最近一笔交易的发起人地址,tx_hash为交易的hash值,epoch 在区块链中通常是指一个固定长度的时间周期,每个 epoch 结束时,系统会进行某些重要的状态更新、奖励结算、节点轮换等操作。它是区块链中周期性变化的管理机制。epoch_timestamp_ms是epoch的时间戳。官方为这四个参数写了对应的getter方法,来获取交易的信息,有兴趣的小伙伴可以自行去看move book中事务上下文的文档。

设置url

设置图片的url我们就不多赘述了,感兴趣的可以看下module sui::url;中的new_unsafe_from_bytes方法,将图片链接转换成url对象实例。

let no = none<Url>();           
    let url = url::new_unsafe_from_bytes(b"https://patchwiki.biligame.com/images/arknights/thumb/0/0f/t5ygg18f380pcqvwt22rrplk11pv734.png/180px-%E9%BE%99%E9%97%A8%E5%B8%81.png");  
    let yes = some<Url>(url);       

冻结对象

public_freeze_object(coin_metadata); 

将CoinMetadata中的coin_metadata传入public_freeze_object,冻结的目的是确保对象的状态是固定的,通常用于确保我们的PRTS代币(如代币或其他重要的区块链数据)在创建后不会再被更改或销毁。

以下是sui官方库的代码

public fun public_freeze_object<T: key + store>(obj: T) {  
    freeze_object_impl(obj)  
}

只有拥有key和store能力的结构体实例才可以传参,key表示对象是有唯一标识符的(通过 UID),可以在区块链上被引用和查询。。

转移货币的所有权

public_transfer(treasury,ctx.sender());

public_transfer方法的作用是传入treasury,treasury里面存的是管理代币的资金池和操作权限,ctx.sender()是交易的发起者,相当于recipient,货币的接收者。

public struct RMB has drop{}  

fun init(rmb:RMB, ctx: &mut TxContext) {  

    let no = none<Url>();           
    let url = url::new_unsafe_from_bytes(b"https://patchwiki.biligame.com/images/arknights/thumb/0/0f/t5ygg18f380pcqvwt22rrplk11pv734.png/180px-%E9%BE%99%E9%97%A8%E5%B8%81.png"); 
    let yes = some<Url>(url);     
    let(treasury,coin_metadata) =  
        create_currency(rmb,8,b"RMB",b"RMB",b"this is renmingbi.",no,ctx);  

    public_freeze_object(coin_metadata); 

    public_share_object(treasury); 
}  

共享货币的权限

public_share_object(treasury);

public_share_object方法的作用就是将铸币的权限共享给每一个人,每一个人都调用mint and transfer 铸币和发币

create_currency方法

重点又来了,module sui::coin;中的create_currency方法,用于创建自定义的货币(或代币),通常用于区块链应用中发行数字资产或管理资源。

let(treasury,coin_metadata) =  
        create_currency(prts,8,b"PRTS",b"Longmen_Coin",b"Currency issued by Longmen, with wide-ranging uses.",yes,ctx);  

在这里,create_currency方法是在 prts(一个 PRTS 类型的资源)上下文中创建一种新的代币或货币。

sui官方库的代码如下

public fun create_currency<T: drop>(  
    witness: T,  
    decimals: u8,  
    symbol: vector<u8>,  
    name: vector<u8>,  
    description: vector<u8>,  
    icon_url: Option<Url>,  
    ctx: &mut TxContext,  
): (TreasuryCap<T>, CoinMetadata<T>) {  
    // Make sure there's only one instance of the type T  
    assert!(sui::types::is_one_time_witness(&witness), EBadWitness);  

    (        TreasuryCap {  
            id: object::new(ctx),  
            total_supply: balance::create_supply(witness),  
        },        CoinMetadata {  
            id: object::new(ctx),  
            decimals,  
            name: string::utf8(name),  
            symbol: ascii::string(symbol),  
            description: string::utf8(description),  
            icon_url,  
        },    )}

方法需要的传参有witness(见证者实例),decimals(小数点精度),symbol(货币符号简称), name(货币全称),description(货币描述),icon_url(货币图片),ctx(事务上下文,表示当前区块链交易的上下文信息),返回的参数为TreasuryCap<T>实例,CoinMetadata<T>实例。

TreasuryCap<T>的作用是管理一种代币的总供应量,并为持有者提供与代币铸造和销毁相关的权限。这个结构体是用来管理代币的资金池和操作权限的。字段有id,类型是UID(唯一标识符),用于区分不同的 TreasuryCap 实例, CoinMetadata<T>的作用是返回关于货币的详细元数据,如符号、名称、描述和图标。同时assert!(sui::types::is_one_time_witness(&witness), EBadWitness); 还会判断见证者是否为一次性见证者。

最后我们再去mint and transfer 函数去铸币交易了,可以在我们的命令行里去调用,语法如下

sui client call --package 0x2<sui官方库的地址固定为0x2> --module coin<调用的模块名> --function mint_and_transfer <调用的函数方法名> --type-args <packageid>::prts::PRTS <函数所需的泛型参数> --args <Treasury> 10000000000 <address> <函数所需的传参>

重点:见证者,事务上下午,能力,对象所有权

  • 原创
  • 学分: 6
  • 分类: Sui
  • 标签: Move 
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Avem
Avem
一个学习智能合约的小白