# 构建我的aptos move 开发环境

By [moonly](https://paragraph.com/@moonly) · 2022-07-17

---

0x0、简介
------

MOVE是一个大家同样在过程中，以安全性的编写记录下来的语言，个人正在慢慢发现目前并没有形成学习结构的探索教程，所以打算将自己的探索，帮助踩到坑，这是第一个篇记录寻找aptos的MOVE IDE配置的笔记，如有错误欢迎大家指正。

联系我：Discord:k8ssssss#1673

0x1、浏览器开发环境
-----------

如果你只是想简单的体验一下move的语法，那么推荐使用浏览器开发环境`Move Playground`

地址：[https://playground.pontem.network/](https://playground.pontem.network/)

先来看下全景图的功能。

![](https://storage.googleapis.com/papyrus_images/894b9307e935ebd267df5da13afea6eabb989857bbdc5ffcb42ce46bc23dc223.png)

![](https://storage.googleapis.com/papyrus_images/299a711eaf803d1ce99a7e5a3dc3790da1320889ca4eeb5c79acc97cee0c8d5f.png)

通过一个简单的脚本来演示如何使用

首先收集所有数据，然后创建我们的新项目`test_script`

![](https://storage.googleapis.com/papyrus_images/51157e6d37de1a1121e7aeb0dddf5d4e33f32fcd663140e3bb066b6f69a92c59.png)

然后我们点击项目目录，展开目录树，工程目录结构如下

*   项目名称（项目名称）
    
    *   脚本（存放脚本目录）
        
    *   来源（加载模块）
        
    *   测试（存放测试文件）
        

分别在`scripts`和`sources`目录下创建文件`test_script.move`和`test_module.move`

![](https://storage.googleapis.com/papyrus_images/664d3c9f471712234517bf86b44f8f9107fa7fd1f0ff79ad128f4aeba51e8974.png)

创建完成后，点击文件就可以在打开的文件中打开编辑窗口，我们在下面的`test_module.move`代码中

    module 0x01::Math {
        public fun sum(a: u64, b: u64): u64 {
            a + b
        }
    }
    

由于目前这个编辑器不支持中文注释，下面带注解版本方便新手理解。

    module 0x01::Math {		//在0x01地址下定义一个名为Math的module
        public fun sum(a: u64, b: u64): u64 {		//定义一个公开的函数，名为sum 需要输入u64类型的a、b 返回一个u64类型的值
            a + b
        }
    }
    

在`test_script.move`中写入以下代码

    script {
        use 0x01::Math;
        use 0x1::Debug;
    
       fun test_script(a: u64, b: u64) {
         let c = Math::sum(a,b);
         Debug::print(&c);
       }
    }
    

简单的注解

    script {			//定义一个script
        use 0x01::Math;			//	引入Math module
        use 0x1::Debug;			//  引入内置module Debug
    
       fun test_script(a: u64, b: u64) {	//定义 一个函数要求输入a、b两u64类型的值
         let c = Math::sum(a,b);		//定义一个变量c 赋值为a、b之和
         Debug::print(&c);			//输出变量c
       }
    }
    

在Run Script功能栏执行`test_script(2,3)`，就可以获得结果等于5，同时可以看到消耗的gas数量。

![](https://storage.googleapis.com/papyrus_images/c9a06a86744d87d9336917fc7c3612072dd967e7c54bf274a451272082fc5213.png)

0x2、本地开发环境构建
------------

### 基于Clion

#### 1、安装aptos CLI

前往发布页面下载最新的二进制文件，当前最新的发布版本是V0.2.0

[https://github.com/aptos-labs/aptos-core/releases](https://github.com/aptos-labs/aptos-core/releases)

![](https://storage.googleapis.com/papyrus_images/31038d31b7583ae45a9706e9d760706d8e14f602ea68c75d4fa27c9e32e5c182.png)

下载解压之后放到你想要的目录下面，由于Mac的安全策略问题需要手动有右键打开一次。然后需要把`apts`添加进环境变量

我这里终端配置的是zsh，所以我直接写入了家目录下的\`.zshrz\`文件，可以根据自己的环境来。

`export PATH="/Users/moonly/aptos:$PATH"`

完成之后重新打开终端，执行\`aptos\`，显示如下信息就是完成安装了

![](https://storage.googleapis.com/papyrus_images/caa559d8f0eff8450449ec04ceef9c3cbfedfabe35df1c5fc2e5529c45dfbcc3.png)

CLI的具体操作说明可以看官方的文档：[https://github.com/aptos-labs/aptos-core/blob/main/crates/aptos/README.md#install-the-aptos-cli](https://github.com/aptos-labs/aptos-core/blob/main/crates/aptos/README.md#install-the-aptos-cli)

#### 2、Clion 联动CLI

安装 Move Language插件

![](https://storage.googleapis.com/papyrus_images/637f93ba23ecd246c44682a137d1f56a6943509fcf601b7f56f77217438823a3.png)

安装中文插件

![](https://storage.googleapis.com/papyrus_images/d7d1ed6efbbe0d3498f200b2d561e42ad943d2ed12c24bb8fe16b6444958e13e.png)

完成后重启CLion，新建项目时就可以选择MOVE了。新建一个项目

![](https://storage.googleapis.com/papyrus_images/6b2edac9dbc3247581a336fce0b3319dec5d93b595ea8b79a9e90a794e2874ff.png)

然后我们需要对aptos进行初始化，点击左下角的`终端`打开命令行，输入`aptos init`

![](https://storage.googleapis.com/papyrus_images/f5981d01529fe9add10da0b4c6eaa3b42a596fccfddb5f948db4ca630d15c08e.png)

命令会交互式的让你提交REST地址、水龙头地址和钱包私钥，如果全部直接回车，则会默认使用公共开发网的地址。

最终会返回一个钱包地址，需要复制这个钱包地址。

![](https://storage.googleapis.com/papyrus_images/9f1f87f5e2ed89982dc6a9c973d456da8c2121e4baa19eb18f56bb6bd98e1525.png)

将上面的钱包地址写入项目目录中的`Move.toml`文件中

![](https://storage.googleapis.com/papyrus_images/25c49438b88cdfcbb2f9ab633aaf526404e24705233520935dcd21727f3b78d6.png)

这样我们就完成了IDE的配置。

#### 3、编写测试

在sources目录下右键新建MOVE文件

![](https://storage.googleapis.com/papyrus_images/59c3cc41d1a19a2c8e0692a3bdfef32e271d7d10deb1ba87df97c9a72b804162.png)

选择`Module`然后输入文件名`test_module`

![](https://storage.googleapis.com/papyrus_images/80fe3506568c8e3d4c758441fca05a26802fad3445628bcf7ce9d68ffb7af252.png)

写入以下代码，一个简单的加法

    module Sender::Math {
        public fun sum(a: u64, b: u64): u64 {
            a + b
        }
    }
    

然后创建`tests`目录

![](https://storage.googleapis.com/papyrus_images/bd249e3b374458e021ec212a01a77041bc6b2377cd864c36233599c63599fcd2.png)

然后在`tests`目录下创建文件`test_script.move`,类型选择Test

![](https://storage.googleapis.com/papyrus_images/0e5ff6f0eda7850a938206f059861c5caaa8d1703123b41a2028f7308dd889e7.png)

写入以下代码，引入刚刚我们的`Math`,然后计算a+b 并验证结果是否等于50

    #[test_only]
    module Sender::MathTest {
        use Sender::Math;
    
        #[test]
        fun test_add() {
            let a = 20;
            let b = 30;
    
            let r = Math::sum(a, b);
            assert!(r == 50, 1);
        }
    }
    

切换回`test_module.move`文件，然后点击右上角Build后的三角形按钮进行本地编译

![](https://storage.googleapis.com/papyrus_images/958d7e7cb8269a56b603ce89ce3502023a9671cebd05f7e528867e5641422bd5.png)

下方会显示结果，如果有报错也会在下面显示，可以看到我们的Math以及发布在我们的钱包地址下了。然后我们之前在`Move.toml`文件中将地址设置为别名`Sender`,现在就可以在脚本中用`use Sender::Math;`来引入Math了。

![](https://storage.googleapis.com/papyrus_images/eb7d811a9c3ec3a11dab826b0ce97cf00f8a5374a6dbdb8bb6cb655622c6712a.png)

切换到`test_script.move`文件，点击方法旁边的绿色三角形可以直接运行函数

![](https://storage.googleapis.com/papyrus_images/f7711ca7ec1a35ea1fcd8479f055ab1c8ef46eb4c0dd12163d742d0f9973e202.png)

也可以通过右上角进行运行

![](https://storage.googleapis.com/papyrus_images/70f042fe00f655f6b03f989b8d4fc8a52e793289ff641c93fdd7d344877d19cb.png)

可以看到运行成功

![](https://storage.googleapis.com/papyrus_images/bb42e1fe7aa8938bafe93ff47f8bd2898473eb77877206a0559367fc37080de7.png)

`assert!`关键字是一个类似于solidity中的`require`，它接受2个参数，第一个参数是一个布尔表达式，如果结果为假就会报错第二个参数的错误码，并终止执行回退操作，如果我们把代码修改一下，再次执行就会报错了。

    #[test_only]
    module Sender::MathTest {
       use Sender::Math;
       #[test]
       fun test_add() {
           let a = 20;
           let b = 30;
    
           let r = Math::sum(a, b);
           assert!(r == 51, 1);
       }
    }
    

![](https://storage.googleapis.com/papyrus_images/0ecf8c9530d75033eebedb3044c66d43223d9746f9cc9b106e972befb79a51b1.png)

### 0x3、基于VS Code

#### 1、安装插件

VS Code中有两个Move插件

一个是Move核心团队维护的`move-analyzer`，一个是由Pontem 团队维护的`Move Language`

这里我选择了`move-analyzer`，插件依赖组件`move-analyzer`语言服务器,`move-analyzer`语言服务器是一个 Rust 程序,所以需要先安装Rust 的包管理器`cargo`.安装完成后执行`cargo -V`查看版本

    curl https://sh.rustup.rs -sSf | sh
    

![](https://storage.googleapis.com/papyrus_images/3b9389d75802a3ae15bcb58a5904e3f3028433e4c54c0a1ad674cbc9be0dbd43.png)

开始安装`move-analyzer`,由于aptos与Move标准风格的地址格式不同，所以需要加上参数`--features "address32"`,安装完成后执行`move-analyzer --version`查看版本,然后执行`where is move-analyzer`找到二进制文件的路径，待会配置插件需要用到。

    cargo install --git https://github.com/move-language/move move-analyzer --features "address32"
    

![](https://storage.googleapis.com/papyrus_images/d01e6bc4205971968368995713786442e5a6debe6e8ccceb37f3a51ac324bdaa.png)

打开VS Code搜索安装插件，安装完成后点击小齿轮选择扩展设置。

![](https://storage.googleapis.com/papyrus_images/4f738995abffca32364811d1550a8bbafdd00a989983f9a111989f048d0f6009.png)

写入刚刚获取的二进制文件路径，然后重启VS Code

![](https://storage.googleapis.com/papyrus_images/66efa65374cde454d19040ee914922491936d30448c736149182a485029215bf.png)

#### 2、安装aptos CLI并初始化项目文件夹

安装方法可以看上面Clion的章节。安装完成后用VS Code打开一个新的文件夹，此时它应该是空的。打开终端执行`aptos move init --name <项目名称>`就会生成项目结构，同时包含一个`Move.toml`文件。

![](https://storage.googleapis.com/papyrus_images/89db2b79e3f87e74cd0860b1caa149b040a4bbe02075c70057e7e3abe9690c6f.png)

然后执行`aptos init` 命令会交互式的让你提交REST地址、水龙头地址和钱包私钥，如果全部直接回车，则会默认使用公共开发网的地址。最终会返回一个钱包地址，需要复制这个钱包地址。写入`Move.toml`文件中格式为`<钱包别名> = “0x<钱包地址>”` ,如果你想修改这个配置可以在项目目录下`.aptos/config.yaml`找到它

![](https://storage.googleapis.com/papyrus_images/d1092946acc4b875a5fe64f551a2acea93c7968060cb6982816404c6297b3314.png)

用一个官方的`HelloBlockchain`来演示一下如何进行编译和运行代码，源码github地址：[https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/move-examples/hello\_blockchain](https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/move-examples/hello_blockchain)

这个用例的核心功能就是为你的钱包中保存一条文本信息。

由于我们刚刚设置的地址别名是`Sender`，所以这里第一行被我修改为了`Sender`。

    module Sender::Message {
        use Std::ASCII;
        use Std::Errors;
        use Std::Event;
        use Std::Signer;
    
        struct MessageHolder has key {
            message: ASCII::String,
            message_change_events: Event::EventHandle<MessageChangeEvent>,
        }
    
        struct MessageChangeEvent has drop, store {
            from_message: ASCII::String,
            to_message: ASCII::String,
        }
    
        /// There is no message present
        const ENO_MESSAGE: u64 = 0;
    
        public fun get_message(addr: address): ASCII::String acquires MessageHolder {
            assert!(exists<MessageHolder>(addr), Errors::not_published(ENO_MESSAGE));
            *&borrow_global<MessageHolder>(addr).message
        }
    
        public(script) fun set_message(account: signer, message_bytes: vector<u8>)
        acquires MessageHolder {
            let message = ASCII::string(message_bytes);
            let account_addr = Signer::address_of(&account);
            if (!exists<MessageHolder>(account_addr)) {
                move_to(&account, MessageHolder {
                    message,
                    message_change_events: Event::new_event_handle<MessageChangeEvent>(&account),
                })
            } else {
                let old_message_holder = borrow_global_mut<MessageHolder>(account_addr);
                let from_message = *&old_message_holder.message;
                Event::emit_event(&mut old_message_holder.message_change_events, MessageChangeEvent {
                    from_message,
                    to_message: copy message,
                });
                old_message_holder.message = message;
            }
        }
    
        #[test(account = @0x1)]
        public(script) fun sender_can_set_message(account: signer) acquires MessageHolder {
            let addr = Signer::address_of(&account);
            set_message(account,  b"Hello, Blockchain");
    
            assert!(
              get_message(addr) == ASCII::string(b"Hello, Blockchain"),
              ENO_MESSAGE
            
        }
    }
    

在本地编译移动包，参数`--package-dir`指定项目目录，如果在项目根目录执行可以省去

`aptos move compile`

![](https://storage.googleapis.com/papyrus_images/f46b2024fb3173658f778bc12a8abb46c7df8c791d6b3f575bd7e4e08deaf36c.png)

在本地编译并进行执行单元测试，可选参数`--package-dir`指定项目目录，如果在项目根目录执行可以省去

`aptos move test`

![](https://storage.googleapis.com/papyrus_images/0f40cadb52a621e4a1b516e562eedba511ad2b78a4347789356d2ab6ab316556.png)

发布移动包

`aptos move publish`

![](https://storage.googleapis.com/papyrus_images/ca810c94c639e283d145f71f34408719a9279758de0c0e1dee6f5bf69a2c2a1e.png)

发布完成后，可以去我们发布的多个链浏览器，就可以看到我们的钱包地址，就可以看到已经绑定到我们的钱包地址了

区块浏览器地址：[https://explorer.devnet.aptos.dev/](https://explorer.devnet.aptos.dev/)

![](https://storage.googleapis.com/papyrus_images/813019034b2fdfbbc1ffb28cf49ededfc31edfe2b2fe23009e4f928b3c93c094.png)

函数运行

    aptos move run --function-id <钱包地址>::<模块名>::<函数名> --args <参数类型>:<参数值>
    

执行`set_message`参数`hello move!`

![](https://storage.googleapis.com/papyrus_images/02e125958f151bc06f78708c8315bca33c1deb3fd2513e7e705fb6414edde643.png)

已经可以在结果中参数写入账户中查看了。在区块链器上查看。

![](https://storage.googleapis.com/papyrus_images/53fcfcd9456e7a462eaa7a85c329fc9cae7e65d5d7c924e6d4d52ec095db19c5.png)

### 0x4、结束

感谢中文小组成员在创作过程中的帮助。@Boyu\_Chen#697、@lshoo#1959、@ruyisu#5492

参考链接：

aptos官方开发者文档：[https://aptos.dev/guides/getting-started](https://aptos.dev/guides/getting-started)

Aptos CLI官方文档：[https://github.com/aptos-labs/aptos-core/tree/main/crates/aptos](https://github.com/aptos-labs/aptos-core/tree/main/crates/aptos)

pontem官方文档：[https://docs.pontem.network/](https://docs.pontem.network/)

---

*Originally published on [moonly](https://paragraph.com/@moonly/aptos-move)*
