在区块链L1层,除了以太系为主的用Solidity编写的智能合约之外,还有一类是Move语言编写的智能合约,本文以Aptos链为目标,使用Aptos CLI工具进行Move合约的编译、部署以及合约交互。
准备工作
- 安装Aptos CLI
- 下载aptos-core源码
安装Aptos CLI:aptos.dev/tools/aptos…
aptos-core代码:github.com/aptos-labs/…
一、创建账户
首先,创建一个工作目录,命令行执行
mkdir first-move-module
cd first-move-module
然后,初始化Aptos:
aptos init
在命令行交互时,会出现提示:
Configuring for profile default Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet],
选择devnet,然后出现让你输入私钥的提示:
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
选择让工具包生成新的key,回车继续,得到:
No key given, generating key... Account 0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245 doesn't exist, creating it and funding it with 100000000 Octas Account 0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245 funded successfully Aptos CLI is now set up for account 0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245 as profile default! Run
aptos --helpfor more information about commands { "Result": "Success" }
0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245这个地址就是这次随机生成的,作为default地址使用,比如为此账户注入资金时,可以使用命令:
aptos account fund-with-faucet --account default
运行后得到:
{ "Result": "Added 100000000 Octas to account 0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245” }
二、编译Move合约
暂且不考虑Move合约的编写问题,先拷贝Aptos的示例合约:hello_blockchain.move和hello_blockchain_test.move到我们刚才创建的目录下(aptos-core/aptos-move/move-examples)
注意要在此目录下创建Move.toml,写法参考示例合约中的Move.toml,但需要注意的是,要把dependencies的路径指向aptos-core下的aptos-framework。有两种写法:
- 配置本地aptos-framework路径
[dependencies]
AptosFramework = { local = "/Users/xxx/xxx/aptos-core/aptos-move/framework/aptos-framework" }
- 配置远程aptos-framework路径
[dependencies.AptosFramework]
git = "<https://github.com/aptos-labs/aptos-core.git>"
rev = "mainnet"
subdir = "aptos-move/framework/aptos-framework"
然后进行编译:
aptos move compile --named-addresses hello_blockchain=default
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING Examples
{
"Result":
[ "4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245::message" ]
}
可以运行测试合约的命令:
>> aptos move test --named-addresses hello_blockchain=default
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING Examples
Running Move unit tests
[ PASS ] 0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245::message::sender_can_set_message
[ PASS ] 0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245::message_tests::sender_can_set_message
Test result: OK. Total tests: 2; passed: 2; failed: 0
{
"Result": "Success"
}
三、发布合约到链上
>> aptos move publish --named-addresses hello_blockchain=default
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING Examples
package size 1629 bytes
Do you want to submit a transaction for a range of [155500 - 233200] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "0xddb1712ce3beba1bc6673d63c9a0930828d8beab445a64e82e1298b2ec70aff0",
"gas_used": 1555,
"gas_unit_price": 100,
"sender": "4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245",
"sequence_number": 0,
"success": true,
"timestamp_us": 1715830600430913,
"version": 17592951,
"vm_status": "Executed successfully"
}
}
这样执行成功后,这个module就存储在链上了,具体的存储位置是在执行部署的账户下,可以通过aptos account list 查看。
四、调用链上合约
在Move合约中,标记为entry的函数是交互的入口,在这个示例合约中是set_message方法,代码如下:
public entry fun set_message(account: signer, message: string::String)
acquires MessageHolder {
let account_addr = signer::address_of(&account);
if (!exists<MessageHolder>(account_addr)) {
move_to(&account, MessageHolder {
message,
})
} else {
let old_message_holder = borrow_global_mut<MessageHolder>(account_addr);
let from_message = old_message_holder.message;
event::emit(MessageChange {
account: account_addr,
from_message,
to_message: copy message,
});
old_message_holder.message = message;
}
}
使用默认账户调用此方法,命令如下:
aptos move run \
--function-id 'default::message::set_message' \
--args 'string:hello, blockchain'
得到结果:
{
"Result": {
"transaction_hash": "0xb1fc7b33e289d818a97108c949b9cb79ac13fd879028a9d92e9d36c5d6ce2df3",
"gas_used": 446,
"gas_unit_price": 100,
"sender": "4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245",
"sequence_number": 1,
"success": true,
"timestamp_us": 1715831045718481,
"version": 17596976,
"vm_status": "Executed successfully"
}
}
显然这个调用作用是将一个‘hello, blockchain’的字符串写入一个MessageHolder的结构体中,我们可以通过下面这条查询判断是否在链上写入成功:
curl https://api.devnet.aptoslabs.com/v1/accounts/4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245/resource/0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245::message::MessageHolder
执行后得到响应:
{"type":"0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245::message::MessageHolder","data":{"message":"hello, blockchain"}}
也就是说,通过调用set_message方法,我们把“hello, blockchain”这个字符串写入了地址为0x4c56adc7c6757b9947f459f7b676c7c8bd07ce690f082d5bb07ee3e15db34245的Account的一个叫MessageHolder的结构体下。
另一种验证方式,仍是通过查看Account下所有resource,运行aptos account list后,得到一个JSON响应体,格式化后可以看到此账户下的存储资源如下图所示:
至此,一个简单的Move合约就创建并部署完成了。
目前,Aptos以及SUI都支持Move合约,与以太系的Solidity基本原理和存储结构虽然不太相同,但也相对容易理解,并且有配套的CLI工具和几种主流编程语言的SDK可以使用,不妨学习了解一下。