Sui Move合约开发简明教程
本文将使用Sui Move开发一个简单的智能合约来发行和管理 Coin,然后在Sui脸上部署它并与之交互。
一键发币: SUI | SOL | BNB | ETH | BASE | ARB | OP | POLYGON | AVAX | FTM | OK
在上一篇关于 Aptos 的“Code in Move”文章发表一年后,终于迎来了第四集,其中介绍了最具创新性和前景的区块链之一:Sui!
在 2022 年春季探索 Aptos 后不久,我发现了由 Mysten Labs 构建的 Sui,这是一个来自 Facebook 的团队,就像 Aptos Labs 一样。如果我认为 Move 和 Aptos 与竞争对手相比是有趣的创新,那么 Sui 让我大吃一惊,它确实是从 0 到 1 的创新,现在独树一帜。
就像那篇文章中的 Aptos 一样,我们将创建一个简单的智能合约来发行和管理 Coin,然后部署它并与之交互。几个月来,我一直渴望继续使用 Sui 进行这个系列,这让我非常兴奋,最后,我们来了!不过,你会注意到,我在 Twitter 上非常活跃,分享有关 Sui 的技术和教育内容,等等!
1、先决条件
让我们从安装开发环境开始。按照这个教程安装 Sui 二进制文件。然后,如果你使用的是 vscode 或分叉版本(例如非常好的 Cursor),请安装 move-analyzer(按照这些说明)或 sui-move-analyzer(按照扩展页面上的说明)。
2、基础知识
Sui 围绕一个基本概念构建:对象。对象是采用特定结构形式的基本构建块。结构具有与 Aptos 上的结构相同的能力,但它们的效果并不完全相同。复制和删除能力允许复制或删除结构,而存储允许将结构包装在另一个结构中并自由传输(如果它是对象)。具有 key
能力且第一个字段为 id: UID
的结构是一个对象。
除了用户帐户(只是公共地址)之外,一切都是 Sui 对象。资产(NFT、硬币、LP 代币、SFT 等)是对象,智能合约也是对象,它们是不可变的,因为它们不保持状态。与智能合约相关的数据存储在共享对象中。
有两种类型的对象:
- 自有对象:由所有者(owner)签署的交易可读取和写入。仅使用自有对象的交易受益于极低的最终延迟,因为它们不需要经过共识。
- 共享对象:任何交易均可读取和写入。访问一个或多个共享对象的交易需要共识来对这些对象进行顺序读取和写入。这会导致 gas 成本略高,并增加延迟。
还有一种特殊类型的共享对象,即不可变(或冻结)对象。这些对象不能被修改、转移或删除,因此可以绕过共识,就像自有对象一样(这就是智能合约不可变的原因)。
有两种使用对象的方法:
- by value:拥有对象的所有权意味着你可以完全控制它。你可以根据定义它的模块中设置的权限销毁它、包装它、修改它和转移它。
- by reference:借用对象的某些部分(可变或不可变)意味着用户对其拥有完全所有权。智能合约定义 setter 和 getter,以只读或写入模式授予对特定字段的权限访问。
3、编写包
在 Sui 上,智能合约称为包(package),并在链上发布(部署)。它们与 Aptos 类似,拆分为 Move 模块。
sui move new first-coin
将创建一个新的 Sui 项目,其中包含 Move.toml
,其中已设置 sui-framework
依赖项。你可以通过引用 github 存储库来添加任何链上依赖项,让我们添加 Move 标准库:
[package]
name = "first-coin"
version = "0.0.1"
[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }
MoveStdlib = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "framework/testnet" }
[addresses]
first_coin = "0x0"
在 ./src
下创建一个 coin.move
文件并添加以下导入:
module first_coin::managed {
use std::option;
use sui::coin::{Self, Coin, TreasuryCap};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
}
对于此用例,我们需要一种称为一次性见证 (OTW) 的特殊 Sui Move 类型。这是一种保证最多只有一个实例的类型。它对于限制某些操作仅发生一次(创建硬币、发行 NFT 集合等)很有用。在 Move 中,如果满足以下条件,则类型被视为 OTW:
- 其名称与其模块的名称相同,全部大写。
- 它具有删除能力并且只有删除能力。
- 它没有字段,或者只有一个 bool 字段。
它是在 init
函数中传递的第一个参数(函数在部署期间运行一次),它将是我们硬币的符号。
struct COIN has drop {}
fun init(otw: COIN, ctx: &mut TxContext) {
let (treasury_cap, metadata) = coin::create_currency<COIN>(witness, 9, b"COIN", b"First Coin", b"This is my first coin", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury_cap, tx_context::sender(ctx))
}
在这里,我们在 Sui 系统中创建一个具有 9 个小数的 Coin 类型,并返回 TreasuryCap
和 CoinMetadata
对象。 “Cap” 对象通常用于向其持有者授予特定权限(此处为铸造和销毁)。 我们将其转移到发布者地址以限制铸造和销毁,但我们也可以共享该对象以授权任何人铸造和销毁一定数量的这种硬币。 另一个对象由前端和其他智能合约用于获取有关硬币的信息。 我们冻结它以防止进一步修改。
我们现在需要铸造和选择性销毁一定数量的这种硬币的函数:
// returns a Coin object
public fun mint(
treasury_cap: &mut TreasuryCap<COIN>, amount: u64, ctx: &mut TxContext
): Coin<COIN> {
coin::mint(treasury_cap, amount, ctx)
}
// sends the Coin object to a recipient
public entry fun mint_and_transfer(
treasury_cap: &mut TreasuryCap<COIN>, amount: u64, recipient: address, ctx: &mut TxContext
) {
coin::mint_and_transfer(treasury_cap, amount, recipient, ctx);
}
public entry fun burn(treasury_cap: &mut TreasuryCap<COIN>, coin: Coin<COIN>) {
coin::burn(treasury_cap, coin);
}
默认情况下,函数是私有的,可以是标注为 entry
(可从前端调用)、 public
(可从其他包调用,现在是可编程交易块)、 public(friend)
(可从友模块调用)。
所有这些函数都可变地借用了 TreasuryCap
,这意味着从技术上讲,对象以写入权限传递给智能合约,但发送者始终保留所有权。因为需要拥有 Cap 才能调用这些函数,所以只有 Coin 管理器才能铸造和销毁硬币。它是可变传递的,因为包需要修改其 total_supply
字段。
使用时, ctx: &mut TxContext
需要是函数的最后一个参数,它会自动从前端传递。此参数允许访问重要信息(如链上时间)或创建对象(如 Coins)。
burn
和 mint_and_transfer
很简单,因为它在其他区块链上就是这样工作的。但 Sui 有很多很酷的功能,其中之一就是可编程交易块 (PTB)。
我将专门写一篇文章来介绍 PTB,但这里是 tl;dr:Sui 与其他链一样具有交易,最多可将 1024 个交易合并到一个 PTB 中。这意味着可以在一次执行中执行许多操作,从而大大减少延迟、成本和故障率,并提高可组合性。这里有一个例子和另一个例子。
它确实是一个很棒的工具,为开发人员开辟了许多新模式和机会,但它是一个需要掌握的新编程范式。对于鉴赏家来说,Radix 有一个类似的概念,称为交易清单。
在这里,想法是返回 Coin 对象。在前端或后端,我们将能够使用此对象,将其发送或传递给另一个函数。也许我们想使用 mint
函数直接将一些 Coin 发送到地址列表,并将其余的添加到流动性池中。我们不需要在我们的包中创建发送函数或复杂的跨合约调用。由于 PTB,这将被抽象出来!
你可以在此处找到源代码。
4、发布并与包交互
我们的包现在可以发布了。 运行 sui client
以初始化 Sui CLI 的新配置。 你可以在 ~/.sui/sui_config
中找到它。 使用 sui move build
构建包。 使用 sui client publish --gas-budget 100000000
发布它。 如果你收到正常错误,则需要 SUI 币来支付 gas。 复制错误中指示的地址并转到 Sui discord 在 devnet 上领取一些 SUI。
发布后,你将看到与交易相关的数据,包括对象更改。
在这里,我们可以找到调用 mint
和 burn
函数所需的新创建对象的 ID。 你也可以从 Sui 浏览器之一获取它们:Sui Explorer、Sui Vision 或 Sui Scan。
sui client call --package <publishedPackageID> --module coin --function mint_and_transfer --args <createdTreasuryCapID> 10 <recipientAddress>--gas-budget 10000000
此命令将调用你新发布的包中的 coin 模块中的函数 mint_and_transfer
,传递 TreasuryCap id、金额和收件人地址作为参数(TxContext 自动传递)。
现在,如果你在浏览器上检查收件人地址,将看到一个余额为 amount/10ᵈᵉᶜⁱᵐᵃˡˢ 的 Coin。如果这是你的地址,你可以获取 Coin 对象 id 以同样的方式销毁你选择的金额。
5、结束语
这是一个非常基本的 Sui 智能合约,但它展示了 Sui 的许多特殊特性。这只是开始!
我个人曾尝试过几种区块链编程模型,但我最喜欢的是在 Sui 上构建或多或少复杂的 dapp。一旦你掌握了这个新专业背后的哲学,语法模型,感觉非常直观和自然。我强烈建议你仔细阅读文档,其中详细介绍了 Mysten Labs 的愿景。
这个才华横溢的团队开发了令人兴奋的构建原语,例如 PTB、赞助交易、zkLogin、zkSend、动态字段、闭环令牌、Kiosk 等。我们将在未来的文章中看到这些概念。
原文链接:Code in Move [4] — Sui Move Basics
DefiPlot翻译整理,转载请标明出处
免责声明:本站资源仅用于学习目的,也不应被视为投资建议,读者在采取任何行动之前应自行研究并对自己的决定承担全部责任。