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合约 - 苏慕白的博客

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Rust调用Java代码,可以使用Java Native Interface(JNI)来实现。下面是一些基本步骤: 1. 编写Java代码并将其编译为JAR文件。确保你的代码包含一个公共类和一个公共方法。 2. 在Rust中,使用rust-jni或jni-sys crate来链接JNI库,并使用JNI函数加载JAR文件。例如,使用`JNIEnv::FindClass`函数来找到Java类,使用`JNIEnv::GetMethodID`函数来获取Java方法的ID。 3. 通过JNI接口调用Java方法。使用`JNIEnv::CallStaticMethod`函数来调用静态方法或`JNIEnv::CallObjectMethod`函数来调用非静态方法。 以下是一个简单的示例代码,展示了如何在Rust调用Java代码: ```rust extern crate jni; use jni::JNIEnv; use jni::objects::{JClass, JString}; use jni::sys::{jstring, jobject}; #[no_mangle] pub extern "system" fn Java_MyClass_myMethod(env: JNIEnv, _: JClass, input: JString) -> jobject { // Convert the input string to a Rust string let input_str: String = env.get_string(input).expect("Invalid string").into(); // Call a Java method that takes a string and returns an object let output = env.call_static_method( "MyClass", "myMethod", "(Ljava/lang/String;)Ljava/lang/Object;", &[input.into()], ).expect("Failed to call method"); // Return the Java object output.into_inner() } ``` 注意,`Java_MyClass_myMethod`是一个伪函数名,你需要将其替换为实际的Java类名和方法名。此外,你需要将方法签名`(Ljava/lang/String;)Ljava/lang/Object;`替换为你实际方法的签名。 希望这可以帮助你开始在Rust调用Java代码!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值