任务要求完成两个Coin合约的上链部署上链网络:mainnet需求完成Coin相关知识的学习完成MyCoin的学习并部署主网完成FaucetCoin的学习并部署主网提交MyCoin和FaucetCoin合约发布packageid
完成 Coin相关知识的学习
完成 My Coin
的学习并部署主网
完成 Faucet Coin
的学习并部署主网
提交 My Coin
和 Faucet 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());
}
public struct PRTS has drop{}
代码定义了一个公共结构体PRTS,has drop()赋予了它可以丢弃或者忽略自己的实例的能力。
那什么是能力呢?根据move book文档Move 基础篇中的能力:介绍,能力是一种允许类型具有特定行为的方式,它是声明结构体的一部分,赋予结构体实例允许的行为。
能力分为四种,分别为copy,drop,key,store,分别代表结构体实例可以被复制,可以被丢弃忽略,可以被用做用作存储中的键,has store的结构体可以被拥有key能力的结构体包裹(变成它的一个字段),除引用外,所有内置类型都具有copy
、drop
和store
能力。引用具有copy
和drop
能力。没有能力的结构体不能被丢弃复制存储,所以就得在程序中一直传递,像一个烫手山芋一样,所以我们称这种结构体为 Hot Potato
为什么sui需要能力呢,因为 Move 旨在表达数字资产和资源,不能被随意复制,随意丢弃,我们要确保代码的安全性和资源的正确使用。
所以has drop
属性表示 PRTS
实例可以被销毁(当不再需要时)。
接下来我们来看看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我们就不多赘述了,感兴趣的可以看下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 铸币和发币
重点又来了,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> <函数所需的传参>
重点:见证者,事务上下午,能力,对象所有权
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!