Rust调用sui合约

照着move-book教程 Hello, Sui! - The Move Book 很快写完 move 合约部署到测试网

创建一个 todo_list Object 并将 ownership 转移给我自己的合约调用如下(ptb=ProgrammableTransactionBuilder)

复制代码
sui client ptb \
  --assign sender @$(sui client active-address) \
  --move-call $PACKAGE_ID::todo_list::new \
  # 将new函数的返回值保存到list中
  --assign list \
  # transfer 之后用 sui client objects --json 就能看到我拥有个 TodoList Object
  --transfer-objects "[list]" sender

sui client ptb 一次可以传入多个 --move-call 但字符串的入参要单双引号两个参数转义 否则就报错如下

复制代码
sui client ptb --move-call 0x702815e66354365ec77e0ea708912725be4e8e0407b041e11f3b3f733c2a4a53::todo_list::add @0x6d08e394bcc4dec6a8349f1ffb4e5630c0cd55df1ba9882cfe66dfa5b1f7d130 'item 3'
   ╭────
 1 │ --move-call 0x702815e66354365ec77e0ea708912725be4e8e0407b041e11f3b3f733c2a4a53::todo_list::add @0x6d08e394bcc4dec6a8349f1ffb4e5630c0cd55df1ba9882cfe66dfa5b1f7d130 item 3 
   ·                                                                                                ─────────────────────────────────────┬────────────────────────────────────
   ·                                                                                                                                     ╰── Expected 2 arguments, but got 3

sui client ptb 或者 call 都能调用合约,但 ptb 的功能更多点不仅限于调用合约

sui client ptb --move-call 0x702815e66354365ec77e0ea708912725be4e8e0407b041e11f3b3f733c2a4a53::todo_list::add @0x6d08e394bcc4dec6a8349f1ffb4e5630c0cd55df1ba9882cfe66dfa5b1f7d130 ''\''item 2'\'''

sui client call --package 0x702815e66354365ec77e0ea708912725be4e8e0407b041e11f3b3f733c2a4a53 --module todo_list --function add --args 0x6d08e394bcc4dec6a8349f1ffb4e5630c0cd55df1ba9882cfe66dfa5b1f7d130 'item 2'

最后区块浏览器查看 https://suiscan.xyz/testnet/object/0x6d08e394bcc4dec6a8349f1ffb4e5630c0cd55df1ba9882cfe66dfa5b1f7d130

sui/sol/apt一样,数据存储需要支付押金 Storage Rebate Sui Gas Pricing | Sui Documentation

可以类似sol销户那样退存储押金

背景知识

struct SuiObjectData

Object Model | Sui Documentation, Object 类似于 aptos 的 Resource 和 solana 的 Account

核心字段(组成 ObjectRef ):

  • object_id: u256
  • version: SequenceNumber
  • digest: hash of the object's contents and metadata

发送交易的是必须要传入 GasCoin 的 ObjectRef, 如果要修改 Object 函数入参第一个一般都是 ObjectRef

悲剧的是区块浏览器不能获取到 digest (我一开始还以为是nonce作用类似的previous_transaction digest)

例如我 todo_list object 修改了三次之后 digest 是 o#B1t1pVwpn8vQ9LDEeKT5HY6wA859rPHwuJwUGW1NcXyt

理论上修改第四次的时候 digest 会变,果然变了 o#n9pBGbgV3fF2R2KDDWicVitys7PGvStQgYSizo4R5N9

tx commands

  • SplitCoins: 例如支付GAS
  • MoveCall: 调用智能合约函数
  • TransferObjects

Transaction effects are the changes that a transaction makes to the blockchain state

sign tx

Signing and Sending Transactions | Sui Documentation

tx_data 通过 bcs::to_bytes 序列化成 Vec 后面再用 blake2 哈希出摘要,摘要+签名算法flag+公钥 一起签名得到 Signature

整个过程跟 bluefin 交易所下单/撤单的交易签名类似

