用 Elixir 交互 Aptos | Move dApp 极速入门(拾捌)

  • 李大狗
  • 更新于 2023-08-20 12:28
  • 阅读 921

函数式语言 <> Move

NonceGeekDAO 长期聚焦于 Move 生态与 Elixir 函数式编程语言。

https\://github.com/NonceGeek/ 

web3_move_ex 是 NonceGeekDAO 开发的,泛 Move 生态的 Elixir SDK,目前已完成对Aptos的基础支持。

本篇文章案例可见:

https\://github.com/NonceGeek/web3_move_ex_example

Aptos 已完成功能列表:

  • Acct Operations(账户相关操作)
  • Read Resource(读取资源)
  • Read Events(读取事件)
  • Call Func(调取函数)
  • Func Parser(解析字符串格式的函数,如0xdea79e568e00066f60fbfe6ac6d8a9ef2fabbeadc6aae1ec9158d50f6efe4ac8::addr_aggregator::create_addr_aggregator(u64,vector&lt;string>)

0x01 安装

创建一个新的示例项目:

$ mix new web3_move_ex_example
$ # 或者 clone 现成的 github repo:
$ git clone https://github.com/NonceGeek/web3_move_ex_example.git

mix.exs 中添加最新版本的web3_move_ex

defp deps do
    [
            {:web3_move_ex, "~> 0.4.0"}
    ]
end

打开交互式界面:

$ iex -S mix

0x02 账户相关

我们可以通过随机种子来生成账户:

alias Web3MoveEx.Aptos
{:ok, acct} = Aptos.generate_keys()

也可以通过私钥来生成:

{:ok, acct} = Aptos.generate_keys("0xffc207d0666ca82eac4e2238d0cf15f963a03ec6a9daa617dc035b7228de1f28")

创建连接节点的 client

{:ok, client} = Aptos.connect(:testnet)

给账户注入一些 faucet

Aptos.get_faucet(client, acct)

获取余额:

Aptos.get_balance(client, acct)

可以看到获取 faucet 成功了:

iex(10)> Aptos.get_balance(client, acct)
%{
  coin: %{value: "100000000"},
  deposit_events: %{
    counter: "1",
    guid: %{
      id: %{
        addr: "0xe59f44953723d5a8e26df9d3d4a613a2da3ff9f7dc4214dc281e10a244f39e3f",
        creation_num: "2"
      }
    }
  },
  frozen: false,
  withdraw_events: %{
    counter: "0",
    guid: %{
      id: %{
        addr: "0xe59f44953723d5a8e26df9d3d4a613a2da3ff9f7dc4214dc281e10a244f39e3f",
        creation_num: "3"
      }
    }
  }
}

我们可以把刚才的一系列步骤打包成一个函数:

def gen_acct_and_get_faucet(network_type) do
  {:ok, acct} = Aptos.generate_keys()
  {:ok, client} = Aptos.connect(network_type)
  {:ok, _res} = Aptos.get_faucet(client, acct)
  Process.sleep(2000)  # 用 2 秒等待交易成功
  %{res: Aptos.get_balance(client, acct), acct: acct}
end

函数执行结果:

iex(7)> %{acct: acct} = Web3MoveExExample.gen_acct_and_get_faucet(:testnet)
%{
  acct: #Account&lt;0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f>,
  res: %{
    coin: %{value: "100000000"},
    deposit_events: %{
      counter: "1",
      guid: %{
        id: %{
          addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
          creation_num: "2"
        }
      }
    },
    frozen: false,
    withdraw_events: %{
      counter: "0",
      guid: %{
        id: %{
          addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
          creation_num: "3"
        }
      }
    }
  }
}

0x03 调取函数与读取事件

我们以 MoveDID在测试网络上的合约为例,演示如何通过web3_move_ex来进行合约调用。

MoveDID Repo:https\://github.com/NonceGeek/MoveDID

Smart Contract on Testnet:

0x06195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46

我们可以通过 func_string 来生成 func:

import Web3MoveEx.Aptos
addr= "0x06195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46" # 合约地址
init_func_str = "#{addr}::init::init(u64, string)"
{:ok, init_func} = ~a"#{init_func_str}"

结果如下:

iex(5)> {:ok, init_func} = ~a"#{init_func_str}"
{:ok,
 %Web3MoveEx.Aptos.Types.Function{
   address: &lt;&lt;6, 25, 93, 67, 237, 222, 75, 28, 211, 169, 111, 120, 56,
     104, 107, 155, 18, 181, 16, 35, 205, 56, 141, 251, 33, 241, 35,
     179, 80, 244, 236, 70>>,
   address_encoded: "0x06195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46",
   is_entry: true,
   module: "init",
   name: "init",
   param_names: [],
   params: [:u64, :string],
   return: [],
   type_params: [],
   visibility: :public
 }}

可以顺便检查一下events的功能,按照合约逻辑,新添加一个DID,会在contract_owner下生成相应的事件。

Aptos.build_event_path(client, addr, "#{addr}::addr_aggregator::CreateAddrAggregatorEventSet", "create_addr_aggregator_events")
# 这个函数生成的地址可以直接用浏览器访问.

640.png

Aptos.get_events(client, addr, "#{addr}::addr_aggregator::CreateAddrAggregatorEventSet", "create_addr_aggregator_events")
# 这个函数可以拿到 Event 结果.

Result:

iex(13)> Aptos.get_events(client, addr, "#{addr}::addr_aggregator::CreateAddrAggregatorEventSet", "create_addr_aggregator_events")
{:ok, []}

生成 payload

payload = Aptos.call_function(f, [], [1, "testAcct"])

提交交易:

Aptos.submit_txn_with_auto_acct_updating(client, acct, payload)
# 方法 0x01:自动更新 acct 的信息
# Aptos.submit_txn(client, acct, payload)
# 方法 0x02:不自动更新 acct 的信息

执行结果:

iex(15)> Aptos.submit_txn_with_auto_acct_updating(client, acct, payload)
{:ok,
 %{
   expiration_timestamp_secs: "1679451173",
   gas_unit_price: "1000",
   hash: "0x931c2821df3e6c9c40bf00d5ed7e20aa1172a053d3c3d658a9f7bd31f17d91f6",
   max_gas_amount: "2000",
   payload: %{
     arguments: ["1", "testAcct"],
     function: "0x6195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46::init::init",
     type: "entry_function_payload",
     type_arguments: []
   },
   sender: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
   sequence_number: "0",
   signature: %{
     public_key: "0x361c4395cc87cf951dc5f879bdf2c2f91df3078c9a2ee4b5bf9892243a24a5fb",
     signature: "0x94f9cbf17c5095e76ea30a88d6683c9951fbfa3b1e261ca6b4722fac985946dcc0f5e7a8c03e6b322f39b102874484b620cf0943c672eadd4fd9b3505e65f804",
     type: "ed25519_signature"
   }
 }}

在浏览器上查看,交易执行成功:

640 (1).png

我们也可以通过check_tx_res_by_hash查看:

Aptos.check_tx_res_by_hash(client, hash) # return true or false

我们同样可以将call_fun_init的过程封装为一个函数:

  def call_func_init(client, acct, contract_addr,  did_type, description) do
    {:ok, f} = gen_func_init(contract_addr)
    payload = Aptos.call_function(f, [], [did_type, description])
    {:ok, %{hash: hash} = tx} = Aptos.submit_txn_with_auto_acct_updating(client, acct, payload)
    Process.sleep(2000)  # 用 2 秒等待交易成功
    res = Aptos.check_tx_res_by_hash(client, hash)
    %{res: res, tx: tx}
  end

  def gen_func_init(contract_addr) do
    init_func_str = "#{contract_addr}::init::init(u64, string)"
    ~a"#{init_func_str}"
  end

执行结果:

iex(22)> Web3MoveExExample.call_func_init(client, acct, addr, 1, "test Acct")
%{
  res: true,
  tx: %{
    expiration_timestamp_secs: "1679475296",
    gas_unit_price: "1000",
    hash: "0x73687a7e4c953f3cf13a768fe03560a61c06615fa8c089888f23cd3ccd8dc6e8",
    max_gas_amount: "2000",
    payload: %{
      arguments: ["1", "test Acct"],
      function: "0x6195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46::init::init",
      type: "entry_function_payload",
      type_arguments: []
    },
    sender: "0xc193cd62bab00790d40265505ce894552c14a3693aca9bc2310ee0ecdc53780b",
    sequence_number: "0",
    signature: %{
      public_key: "0x6bfa0d62dd63ea8a4291ffec10fc448ab554188d7765a9faf1b0992dbb199c38",
      signature: "0xc8a9d4368a0cc2daff3add7162745990d3bd9c33ec6f1112b5dfe45cdd25d4fdf5d19a361048b67081e3ce9c242c93266af4736d8c86541906e08c2ef387ef05",
      type: "ed25519_signature"
    }
  }
}

此时再次执行 get_events,会发现 events 成功生成:

iex(16)> Aptos.get_events(client, addr, "#{addr}::addr_aggregator::CreateAddrAggregatorEventSet", "create_addr_aggregator_events")
{:ok,
 [
   %{
     data: %{
       description: "testAcct",
       key_addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
       type: "1"
     },
     guid: %{
       account_address: "0x6195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46",
       creation_number: "4"
     },
     sequence_number: "0",
     type: "0x6195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46::addr_aggregator::CreateAddrAggregatorEvent",
     version: "473098605"
   }
 ]}

0x04 查看资源

打开浏览器访问:

https\://explorer.aptoslabs.com/account/0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f/resources

我们会发现增加了两个资源。

640 (2).png

image-20230322101914974

这个资源我们同样可以通过 web3_move_ex获取到:

Aptos.get_resource(client, account.address_hex, "#{addr}::addr_aggregator::AddrAggregator")

结果:

iex(20)> Aptos.get_resource(client, "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f", "#{addr}::addr_aggregator::AddrAggregator")
{:ok,
 %{
   data: %{
     add_addr_events: %{
       counter: "0",
       guid: %{
         id: %{
           addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
           creation_num: "4"
         }
       }
     },
     addr_infos_map: %{
       handle: "0xbae0b5ae8c373db15ca2f71a18f92ed3ed363e5730cf3f8a90791c04ff6908da"
     },
     addrs: [],
     delete_addr_events: %{
       counter: "0",
       guid: %{
         id: %{
           addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
           creation_num: "7"
         }
       }
     },
     description: "testAcct",
     key_addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
     max_id: "0",
     modified_counter: "0",
     type: "1",
     update_addr_events: %{
       counter: "0",
       guid: %{
         id: %{
           addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
           creation_num: "6"
         }
       }
     },
     update_addr_signature_events: %{
       counter: "0",
       guid: %{
         id: %{
           addr: "0xedf8dcb761e7ee7884e5a94d1f9b330f7a3ed09317bebe163738c31dc67e446f",
           creation_num: "5"
         }
       }
     }
   },
   type: "0x6195d43edde4b1cd3a96f7838686b9b12b51023cd388dfb21f123b350f4ec46::addr_aggregator::AddrAggregator"
 }}

前文链接:

Sui 链上数据查询 | Move dApp 极速入门(拾柒)\

SUI 合约测试攻略 | Move dApp 极速入门(拾陆)\

Sui 数据类型详解 | Move dApp 极速入门(十五)\

Airdropper Contract in Aptos | Move dApp 极速入门(拾肆)\

Sandwich合约案例实践 | Move dApp 极速入门(拾叁)\

Sui 极速上手 | Move dApp 极速入门(拾贰)

Move 高阶语法 | 共学课优秀笔记\

Move 基础语法 | 共学课优秀学习笔记

scaffold-aptos 脚手架 | Move dApp 极速入门(拾壹)

Aptos NFT 发行指南 | Move dApp 极速入门(十)

对 DID Document 的思考 | Move dApp 极速入门(九)\

DID中地址聚合器的实现 | Move dApp 极速入门(八)

Aptos 中的智能合约形式化验证 | Move dApp 极速入门(七)

Aptos CLI使用指南与REPL设计建议 | Move dApp 极速入门(六)\

实现一套 DID 之总体设计 | Move dApp 极速入门(五)\

合约数据类型综述 | Move dApp 极速入门(四)\

操作资源 | Move dApp极速入门(三)\

第一个 Move dApp | Move dApp极速入门(二)\

Hello Move | Move dApp极速入门(一)

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
李大狗
李大狗
0x73c7...6A1d
面向炫酷编程