ptb

Building Programmable Transaction Blocks | Sui Documentation

SuiClientCommands::Call

照着 sui 源码 Call sub command 的处理流程读一遍,就加深对 sui 调用合约函数过程的理解

Rust 代码实现

参考 crates/sui-sdk/examples/function_move_call.rs

Cargo.toml

复制代码
sui_sdk = { git = "https://github.com/mystenlabs/sui", package = "sui-sdk"}
sui_keys = { git = "https://github.com/mystenlabs/sui", package = "sui-keys"}
shared_crypto = { git = "https://github.com/mystenlabs/sui", package = "shared-crypto"}
bcs = "0.1.6"

初始化查询下 sui 的 ObjectRef 信息和我自己 Object 信息,后续可以优化成只查询一次缓存下来

复制代码
let sui_client = sui_sdk::SuiClientBuilder::default().build_testnet().await.unwrap();
let sender: SuiAddress = my_addr.parse().unwrap();
let coins = sui_client.coin_read_api().get_coins(sender, None, None, None).await.unwrap();
let gas_coin = coins.data.into_iter().next().unwrap();

let object_id: ObjectID = object_id.parse().unwrap();
let obj = sui_client.read_api().get_object_with_options(object_id, SuiObjectDataOptions::bcs_lossless()).await.unwrap().data.unwrap();
dbg!(&obj.digest);

请求的入参封装如下

复制代码
let mut ptb = ProgrammableTransactionBuilder::new();
let arg0 = CallArg::Object(ObjectArg::ImmOrOwnedObject((obj.object_id, obj.version, obj.digest)));
// Add this input to the builder
ptb.input(arg0).unwrap();
let arg1 = "item 4";
ptb.input(CallArg::Pure(bcs::to_bytes(&arg1).unwrap())).unwrap();
let pkg_id = "0x702815e66354365ec77e0ea708912725be4e8e0407b041e11f3b3f733c2a4a53";
let package = ObjectID::from_hex_literal(pkg_id).unwrap();
let module = Identifier::new("todo_list").unwrap();
let function = Identifier::new("add").unwrap();
ptb.command(Command::MoveCall(Box::new(ProgrammableMoveCall {
    package,
    module,
    function,
    type_arguments: vec![],
    arguments: vec![Argument::Input(0), Argument::Input(1)],
})));
let builder = ptb.finish();

这个函数对应的 move 源码 以及 ABI

复制代码
module todo_list::todo_list {
// 因为sui有次升级为了方便前端tx调用合约函数,没有entry修饰的函数也可以rpc调用了
public fun add(list: &mut TodoList, item: String) {
    list.items.push_back(item);
}
}

原帖地址: Rust调用sui合约 - 苏慕白的博客

相关推荐
石榴树下7 分钟前
00. 马里奥的 OAuth 2 和 OIDC 历险记
后端
uhakadotcom7 分钟前
开源:subdomainpy快速高效的 Python 子域名检测工具
前端·后端·面试
似水流年流不尽思念24 分钟前
容器化技术了解吗?主要解决什么问题?原理是什么?
后端
Java水解25 分钟前
Java中的四种引用类型详解:强引用、软引用、弱引用和虚引用
java·后端
i听风逝夜26 分钟前
看好了,第二遍,SpringBoot单体应用真正的零停机无缝更新代码
后端
柏油1 小时前
可视化 MySQL binlog 监听方案
数据库·后端·mysql
舒一笑2 小时前
Started TttttApplication in 0.257 seconds (没有 Web 依赖导致 JVM 正常退出)
jvm·spring boot·后端
M1A12 小时前
Java Enum 类:优雅的常量定义与管理方式(深度解析)
后端
AAA修煤气灶刘哥3 小时前
别再懵了!Spring、Spring Boot、Spring MVC 的区别,一篇讲透
后端·面试
柏油3 小时前
MySQL 字符集 utf8 与 utf8mb4
数据库·后端·mysql