搭建本地测试网
学习材料
https://aptos.dev/zh/build/cli/running-a-local-network
下载及编译
# 下载源码
$ git@github.com:aptos-labs/aptos-core.git
# 安装依赖
$ ./dev_setup.sh
# 编译
$ cargo build --release
# 查看版本
$ ./target/release/aptos -V
aptos 4.1.0
启动本地网络
$ ./target/release/aptos node run-local-testnet --with-indexer-api
Image postgres:14.11 not found, pulling it now...
Image hasura/graphql-engine:v2.40.2-ce not found, pulling it now...
Readiness endpoint: http://127.0.0.1:8070/
Indexer API is starting, please wait...
Node API is starting, please wait...
Faucet is starting, please wait...
Transaction stream is starting, please wait...
Postgres is starting, please wait...
Completed generating configuration:
Log file: "/root/.aptos/testnet/validator.log"
Test dir: "/root/.aptos/testnet"
Aptos root key path: "/root/.aptos/testnet/mint.key"
Waypoint: 0:2c7523c0f215144d249ac1d115cf583060f02309d54bf6eaf36b391579f2804d
ChainId: 4
REST API endpoint: http://127.0.0.1:8080
Metrics endpoint: http://127.0.0.1:9101/metrics
Aptosnet fullnode network endpoint: /ip4/0.0.0.0/tcp/6181
Indexer gRPC node stream endpoint: 127.0.0.1:50051
Aptos is running, press ctrl-c to exit
Node API is ready. Endpoint: http://127.0.0.1:8080/
Postgres is ready. Endpoint: postgres://postgres@127.0.0.1:5433/local_testnet
Transaction stream is ready. Endpoint: http://127.0.0.1:50051/
Faucet is ready. Endpoint: http://127.0.0.1:8081/
Indexer API is ready. Endpoint: http://127.0.0.1:8090/
Applying post startup steps...
Setup is complete, you can now use the localnet!
运行服务
当本地网络启动成功后,将会启动以下服务:
服务 | 描述 | 端点 |
---|---|---|
节点API | 直接在节点上运行的 REST API。它支持核心写功能,如交易提交,以及有限的读功能,如读取帐户资源或 Move 模块信息 | http://127.0.0.1:8080/ |
索引器API | 提供对索引区块链数据丰富读取访问的 GraphQL API。通过点击 URL,可以访问 Hasura 控制台,一个帮助您查询索引器 GraphQL API 的 Web UI | http://127.0.0.1:8090/ |
交易流服务 | 索引器 API 使用的 gRPC 交易流 | http://127.0.0.1:50051/ |
Postgres | 索引器处理器写入的数据库。索引器 API 从此数据库读取。 | postgres://postgres@127.0.0.1:5433/local_testnet |
水龙头 | 可用于在本地网络中为帐户提供资金的服务 | http://127.0.0.1:8081/ |
重置本地网络
当需要将本地网络重置回初始状态时执行该命令,以应对:
- 对Move模块进行了不能向后兼容的更改
- 正在构建一个自定义索引处理器,希望使用一个全新的网络进行索引
- 想清除所有链上状态,例如账户、对象等
$ ./target/release/aptos node run-local-testnet --force-restart
Are you sure you want to delete the existing localnet data? [yes/no] >
yes
Readiness endpoint: http://127.0.0.1:8070/
Node API is starting, please wait...
Transaction stream is starting, please wait...
Faucet is starting, please wait...
Completed generating configuration:
Log file: "/root/.aptos/testnet/validator.log"
Test dir: "/root/.aptos/testnet"
Aptos root key path: "/root/.aptos/testnet/mint.key"
Waypoint: 0:0cb18010ecdfabbfb2e4d0faa91f49e5e1dcb6ef5d106e8ad86032fd0eec7b73
ChainId: 4
REST API endpoint: http://127.0.0.1:8080
Metrics endpoint: http://127.0.0.1:9101/metrics
Aptosnet fullnode network endpoint: /ip4/0.0.0.0/tcp/6181
Indexer gRPC node stream endpoint: 127.0.0.1:50051
Aptos is running, press ctrl-c to exit
Node API is ready. Endpoint: http://127.0.0.1:8080/
Transaction stream is ready. Endpoint: http://127.0.0.1:50051/
Faucet is ready. Endpoint: http://127.0.0.1:8081/
Applying post startup steps...
Setup is complete, you can now use the localnet!
API文档
http://127.0.0.1:8080/v1/spec#/operations/get_ledger_info
开发第一个Aptos Move合约:Todo list
工程创建
$ mkdir aptos_todo_list && cd aptos_todo_list
$ aptos move init --name aptos_todo_list
{
"Result": "Success"
}
合约开发
代码来自:https://learn.aptoslabs.com/zh/code-examples/todo-list
module todo_list_addr::todo_list {
use std::bcs;
use std::signer;
use std::vector;
use std::string::String;
use aptos_std::string_utils;
use aptos_framework::object;
/// Todo list does not exist
const E_TODO_LIST_DOSE_NOT_EXIST: u64 = 1;
/// Todo does not exist
const E_TODO_DOSE_NOT_EXIST: u64 = 2;
/// Todo is already completed
const E_TODO_ALREADY_COMPLETED: u64 = 3;
struct UserTodoListCounter has key {
counter: u64,
}
struct TodoList has key {
owner: address,
todos: vector<Todo>,
}
struct Todo has store, drop, copy {
content: String,
completed: bool,
}
// This function is only called once when the module is published for the first time.
// init_module is optional, you can also have an entry function as the initializer.
fun init_module(_module_publisher: &signer) {
// nothing to do here
}
// ======================== Write functions ========================
public entry fun create_todo_list(sender: &signer) acquires UserTodoListCounter {
let sender_address = signer::address_of(sender);
let counter = if (exists<UserTodoListCounter>(sender_address)) {
let counter = borrow_global<UserTodoListCounter>(sender_address);
counter.counter
} else {
let counter = UserTodoListCounter { counter: 0 };
// store the UserTodoListCounter resource directly under the sender
move_to(sender, counter);
0
};
// create a new object to hold the todo list, use the contract_addr_counter as seed
let obj_holds_todo_list = object::create_named_object(
sender,
construct_todo_list_object_seed(counter),
);
let obj_signer = object::generate_signer(&obj_holds_todo_list);
let todo_list = TodoList {
owner: sender_address,
todos: vector::empty(),
};
// store the TodoList resource under the newly created object
move_to(&obj_signer, todo_list);
// increment the counter
let counter = borrow_global_mut<UserTodoListCounter>(sender_address);
counter.counter = counter.counter + 1;
}
public entry fun create_todo(sender: &signer, todo_list_idx: u64, content: String) acquires TodoList {
let sender_address = signer::address_of(sender);
let todo_list_obj_addr = object::create_object_address(
&sender_address,
construct_todo_list_object_seed(todo_list_idx)
);
assert_user_has_todo_list(todo_list_obj_addr);
let todo_list = borrow_global_mut<TodoList>(todo_list_obj_addr);
let new_todo = Todo {
content,
completed: false
};
vector::push_back(&mut todo_list.todos, new_todo);
}
public entry fun complete_todo(sender: &signer, todo_list_idx: u64, todo_idx: u64) acquires TodoList {
let sender_address = signer::address_of(sender);
let todo_list_obj_addr = object::create_object_address(
&sender_address,
construct_todo_list_object_seed(todo_list_idx)
);
assert_user_has_todo_list(todo_list_obj_addr);
let todo_list = borrow_global_mut<TodoList>(todo_list_obj_addr);
assert_user_has_given_todo(todo_list, todo_idx);
let todo_record = vector::borrow_mut(&mut todo_list.todos, todo_idx);
assert!(todo_record.completed == false, E_TODO_ALREADY_COMPLETED);
todo_record.completed = true;
}
// ======================== Read Functions ========================
// Get how many todo lists the sender has, return 0 if the sender has none.
#[view]
public fun get_todo_list_counter(sender: address): u64 acquires UserTodoListCounter {
if (exists<UserTodoListCounter>(sender)) {
let counter = borrow_global<UserTodoListCounter>(sender);
counter.counter
} else {
0
}
}
#[view]
public fun get_todo_list_obj_addr(sender: address, todo_list_idx: u64): address {
object::create_object_address(&sender, construct_todo_list_object_seed(todo_list_idx))
}
#[view]
public fun has_todo_list(sender: address, todo_list_idx: u64): bool {
let todo_list_obj_addr = get_todo_list_obj_addr(sender, todo_list_idx);
exists<TodoList>(todo_list_obj_addr)
}
#[view]
public fun get_todo_list(sender: address, todo_list_idx: u64): (address, u64) acquires TodoList {
let todo_list_obj_addr = get_todo_list_obj_addr(sender, todo_list_idx);
assert_user_has_todo_list(todo_list_obj_addr);
let todo_list = borrow_global<TodoList>(todo_list_obj_addr);
(todo_list.owner, vector::length(&todo_list.todos))
}
#[view]
public fun get_todo_list_by_todo_list_obj_addr(todo_list_obj_addr: address): (address, u64) acquires TodoList {
let todo_list = borrow_global<TodoList>(todo_list_obj_addr);
(todo_list.owner, vector::length(&todo_list.todos))
}
#[view]
public fun get_todo(sender: address, todo_list_idx: u64, todo_idx: u64): (String, bool) acquires TodoList {
let todo_list_obj_addr = get_todo_list_obj_addr(sender, todo_list_idx);
assert_user_has_todo_list(todo_list_obj_addr);
let todo_list = borrow_global<TodoList>(todo_list_obj_addr);
assert!(todo_idx < vector::length(&todo_list.todos), E_TODO_DOSE_NOT_EXIST);
let todo_record = vector::borrow(&todo_list.todos, todo_idx);
(todo_record.content, todo_record.completed)
}
// ======================== Helper Functions ========================
fun assert_user_has_todo_list(user_addr: address) {
assert!(
exists<TodoList>(user_addr),
E_TODO_LIST_DOSE_NOT_EXIST
);
}
fun assert_user_has_given_todo(todo_list: &TodoList, todo_id: u64) {
assert!(
todo_id < vector::length(&todo_list.todos),
E_TODO_DOSE_NOT_EXIST
);
}
fun get_todo_list_obj(sender: address, todo_list_idx: u64): object::Object<TodoList> {
let addr = get_todo_list_obj_addr(sender, todo_list_idx);
object::address_to_object(addr)
}
fun construct_todo_list_object_seed(counter: u64): vector<u8> {
// The seed must be unique per todo list creator
//Wwe add contract address as part of the seed so seed from 2 todo list contract for same user would be different
bcs::to_bytes(&string_utils::format2(&b"{}_{}", @todo_list_addr, counter))
}
// ======================== Unit Tests ========================
#[test_only]
use std::string;
#[test_only]
use aptos_framework::account;
#[test_only]
use aptos_std::debug;
#[test(admin = @0x100)]
public entry fun test_end_to_end(admin: signer) acquires TodoList, UserTodoListCounter {
let admin_addr = signer::address_of(&admin);
let todo_list_idx = get_todo_list_counter(admin_addr);
assert!(todo_list_idx == 0, 1);
account::create_account_for_test(admin_addr);
assert!(!has_todo_list(admin_addr, todo_list_idx), 2);
create_todo_list(&admin);
assert!(get_todo_list_counter(admin_addr) == 1, 3);
assert!(has_todo_list(admin_addr, todo_list_idx), 4);
create_todo(&admin, todo_list_idx, string::utf8(b"New Todo"));
let (todo_list_owner, todo_list_length) = get_todo_list(admin_addr, todo_list_idx);
debug::print(&string_utils::format1(&b"todo_list_owner: {}", todo_list_owner));
debug::print(&string_utils::format1(&b"todo_list_length: {}", todo_list_length));
assert!(todo_list_owner == admin_addr, 5);
assert!(todo_list_length == 1, 6);
let (todo_content, todo_completed) = get_todo(admin_addr, todo_list_idx, 0);
debug::print(&string_utils::format1(&b"todo_content: {}", todo_content));
debug::print(&string_utils::format1(&b"todo_completed: {}", todo_completed));
assert!(!todo_completed, 7);
assert!(todo_content == string::utf8(b"New Todo"), 8);
complete_todo(&admin, todo_list_idx, 0);
let (_todo_content, todo_completed) = get_todo(admin_addr, todo_list_idx, 0);
debug::print(&string_utils::format1(&b"todo_completed: {}", todo_completed));
assert!(todo_completed, 9);
}
#[test(admin = @0x100)]
public entry fun test_end_to_end_2_todo_lists(admin: signer) acquires TodoList, UserTodoListCounter {
let admin_addr = signer::address_of(&admin);
create_todo_list(&admin);
let todo_list_1_idx = get_todo_list_counter(admin_addr) - 1;
create_todo_list(&admin);
let todo_list_2_idx = get_todo_list_counter(admin_addr) - 1;
create_todo(&admin, todo_list_1_idx, string::utf8(b"New Todo"));
let (todo_list_owner, todo_list_length) = get_todo_list(admin_addr, todo_list_1_idx);
assert!(todo_list_owner == admin_addr, 1);
assert!(todo_list_length == 1, 2);
let (todo_content, todo_completed) = get_todo(admin_addr, todo_list_1_idx, 0);
assert!(!todo_completed, 3);
assert!(todo_content == string::utf8(b"New Todo"), 4);
complete_todo(&admin, todo_list_1_idx, 0);
let (_todo_content, todo_completed) = get_todo(admin_addr, todo_list_1_idx, 0);
assert!(todo_completed, 5);
create_todo(&admin, todo_list_2_idx, string::utf8(b"New Todo"));
let (todo_list_owner, todo_list_length) = get_todo_list(admin_addr, todo_list_2_idx);
assert!(todo_list_owner == admin_addr, 6);
assert!(todo_list_length == 1, 7);
let (todo_content, todo_completed) = get_todo(admin_addr, todo_list_2_idx, 0);
assert!(!todo_completed, 8);
assert!(todo_content == string::utf8(b"New Todo"), 9);
complete_todo(&admin, todo_list_2_idx, 0);
let (_todo_content, todo_completed) = get_todo(admin_addr, todo_list_2_idx, 0);
assert!(todo_completed, 10);
}
#[test(admin = @0x100)]
#[expected_failure(abort_code = E_TODO_LIST_DOSE_NOT_EXIST, location = Self)]
public entry fun test_todo_list_does_not_exist(admin: signer) acquires TodoList, UserTodoListCounter {
let admin_addr = signer::address_of(&admin);
account::create_account_for_test(admin_addr);
let todo_list_idx = get_todo_list_counter(admin_addr);
// account cannot create todo on a todo list (that does not exist
create_todo(&admin, todo_list_idx, string::utf8(b"New Todo"));
}
#[test(admin = @0x100)]
#[expected_failure(abort_code = E_TODO_DOSE_NOT_EXIST, location = Self)]
public entry fun test_todo_does_not_exist(admin: signer) acquires TodoList, UserTodoListCounter {
let admin_addr = signer::address_of(&admin);
account::create_account_for_test(admin_addr);
let todo_list_idx = get_todo_list_counter(admin_addr);
create_todo_list(&admin);
// can not complete todo that does not exist
complete_todo(&admin, todo_list_idx, 1);
}
#[test(admin = @0x100)]
#[expected_failure(abort_code = E_TODO_ALREADY_COMPLETED, location = Self)]
public entry fun test_todo_already_completed(admin: signer) acquires TodoList, UserTodoListCounter {
let admin_addr = signer::address_of(&admin);
account::create_account_for_test(admin_addr);
let todo_list_idx = get_todo_list_counter(admin_addr);
create_todo_list(&admin);
create_todo(&admin, todo_list_idx, string::utf8(b"New Todo"));
complete_todo(&admin, todo_list_idx, 0);
// can not complete todo that is already completed
complete_todo(&admin, todo_list_idx, 0);
}
}
环境初始化
$ aptos init
Configuring for profile default
Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
testnet
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
No key given, generating key...
Account 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022 doesn't exist, creating it and funding it with 100000000 Octas
Account 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022 funded successfully
---
Aptos CLI is now set up for account 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022 as profile default!
See the account here: https://explorer.aptoslabs.com/account/0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022?network=testnet
Run `aptos --help` for more information about commands
{
"Result": "Success"
}
注:生成的地址
0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022
就是账户地址,别名是default
执行上述命令,将在当前工程目录生成以下文件:
$ cat .aptos/config.yaml
---
profiles:
default:
network: Testnet
private_key: "0x2a88d0....0b45"
public_key: "0xd6a31c....27ea6"
account: cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022
rest_url: "https://fullnode.testnet.aptoslabs.com"
faucet_url: "https://faucet.testnet.aptoslabs.com"
领水
$ aptos account fund-with-faucet --account default
# 等价命令
$ aptos account fund-with-faucet --account 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022
{
"Result": "Added 100000000 Octas to account 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022"
}
合约编译
$ aptos move build
# 等价命令
$ aptos move compile
Compiling, may take a little while to download git dependencies...
UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING aptos_todo_list
{
"Result": [
"cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list"
]
}
注:如果Move.toml中未定义address,需使用命令:
$ aptos move compile --named-addresses todo_list_addr=default
执行单测
$ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING aptos_todo_list
Running Move unit tests
[debug] "todo_list_owner: @0x100"
[debug] "todo_list_length: 1"
[debug] "todo_content: \"New Todo\""
[debug] "todo_completed: false"
[debug] "todo_completed: true"
[ PASS ] 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list::test_end_to_end
[ PASS ] 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list::test_end_to_end_2_todo_lists
[ PASS ] 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list::test_todo_already_completed
[ PASS ] 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list::test_todo_does_not_exist
[ PASS ] 0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list::test_todo_list_does_not_exist
Test result: OK. Total tests: 5; passed: 5; failed: 0
{
"Result": "Success"
}
合约部署
$ aptos move publish
Compiling, may take a little while to download git dependencies...
UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING aptos_todo_list
package size 4576 bytes
Do you want to submit a transaction for a range of [274000 - 411000] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x0b7b5b75a81040352741c1342db44a57faea5b8492f2248bab54577b6fd146a3?network=testnet
{
"Result": {
"transaction_hash": "0x0b7b5b75a81040352741c1342db44a57faea5b8492f2248bab54577b6fd146a3",
"gas_used": 2740,
"gas_unit_price": 100,
"sender": "cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022",
"sequence_number": 0,
"success": true,
"timestamp_us": 1725804736732089,
"version": 5954581859,
"vm_status": "Executed successfully"
}
}
合约调用
create_todo_list
$ aptos move run \
--function-id 'default::todo_list::create_todo_list'
Do you want to submit a transaction for a range of [138600 - 207900] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x4aad67f5976cb875e7aa4a10f6210fca79dbacaaccc004a3184eafe7b72a5fe2?network=testnet
{
"Result": {
"transaction_hash": "0x4aad67f5976cb875e7aa4a10f6210fca79dbacaaccc004a3184eafe7b72a5fe2",
"gas_used": 1386,
"gas_unit_price": 100,
"sender": "cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022",
"sequence_number": 3,
"success": true,
"timestamp_us": 1725807418268333,
"version": 5954728316,
"vm_status": "Executed successfully"
}
}
create_todo
$ aptos move run \
--function-id 'default::todo_list::create_todo' \
--args 'u64:0' 'string:study'
Do you want to submit a transaction for a range of [800 - 1200] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x0559761e6e0e537832a7293a9afc02779a501534052a5ba1b8632c1804cbe6d3?network=testnet
{
"Result": {
"transaction_hash": "0x0559761e6e0e537832a7293a9afc02779a501534052a5ba1b8632c1804cbe6d3",
"gas_used": 8,
"gas_unit_price": 100,
"sender": "cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022",
"sequence_number": 4,
"success": true,
"timestamp_us": 1725807739852836,
"version": 5954745955,
"vm_status": "Executed successfully"
}
}
complete_todo
$ aptos move run \
--function-id 'default::todo_list::complete_todo' \
--args 'u64:0' 'u64:0'
Do you want to submit a transaction for a range of [600 - 900] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x27bddde7703199720412a67854e4f04bac62c0213b1836f7bb289625ef93f503?network=testnet
{
"Result": {
"transaction_hash": "0x27bddde7703199720412a67854e4f04bac62c0213b1836f7bb289625ef93f503",
"gas_used": 6,
"gas_unit_price": 100,
"sender": "cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022",
"sequence_number": 5,
"success": true,
"timestamp_us": 1725807879910254,
"version": 5954753634,
"vm_status": "Executed successfully"
}
}
学习材料
https://aptos.dev/en/build/guides/first-move-module
TypeScript SDK Quickstart
学习材料
https://aptos.dev/en/build/sdks/ts-sdk/quickstart
工程初始化
$ mkdir ts_sdk_quickstart && cd ts_sdk_quickstart
$ pnpm init && \
pnpm add -D typescript @types/node ts-node && \
npx tsc --init && \
mkdir src && \
echo 'async function example() { console.log("Running example!")}; example()' > src/quickstart.ts
- 测试
$ pnpx ts-node src/quickstart.ts
Running example!
安装 Aptos TS SDK
$ pnpm add @aptos-labs/ts-sdk
$ cat package.json
{
"name": "ts_sdk_quickstart",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^22.5.4",
"ts-node": "^10.9.2",
"typescript": "^5.5.4"
},
"dependencies": {
"@aptos-labs/ts-sdk": "^1.27.1"
}
}
获取用户创建模块信息
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
async function example() {
const config = new AptosConfig({ network: Network.TESTNET });
const aptos = new Aptos(config);
const modules = await aptos.getAccountModules({
accountAddress:
"0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022",
});
console.log(JSON.stringify(modules, null, 2));
}
example();
创建账号并领水
import {
Account,
Aptos,
AptosConfig,
Network,
AccountAddress,
} from "@aptos-labs/ts-sdk";
const APTOS_COIN = "0x1::aptos_coin::AptosCoin";
const COIN_STORE = `0x1::coin::CoinStore<${APTOS_COIN}>`;
const ALICE_INITIAL_BALANCE = 100_000_000;
const BOB_INITIAL_BALANCE = 100;
async function createAndFundAccount(aptos: Aptos, initialBalance: number) {
const account: Account = Account.generate();
await aptos.fundAccount({
accountAddress: account.accountAddress,
amount: initialBalance,
});
return account;
}
async function getAccountBalance(aptos: Aptos, accountAddress: AccountAddress) {
const accountBalance = await aptos.getAccountResource({
accountAddress: accountAddress,
resourceType: COIN_STORE,
});
return Number(accountBalance.coin.value);
}
async function example() {
const config = new AptosConfig({ network: Network.TESTNET });
const aptos = new Aptos(config);
const alice = await createAndFundAccount(aptos, ALICE_INITIAL_BALANCE);
const bob = await createAndFundAccount(aptos, BOB_INITIAL_BALANCE);
console.log(`alice account: ${alice.accountAddress}`);
console.log(`bob account: ${bob.accountAddress}`);
console.log("\n=== Balances ===");
const aliceBalance = await getAccountBalance(aptos, alice.accountAddress);
console.log(`Alice's balance is: ${aliceBalance}`);
const bobBalance = await getAccountBalance(aptos, bob.accountAddress);
console.log(`Bob's balance is: ${bobBalance}`);
}
example();
// Output:
// alice account: 0x7c36a18406f432fc752df9542d95c08ae299d5a8175614381c7778eafe0954e6
// bob account: 0xc6705ad2cc5435103e59dc9144d5c1ea7b0d99d535d5a4a10bc1c0b32cf52337
// === Balances ===
// Alice's balance is: 100000000
// Bob's balance is: 100
Aptos DApp 开发入门
学习材料
https://aptos.dev/en/build/create-aptos-dapp
执行创建命令
$ pnpx create-aptos-dapp@latest
### ######## ######## ####### ######
## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ##
## ## ######## ## ## ## ######
######### ## ## ## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ####### ######
Welcome to the create-aptos-dapp wizard 🌐
✔ Enter a new project name … js-aptos-dapp
? Choose how to start › - Use arrow-keys. Return to submit.
❯ Boilerplate Template - A Boilerplate template to start an Aptos dapp with
NFT minting dapp
Token minting dapp
Token staking dapp
? Choose your network › - You can change this later
Mainnet
❯ Testnet
Devnet
✔ Help us improve create-aptos-dapp by collection anonymous data … no
✔ Do you want to make any changes to your selections? (Default is No) … no
✔ Scaffolding project in /root/Study/MDBook/intensive-colearning-aptos/src/codes/hello_aptos_dapp/js-aptos-dapp
Need to install dependencies, this might take a while - in the meantime:
📖 Visit the Boilerplate Template docs: https://aptos.dev/en/build/create-aptos-dapp/templates/boilerplate
⠋ Installing the dependencies...
✔ Scaffolding project in /root/Study/MDBook/intensive-colearning-aptos/src/codes/hello_aptos_dapp/js-aptos-dapp
Success! You're ready to start building your dapp on Aptos.
Next steps:
Run: cd js-aptos-dapp
Open in your favorite IDE && follow the README file
- 创建的
dapp
模板工程目录结构
js-aptos-dapp/
├── LICENSE
├── README.md
├── components.json
├── contract —— 合约代码
├── frontend —— 前端代码
├── index.html
├── package.json
├── postcss.config.js
├── public —— 静态资源
├── scripts —— 脚本代码
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite-env.d.ts
└── vite.config.ts
初始化账户
$ aptos init
Configuring for profile default
Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
testnet
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
No key given, generating key...
Account 0x3bd29c1df0312353e7cc1598d019c0716bee9dc10be949f8182856468c570f7d doesn't exist, creating it and funding it with 100000000 Octas
Account 0x3bd29c1df0312353e7cc1598d019c0716bee9dc10be949f8182856468c570f7d funded successfully
---
Aptos CLI is now set up for account 0x3bd29c1df0312353e7cc1598d019c0716bee9dc10be949f8182856468c570f7d as profile default!
See the account here: https://explorer.aptoslabs.com/account/0x3bd29c1df0312353e7cc1598d019c0716bee9dc10be949f8182856468c570f7d?network=testnet
Run `aptos --help` for more information about commands
{
"Result": "Success"
}
部署合约
$ aptos move publish --named-addresses message_board_addr=default
Compiling, may take a little while to download git dependencies...
UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING MessageBoard
package size 2084 bytes
Do you want to submit a transaction for a range of [268700 - 403000] Octas at a gas unit price of 100 Octas? [yes/no] >
Do you want to submit a transaction for a range of [268700 - 403000] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x112a06807e1efb3c26972b017d4b9c1ee2eba94fc5868093427206babffa968f?network=testnet
{
"Result": {
"transaction_hash": "0x112a06807e1efb3c26972b017d4b9c1ee2eba94fc5868093427206babffa968f",
"gas_used": 2687,
"gas_unit_price": 100,
"sender": "3bd29c1df0312353e7cc1598d019c0716bee9dc10be949f8182856468c570f7d",
"sequence_number": 0,
"success": true,
"timestamp_us": 1725967632715580,
"version": 5963473442,
"vm_status": "Executed successfully"
}
}
添加地址到.env
文件
PROJECT_NAME=js-aptos-dapp
VITE_APP_NETWORK=testnet
VITE_MODULE_ADDRESS=0x3bd29c1df0312353e7cc1598d019c0716bee9dc10be949f8182856468c570f7d
启动服务
$ npm run dev
页面交互
官方 Todolist 前端交互体验
发布官方Todolist合约
初始化账户
$ aptos init
Configuring for profile default
Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
testnet
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
No key given, generating key...
Account 0x09222b2046de179884197d7bba84656e16876a7630aec3c523a4d2491e909433 doesn't exist, creating it and funding it with 100000000 Octas
Account 0x09222b2046de179884197d7bba84656e16876a7630aec3c523a4d2491e909433 funded successfully
---
Aptos CLI is now set up for account 0x09222b2046de179884197d7bba84656e16876a7630aec3c523a4d2491e909433 as profile default!
See the account here: https://explorer.aptoslabs.com/account/0x09222b2046de179884197d7bba84656e16876a7630aec3c523a4d2491e909433?network=testnet
Run `aptos --help` for more information about commands
{
"Result": "Success"
}
发布合约
$ aptos move publish --named-addresses todolist_addr=default
Compiling, may take a little while to download git dependencies...
UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING my_todo_list
Do you want to submit a transaction for a range of [190300 - 285400] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x18f2969ac50c1ad5b0c0e70bd666db729f71d62d2d27d88ac2bf28b918b34d13?network=testnet
{
"Result": {
"transaction_hash": "0x18f2969ac50c1ad5b0c0e70bd666db729f71d62d2d27d88ac2bf28b918b34d13",
"gas_used": 1903,
"gas_unit_price": 100,
"sender": "09222b2046de179884197d7bba84656e16876a7630aec3c523a4d2491e909433",
"sequence_number": 0,
"success": true,
"timestamp_us": 1726052998054573,
"version": 5968275918,
"vm_status": "Executed successfully"
}
}
修改前端代码
- 修改前
export const aptos = new Aptos();
// change this to be your module account address
export const moduleAddress = "0xcbddf398841353776903dbab2fdaefc54f181d07e114ae818b1a67af28d1b018";
- 修改后
export const aptos = new Aptos(new AptosConfig({ network: Network.TESTNET }));
// change this to be your module account address
export const moduleAddress =
"0x09222b2046de179884197d7bba84656e16876a7630aec3c523a4d2491e909433";
启动前端服务
$ pnpm i
$ pnpm start
功能交互
创建新的Todolist
创建新的待办
完成待办

TypeScript SDK 基本使用
项目创建
$ mkdir ts_sdk_basic_usage && cd ts_sdk_basic_usage
$ pnpm init
$ pnpm add @aptos-labs/ts-sdk
Account
import {
Account,
Ed25519PrivateKey,
SigningSchemeInput,
} from "@aptos-labs/ts-sdk";
function createAccount() {
const account1 = Account.generate(); // defaults to Legacy Ed25519
console.log(`account1: ${account1.accountAddress.toString()}`);
account1.privateKey.toString;
const account2 = Account.generate({
scheme: SigningSchemeInput.Secp256k1Ecdsa,
}); // Single Sender Secp256k1
console.log(`account2: ${account2.accountAddress.toString()}`);
const account3 = Account.generate({
scheme: SigningSchemeInput.Ed25519,
legacy: false,
}); // Single Sender Ed25519
console.log(`account3: ${account3.accountAddress.toString()}`);
return account1;
}
function createAccountFromPrivateKey(privateKeyBytes: string) {
const privateKey = new Ed25519PrivateKey(privateKeyBytes);
const account = Account.fromPrivateKey({ privateKey });
console.log(
`account1 from private key: ${account.accountAddress.toString()}`
);
}
async function main() {
const account = createAccount();
createAccountFromPrivateKey(account.privateKey.toString());
}
main();
// OUTPUT:
// account1: 0x2d7b14974554446317f614737f1f3df32a285c48b44ee3f520d2885ad9ade31a
// account2: 0xd49f49ee44ade9a30dcded76f2b805d683ad9117613ccd95e38b30d586351dbf
// account3: 0xc04102d0a5fdb19ea0ba31c8d7215625a76b1b778167bf58297cdbec1b0cd8e6
// account1 from private key: 0x2d7b14974554446317f614737f1f3df32a285c48b44ee3f520d2885ad9ade31a
fetch data
import {
Account,
Aptos,
AptosConfig,
Ed25519PrivateKey,
Network,
SigningSchemeInput,
} from "@aptos-labs/ts-sdk";
async function fetch_data() {
const aptosConfig = new AptosConfig({ network: Network.TESTNET });
const aptos = new Aptos(aptosConfig);
const account = Account.generate();
console.log(`>>> create account: ${account.accountAddress.toString()}`);
const transaction = await aptos.fundAccount({
accountAddress: account.accountAddress,
amount: 100,
});
console.log(`\n>>> transaction: ${JSON.stringify(transaction)}`);
const fund = await aptos.getAccountInfo({
accountAddress: account.accountAddress,
});
console.log(`\n>>>fund: ${JSON.stringify(fund)}`);
const modules = await aptos.getAccountModules({
accountAddress: account.accountAddress,
});
console.log(`\n>>> modules: ${JSON.stringify(modules)}`);
const tokens = await aptos.getAccountOwnedTokens({
accountAddress: account.accountAddress,
});
console.log(`\n>>> tokens: ${JSON.stringify(tokens)}`);
type Coin = { coin: { value: string } };
const resource = await aptos.getAccountResource<Coin>({
accountAddress: account.accountAddress,
resourceType: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>",
});
console.log(`\n>>> resource: ${JSON.stringify(resource)}`);
const value = resource.coin.value;
console.log(`\n>>> coin value: ${value}`);
}
async function main() {
fetch_data();
}
main();
// >>> create account: 0x06a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d
// >>> transaction: {"version":"5974082853","hash":"0x3308cd348384fa5623986b2c6aa82cb93a4df3fb4d8d11fa21e7e18c07dc369c","state_change_hash":"0x9df9233fe8a13c6e790cf588b2c7160587d5ce0f33cd87e0b92434361dbe34eb","event_root_hash":"0x5efdc1806cd0bc1968a417db06bf204d175291443a0f20535b45ead9fb1f168a","state_checkpoint_hash":null,"gas_used":"1001","success":true,"vm_status":"Executed successfully","accumulator_root_hash":"0xedb82d4e1287e47350edc723dc470ccd41794b831d24ae35e409df205820c967","changes":[{"address":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","state_key_hash":"0x8ff336347df3a198a09afdaaad8c8434ded97110b4c398aa4ffcfb0d60c65e35","data":{"type":"0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>","data":{"coin":{"value":"100"},"deposit_events":{"counter":"1","guid":{"id":{"addr":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","creation_num":"2"}}},"frozen":false,"withdraw_events":{"counter":"0","guid":{"id":{"addr":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","creation_num":"3"}}}}},"type":"write_resource"},{"address":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","state_key_hash":"0x3f92d599ad51f3a459fb7dbc993208a7ac55aa8ff7b529ee318eb71d683d4b8f","data":{"type":"0x1::account::Account","data":{"authentication_key":"0x06a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","coin_register_events":{"counter":"1","guid":{"id":{"addr":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","creation_num":"0"}}},"guid_creation_num":"4","key_rotation_events":{"counter":"0","guid":{"id":{"addr":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","creation_num":"1"}}},"rotation_capability_offer":{"for":{"vec":[]}},"sequence_number":"0","signer_capability_offer":{"for":{"vec":[]}}}},"type":"write_resource"},{"address":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","state_key_hash":"0xc1b87f42046e685dfc675966f239376b4dad0bddb08c5d4710d87d631381be1d","data":{"type":"0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>","data":{"coin":{"value":"328418492900"},"deposit_events":{"counter":"2381638","guid":{"id":{"addr":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","creation_num":"2"}}},"frozen":false,"withdraw_events":{"counter":"2381630","guid":{"id":{"addr":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","creation_num":"3"}}}}},"type":"write_resource"},{"address":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","state_key_hash":"0xa64c3e06541e5b27ab82cec64706a40eb629a67a9218f13cd7459f5baa9978ff","data":{"type":"0x1::account::Account","data":{"authentication_key":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","coin_register_events":{"counter":"1","guid":{"id":{"addr":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","creation_num":"0"}}},"guid_creation_num":"4","key_rotation_events":{"counter":"0","guid":{"id":{"addr":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","creation_num":"1"}}},"rotation_capability_offer":{"for":{"vec":[]}},"sequence_number":"2381638","signer_capability_offer":{"for":{"vec":[]}}}},"type":"write_resource"},{"state_key_hash":"0x6e4b28d40f98a106a65163530924c0dcb40c1349d3aa915d108b4d6cfc1ddb19","handle":"0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca","key":"0x0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935","value":"0x4d784ea77b0cbd940100000000000000","data":null,"type":"write_table_item"}],"sender":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12","sequence_number":"2381637","max_gas_amount":"500000","gas_unit_price":"100","expiration_timestamp_secs":"1726153296","payload":{"code":{"bytecode":"0xa11ceb0b0500000008010008020804030c150421020523100733500883012006a30114000000010002000301050800030403010002060105010001070002000008000200010403060c050301050001060c01080001030d6170746f735f6163636f756e740a6170746f735f636f696e04636f696e067369676e65720a616464726573735f6f66094170746f73436f696e0762616c616e6365046d696e74087472616e7366657200000000000000000000000000000000000000000000000000000000000000010308a0860100000000000308ffffffffffffffff000001170a0011000c030a03380007010a02170700172304120a000b030a0207001611020b000b010b02110302","abi":{"name":"main","visibility":"public","is_entry":true,"is_view":false,"generic_type_params":[],"params":["&signer","address","u64"],"return":[]}},"type_arguments":[],"arguments":["0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","100"],"type":"script_payload"},"signature":{"public_key":"0x7a58e569925baaba11db29b72e2f4975a0262ec6f9502d50e3b1a5da1d85ae04","signature":"0xf9fe2ff5efe90ee8ec1f1b0117c58bc7b4e5202b385b1d044d60c3395625a16902a763298433ea4c66babf1c6bc618af0f06d6fb9ad977ecef12d25478905f0a","type":"ed25519_signature"},"events":[{"guid":{"creation_number":"2","account_address":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12"},"sequence_number":"2381637","type":"0x1::coin::DepositEvent","data":{"amount":"100100"}},{"guid":{"creation_number":"0","account_address":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d"},"sequence_number":"0","type":"0x1::account::CoinRegisterEvent","data":{"type_info":{"account_address":"0x1","module_name":"0x6170746f735f636f696e","struct_name":"0x4170746f73436f696e"}}},{"guid":{"creation_number":"3","account_address":"0x19e2c9d62d5d5cc16f0de87e7e05f5161f9e820932341e82740cdeed1ba63d12"},"sequence_number":"2381629","type":"0x1::coin::WithdrawEvent","data":{"amount":"100"}},{"guid":{"creation_number":"2","account_address":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d"},"sequence_number":"0","type":"0x1::coin::DepositEvent","data":{"amount":"100"}},{"guid":{"creation_number":"0","account_address":"0x0"},"sequence_number":"0","type":"0x1::transaction_fee::FeeStatement","data":{"execution_gas_units":"6","io_gas_units":"7","storage_fee_octas":"98800","storage_fee_refund_octas":"0","total_charge_gas_units":"1001"}}],"timestamp":"1726153281890208","type":"user_transaction"}
// >>>fund: {"sequence_number":"0","authentication_key":"0x06a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d"}
// >>> modules: []
// >>> tokens: []
// >>> resource: {"coin":{"value":"100"},"deposit_events":{"counter":"1","guid":{"id":{"addr":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","creation_num":"2"}}},"frozen":false,"withdraw_events":{"counter":"0","guid":{"id":{"addr":"0x6a90df7117beb151d0483002ee0138b84c88c9b691610bdfc3edfe52bcfb85d","creation_num":"3"}}}}
// >>> coin value: 100
transaction
import {
Account,
Aptos,
AptosConfig,
Ed25519PrivateKey,
Network,
SigningSchemeInput,
} from "@aptos-labs/ts-sdk";
async function transaction() {
console.log(
"This example will create two accounts (Alice and Bob) and send a transaction transfering APT to Bob's account."
);
// 0. Setup the client and test accounts
const config = new AptosConfig({ network: Network.TESTNET });
const aptos = new Aptos(config);
let alice = Account.generate();
let bob = Account.generate();
console.log("=== Addresses ===\n");
console.log(`Alice's address is: ${alice.accountAddress}`);
console.log(`Bob's address is: ${bob.accountAddress}`);
console.log("\n=== Funding accounts ===\n");
await aptos.fundAccount({
accountAddress: alice.accountAddress,
amount: 100_000_000,
});
await aptos.fundAccount({
accountAddress: bob.accountAddress,
amount: 100,
});
console.log("Funded Alice and Bob's accounts!");
// 1. Build
console.log("\n=== 1. Building the transaction ===\n");
const transaction = await aptos.transaction.build.simple({
sender: alice.accountAddress,
data: {
// All transactions on Aptos are implemented via smart contracts.
function: "0x1::aptos_account::transfer",
functionArguments: [bob.accountAddress, 100],
},
});
console.log("Built the transaction!");
// 2. Simulate (Optional)
console.log("\n === 2. Simulating Response (Optional) === \n");
const [userTransactionResponse] = await aptos.transaction.simulate.simple({
signerPublicKey: alice.publicKey,
transaction,
});
console.log(userTransactionResponse);
// 3. Sign
console.log("\n=== 3. Signing transaction ===\n");
const senderAuthenticator = aptos.transaction.sign({
signer: alice,
transaction,
});
console.log("Signed the transaction!");
// 4. Submit
console.log("\n=== 4. Submitting transaction ===\n");
const submittedTransaction = await aptos.transaction.submit.simple({
transaction,
senderAuthenticator,
});
console.log(`Submitted transaction hash: ${submittedTransaction.hash}`);
// 5. Wait for results
console.log("\n=== 5. Waiting for result of transaction ===\n");
const executedTransaction = await aptos.waitForTransaction({
transactionHash: submittedTransaction.hash,
});
console.log(executedTransaction);
}
async function main() {
transaction();
}
main();
// $ ts-node src/03_transaction.ts
// This example will create two accounts (Alice and Bob) and send a transaction transfering APT to Bob's account.
// === Addresses ===
// Alice's address is: 0x001e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852
// Bob's address is: 0xa52522c9a1d0d6695e09be57b9605168056173e50a56e2f355385270ab7070e1
// === Funding accounts ===
// Funded Alice and Bob's accounts!
// === 1. Building the transaction ===
// Built the transaction!
// === 2. Simulating Response (Optional) ===
// {
// version: '5979042043',
// hash: '0xa3e7b041ce44d6d4aba88fa76a23ead97ecd064d327608bef3a585b5c5c1de22',
// state_change_hash: '0x0000000000000000000000000000000000000000000000000000000000000000',
// event_root_hash: '0x0000000000000000000000000000000000000000000000000000000000000000',
// state_checkpoint_hash: null,
// gas_used: '9',
// success: true,
// vm_status: 'Executed successfully',
// accumulator_root_hash: '0x0000000000000000000000000000000000000000000000000000000000000000',
// changes: [
// {
// address: '0x1e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852',
// state_key_hash: '0x7f4ad20eb420245733b8128041b91e3723ac16a4105a7d42584484207aa31186',
// data: [Object],
// type: 'write_resource'
// },
// {
// address: '0x1e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852',
// state_key_hash: '0x940f9bd6c4a7c61733c53d99c83007bbaea16ccb3a9a638f573d1ab7d3647d85',
// data: [Object],
// type: 'write_resource'
// },
// {
// address: '0xa52522c9a1d0d6695e09be57b9605168056173e50a56e2f355385270ab7070e1',
// state_key_hash: '0x820cf5d86aa00653ace8db87a11885e143a73dd04688fa8dcc23556ba3bd23da',
// data: [Object],
// type: 'write_resource'
// },
// {
// state_key_hash: '0x6e4b28d40f98a106a65163530924c0dcb40c1349d3aa915d108b4d6cfc1ddb19',
// handle: '0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca',
// key: '0x0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935',
// value: '0x65b3a042e529be940100000000000000',
// data: null,
// type: 'write_table_item'
// }
// ],
// sender: '0x1e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852',
// sequence_number: '0',
// max_gas_amount: '200000',
// gas_unit_price: '100',
// expiration_timestamp_secs: '1726236062',
// payload: {
// function: '0x1::aptos_account::transfer',
// type_arguments: [],
// arguments: [
// '0xa52522c9a1d0d6695e09be57b9605168056173e50a56e2f355385270ab7070e1',
// '100'
// ],
// type: 'entry_function_payload'
// },
// signature: {
// public_key: '0x0da1e7c9f856094993233fa9b9d0ce434aa192964c2d2a7f9ac0e98db7bef244',
// signature: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
// type: 'ed25519_signature'
// },
// events: [
// {
// guid: [Object],
// sequence_number: '0',
// type: '0x1::coin::WithdrawEvent',
// data: [Object]
// },
// {
// guid: [Object],
// sequence_number: '1',
// type: '0x1::coin::DepositEvent',
// data: [Object]
// },
// {
// guid: [Object],
// sequence_number: '0',
// type: '0x1::transaction_fee::FeeStatement',
// data: [Object]
// }
// ],
// timestamp: '1726236042647926'
// }
// === 3. Signing transaction ===
// Signed the transaction!
// === 4. Submitting transaction ===
// Submitted transaction hash: 0xab2aee974223a22ea6a1c24754a939c26a02bc417ac2e595aff8df6bb4e38f58
// === 5. Waiting for result of transaction ===
// {
// version: '5979042103',
// hash: '0xab2aee974223a22ea6a1c24754a939c26a02bc417ac2e595aff8df6bb4e38f58',
// state_change_hash: '0xb983e92f607a266695468412bbbecbb52922aecd8d7b7f2681d0b4e977b1a6a6',
// event_root_hash: '0xc6c4ffa097c7cf46570289b33ac3f2cd77fa41c72f767781f8122abe0014b583',
// state_checkpoint_hash: null,
// gas_used: '9',
// success: true,
// vm_status: 'Executed successfully',
// accumulator_root_hash: '0xb9ddc32e3353a440762f727a57929a9722e87b27398924a3aff6ebc322ff00e5',
// changes: [
// {
// address: '0x1e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852',
// state_key_hash: '0x7f4ad20eb420245733b8128041b91e3723ac16a4105a7d42584484207aa31186',
// data: [Object],
// type: 'write_resource'
// },
// {
// address: '0x1e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852',
// state_key_hash: '0x940f9bd6c4a7c61733c53d99c83007bbaea16ccb3a9a638f573d1ab7d3647d85',
// data: [Object],
// type: 'write_resource'
// },
// {
// address: '0xa52522c9a1d0d6695e09be57b9605168056173e50a56e2f355385270ab7070e1',
// state_key_hash: '0x820cf5d86aa00653ace8db87a11885e143a73dd04688fa8dcc23556ba3bd23da',
// data: [Object],
// type: 'write_resource'
// },
// {
// state_key_hash: '0x6e4b28d40f98a106a65163530924c0dcb40c1349d3aa915d108b4d6cfc1ddb19',
// handle: '0x1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca',
// key: '0x0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935',
// value: '0x93d3fb1fe629be940100000000000000',
// data: null,
// type: 'write_table_item'
// }
// ],
// sender: '0x1e858caee9d67b50a97f441b1590c170419905f2fb8d2140803c7e8e22c852',
// sequence_number: '0',
// max_gas_amount: '200000',
// gas_unit_price: '100',
// expiration_timestamp_secs: '1726236062',
// payload: {
// function: '0x1::aptos_account::transfer',
// type_arguments: [],
// arguments: [
// '0xa52522c9a1d0d6695e09be57b9605168056173e50a56e2f355385270ab7070e1',
// '100'
// ],
// type: 'entry_function_payload'
// },
// signature: {
// public_key: '0x0da1e7c9f856094993233fa9b9d0ce434aa192964c2d2a7f9ac0e98db7bef244',
// signature: '0x7cc94bc08806e4c1f71d1a2098b29d950dbc7ff29239bc6c1a628f036059ff7a4702b3a2ec4be64c2777be2e3ca61d5c1d058ae9d56e3d74e9340ac9c5e47802',
// type: 'ed25519_signature'
// },
// events: [
// {
// guid: [Object],
// sequence_number: '0',
// type: '0x1::coin::WithdrawEvent',
// data: [Object]
// },
// {
// guid: [Object],
// sequence_number: '1',
// type: '0x1::coin::DepositEvent',
// data: [Object]
// },
// {
// guid: [Object],
// sequence_number: '0',
// type: '0x1::transaction_fee::FeeStatement',
// data: [Object]
// }
// ],
// timestamp: '1726236043771659',
// type: 'user_transaction'
// }
Aptos CLI
命令总览
$ aptos -h
Command Line Interface (CLI) for developing and interacting with the Aptos blockchain
Usage: aptos <COMMAND>
Commands:
account Tool for interacting with accounts
config Tool for interacting with configuration of the Aptos CLI tool
genesis Tool for setting up an Aptos chain Genesis transaction
governance Tool for on-chain governance
info Show build information about the CLI
init Tool to initialize current directory for the aptos tool
key Tool for generating, inspecting, and interacting with keys
move Tool for Move smart contract related operations
multisig Tool for interacting with multisig accounts
node Tool for operations related to nodes
stake Tool for manipulating stake and stake pools
update Update the CLI or other tools it depends on
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
info - 查看客户端信息
$ aptos info
{
"Result": {
"build_branch": "main",
"build_cargo_version": "cargo 1.78.0 (54d8815d0 2024-03-26)",
"build_clean_checkout": "true",
"build_commit_hash": "4a202570804db6d27ba1ca6cb374228052be5bcb",
"build_is_release_build": "true",
"build_os": "linux-x86_64",
"build_pkg_version": "4.1.0",
"build_profile_name": "release",
"build_rust_channel": "1.78.0-x86_64-unknown-linux-gnu",
"build_rust_version": "rustc 1.78.0 (9b00956e5 2024-04-29)",
"build_tag": "",
"build_time": "2024-09-06 12:07:47 +00:00",
"build_using_tokio_unstable": "true"
}
}
config - 配置相关
命令总览
$ aptos config -h
Tool for interacting with configuration of the Aptos CLI tool
Usage: aptos config <COMMAND>
Commands:
delete-profile Delete the specified profile
generate-shell-completions Generate shell completion files
rename-profile Rename the specified profile
set-global-config Set global configuration settings
show-global-config Shows the properties in the global config
show-private-key Show the private key for the given profile
show-profiles Shows the current profiles available
show-private-key - 查看私钥
$ aptos config show-private-key --profile default
{
"Result": "0x2a88.....................80020b45"
}
> 读取的是这个文件中的私钥
$ cat .aptos/config.yaml
---
profiles:
default:
network: Testnet
private_key: "0x2a88.....................80020b45"
public_key: "0xd6a31c9c8c707d9f2e0b936a05b9427527c879bcebcbdcab1339b7daea327ea6"
account: cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022
rest_url: "https://fullnode.testnet.aptoslabs.com"
faucet_url: "https://faucet.testnet.aptoslabs.com"
init - 初始化本地配置并创建账户
- 创建默认 profile
$ aptos init
Configuring for profile default
Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
testnet
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
No key given, generating key...
Account 0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97 doesn't exist, creating it and funding it with 100000000 Octas
Account 0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97 funded successfully
---
Aptos CLI is now set up for account 0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97 as profile default!
See the account here: https://explorer.aptoslabs.com/account/0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97?network=testnet
Run `aptos --help` for more information about commands
{
"Result": "Success"
}
- 创建指定名称 profile
$ aptos init --profile jason
Configuring for profile jason
Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
mainnet
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
No key given, generating key...
Account 0x7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334 does not exist, you will need to create and fund the account by transferring funds from another account
---
Aptos CLI is now set up for account 0x7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334 as profile jason!
See the account here: https://explorer.aptoslabs.com/account/0x7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334?network=mainnet
Run `aptos --help` for more information about commands
{
"Result": "Success"
}
- 命令执行后,生成内容将会写到文件:
.aptos/config.yaml
中
cat .aptos/config.yaml
---
profiles:
default:
network: Testnet
private_key: "0x9e974b31cabc31b19ed0e1debe97efb0a1f7db88cc6735cc1b326a7d1460e8f1"
public_key: "0x71bbee6b99ef2805d3f900a0b9ca1faa2a2c863076aa1d6d4d0ec0e13e71126b"
account: 47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97
rest_url: "https://fullnode.testnet.aptoslabs.com"
faucet_url: "https://faucet.testnet.aptoslabs.com"
jason:
network: Mainnet
private_key: "0x065700c413f3bf6d9632ace4dc841d422a846bac4949b4c1eb2483fdc855ced8"
public_key: "0xc31ae7a8fb5b794a22f902e47fb7b956c3448a2ecfcb3e3303c637e872e118fb"
account: 7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334
rest_url: "https://fullnode.mainnet.aptoslabs.com"
account - 账户相关
命令总览
$ aptos account -h
Tool for interacting with accounts
Usage: aptos account <COMMAND>
Commands:
create Create a new account on-chain
create-resource-account Create a resource account on-chain
derive-resource-account-address Derive the address for a resource account
fund-with-faucet Fund an account with tokens from a faucet
balance Show the account's balance of different coins
list List resources, modules, or balance owned by an address
lookup-address Lookup the account address through the on-chain lookup table
rotate-key Rotate an account's authentication key
transfer Transfer APT between accounts
create - 创建链上账户
$ aptos account create --account jason
Do you want to submit a transaction for a range of [99700 - 149500] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x2492804e7610ac92601496e9bc549e506f4aa59dad482d041f853fadb00b987e?network=testnet
{
"Result": {
"transaction_hash": "0x2492804e7610ac92601496e9bc549e506f4aa59dad482d041f853fadb00b987e",
"gas_used": 997,
"gas_unit_price": 100,
"sender": "47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"sequence_number": 0,
"success": true,
"timestamp_us": 1726410280917653,
"version": 5989303061,
"vm_status": "Executed successfully"
}
}
list
List resources, modules, or balance owned by an address
Usage: aptos account list [OPTIONS]
Options:
--account <ACCOUNT>
Address of the account you want to list resources/modules/balance for
--query <QUERY>
Type of items to list: [balance, resources, modules] [default: resources] [possible values: balance, modules,
resources]
--url <URL>
URL to a fullnode on the network
--connection-timeout-secs <CONNECTION_TIMEOUT_SECS>
Connection timeout in seconds, used for the REST endpoint of the fullnode [default: 30]
--node-api-key <NODE_API_KEY>
Key to use for ratelimiting purposes with the node API. This value will be used as `Authorization: Bearer
<key>`. You may also set this with the NODE_API_KEY environment variable [env: NODE_API_KEY=]
--profile <PROFILE>
Profile to use from the CLI config
领水
$ aptos account fund-with-faucet --account default
{
"Result": "Added 100000000 Octas to account 0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97"
}
查看账户的余额和转账事件
$ aptos account list --query balance --account default
{
"Result": [
{
"coin": {
"value": "99900300"
},
"deposit_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "2"
}
}
},
"frozen": false,
"withdraw_events": {
"counter": "0",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "3"
}
}
}
}
]
}
列出帐户中的资源
$ aptos account list --query resources --account default
{
"Result": [
{
"0x1::account::Account": {
"authentication_key": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"coin_register_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "0"
}
}
},
"guid_creation_num": "4",
"key_rotation_events": {
"counter": "0",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "1"
}
}
},
"rotation_capability_offer": {
"for": {
"vec": []
}
},
"sequence_number": "1",
"signer_capability_offer": {
"for": {
"vec": []
}
}
}
},
{
"0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>": {
"coin": {
"value": "99900300"
},
"deposit_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "2"
}
}
},
"frozen": false,
"withdraw_events": {
"counter": "0",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "3"
}
}
}
}
}
]
}
列出账户模块
$ aptos account list --query modules
{
"Result": [
{
"bytecode": "0xa11ceb0b060000000c01000c020c1a03266d04930106059901900107a902910408ba064006fa064910c307c9020a8c0a160ca20a97040db90e0a000001010102010301040105000607000007080000080800040d0700021407010001022202000009000100000a020100000b030100000c040500000e060100000f070100001008090000110a0a000012020a00001302040000150a0b0000160a020000170a0c000018070100031e070200021f0f020005201112020202012113050100022316170002241819000225021e0108100a1112141d020608010300010503060c03030103010a0203060c03080301060c0305030302080301020503010b040108010101010800050305070801050708000206050a02020a02080303060a020900090101080301060900040800050708010507030307080208050c05080102060c0a0201080501060805010c0306080105060800020608010501060801010801010b0401090009746f646f5f6c69737403626373066f626a656374067369676e657206737472696e670c737472696e675f7574696c7304546f646f08546f646f4c6973741355736572546f646f4c697374436f756e7465721a6173736572745f757365725f6861735f676976656e5f746f646f196173736572745f757365725f6861735f746f646f5f6c6973740d636f6d706c6574655f746f646f1f636f6e7374727563745f746f646f5f6c6973745f6f626a6563745f7365656406537472696e670b6372656174655f746f646f106372656174655f746f646f5f6c697374086765745f746f646f0d6765745f746f646f5f6c697374236765745f746f646f5f6c6973745f62795f746f646f5f6c6973745f6f626a5f61646472156765745f746f646f5f6c6973745f636f756e746572064f626a656374116765745f746f646f5f6c6973745f6f626a166765745f746f646f5f6c6973745f6f626a5f616464720d6861735f746f646f5f6c6973740b696e69745f6d6f64756c6507636f6e74656e7409636f6d706c65746564056f776e657205746f646f7307636f756e7465720a616464726573735f6f66156372656174655f6f626a6563745f6164647265737307666f726d61743208746f5f62797465730e436f6e7374727563746f72526566136372656174655f6e616d65645f6f626a6563740f67656e65726174655f7369676e657211616464726573735f746f5f6f626a656374cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc4902200000000000000000000000000000000000000000000000000000000000000010308030000000000000003080200000000000000030801000000000000000a0206057b7d5f7b7d0520cb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022126170746f733a3a6d657461646174615f7631b4020301000000000000001a455f544f444f5f4c4953545f444f53455f4e4f545f455849535418546f646f206c69737420646f6573206e6f74206578697374020000000000000015455f544f444f5f444f53455f4e4f545f455849535413546f646f20646f6573206e6f74206578697374030000000000000018455f544f444f5f414c52454144595f434f4d504c4554454419546f646f20697320616c726561647920636f6d706c657465640006086765745f746f646f0101000d6765745f746f646f5f6c6973740101000d6861735f746f646f5f6c697374010100156765745f746f646f5f6c6973745f636f756e746572010100166765745f746f646f5f6c6973745f6f626a5f61646472010100236765745f746f646f5f6c6973745f62795f746f646f5f6c6973745f6f626a5f616464720101000002021908031a010102021b051c0a08000202011d0300000000010a0b010b001000410d2304070509070127020100000001070b002901040405060702270202010401010e280b00110e0c040e040b011103110f0c060a0611010b062a010c050a050a020c032e0b0311000b050f000b02430d0c070a071001140921041f05230b0701070027080b070f01150203000000100a07030c010e0107040b0038000c020e02380102040104010114160b00110e0c040e040b011103110f0c060a0611010b062a010c050b020912000c030b050f000b03440d020501040102152f0a00110e0c060a062902040c0a062b021002140c0105120a0006000000000000000012022d020600000000000000000c010b010c020b000b02110311120c040e0411130c050a06400d000000000000000012010c070e050b072d010b062a020c030a03100214060100000000000000160b030f02150206010001011a200b000b01110b0c040a0411010b042b010c030a020a031000410d23041005140b03010701270b0310000b02420d0c050a051003140b051001140207010001011b100b000b01110b0c030a0311010b032b010c020a021004140b021000410d0208010001011c0a0b002b010c010a011004140b011000410d020901000102040d0a00290204090b002b021002140c01050b0600000000000000000c010b01020a00000001050b000b01110b3802020b01000001050e000b011103110f020c01000001050b000b01110b2901020d0000000101020101000102000000010000",
"abi": {
"address": "0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022",
"name": "todo_list",
"friends": [],
"exposed_functions": [
{
"name": "complete_todo",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [],
"params": [
"&signer",
"u64",
"u64"
],
"return": []
},
{
"name": "create_todo",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [],
"params": [
"&signer",
"u64",
"0x1::string::String"
],
"return": []
},
{
"name": "create_todo_list",
"visibility": "public",
"is_entry": true,
"is_view": false,
"generic_type_params": [],
"params": [
"&signer"
],
"return": []
},
{
"name": "get_todo",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [
"address",
"u64",
"u64"
],
"return": [
"0x1::string::String",
"bool"
]
},
{
"name": "get_todo_list",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [
"address",
"u64"
],
"return": [
"address",
"u64"
]
},
{
"name": "get_todo_list_by_todo_list_obj_addr",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [
"address"
],
"return": [
"address",
"u64"
]
},
{
"name": "get_todo_list_counter",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [
"address"
],
"return": [
"u64"
]
},
{
"name": "get_todo_list_obj_addr",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [
"address",
"u64"
],
"return": [
"address"
]
},
{
"name": "has_todo_list",
"visibility": "public",
"is_entry": false,
"is_view": true,
"generic_type_params": [],
"params": [
"address",
"u64"
],
"return": [
"bool"
]
}
],
"structs": [
{
"name": "Todo",
"is_native": false,
"is_event": false,
"abilities": [
"copy",
"drop",
"store"
],
"generic_type_params": [],
"fields": [
{
"name": "content",
"type": "0x1::string::String"
},
{
"name": "completed",
"type": "bool"
}
]
},
{
"name": "TodoList",
"is_native": false,
"is_event": false,
"abilities": [
"key"
],
"generic_type_params": [],
"fields": [
{
"name": "owner",
"type": "address"
},
{
"name": "todos",
"type": "vector<0xcb3303e6b96a1a666347bd06e27d24cc0cb09e204fedb6223a7bc9091dc49022::todo_list::Todo>"
}
]
},
{
"name": "UserTodoListCounter",
"is_native": false,
"is_event": false,
"abilities": [
"key"
],
"generic_type_params": [],
"fields": [
{
"name": "counter",
"type": "u64"
}
]
}
]
}
}
]
}
转账
$ aptos account balance --account default
{
"Result": [
{
"asset_type": "coin",
"coin_type": "0x1::aptos_coin::AptosCoin",
"balance": 199900300
}
]
}
$ aptos account balance --account jason
{
"Result": [
{
"asset_type": "coin",
"coin_type": "0x1::aptos_coin::AptosCoin",
"balance": 0
}
]
}
$ aptos account transfer --account jason --amount 10000
Do you want to submit a transaction for a range of [900 - 1300] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
Transaction submitted: https://explorer.aptoslabs.com/txn/0x2f24a1685e47cc6abca41e28696dd1a75f87c92c97142d6a67cf96042e15e682?network=testnet
{
"Result": {
"gas_unit_price": 100,
"gas_used": 9,
"balance_changes": {
"47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97": {
"coin": {
"value": "199889400"
},
"deposit_events": {
"counter": "2",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "2"
}
}
},
"frozen": false,
"withdraw_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0x47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"creation_num": "3"
}
}
}
},
"7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334": {
"coin": {
"value": "10000"
},
"deposit_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0x7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334",
"creation_num": "2"
}
}
},
"frozen": false,
"withdraw_events": {
"counter": "0",
"guid": {
"id": {
"addr": "0x7ac59d3368d1eb46c599ed1fb57d6f51d2b926f2d12b4573f6954fcde602c334",
"creation_num": "3"
}
}
}
}
},
"sender": "47946eb78dcc85eda351217d42288e6d4669159113c7efbe7ec87bf6c07f5e97",
"success": true,
"version": 5989333990,
"vm_status": "Executed successfully",
"transaction_hash": "0x2f24a1685e47cc6abca41e28696dd1a75f87c92c97142d6a67cf96042e15e682"
}
}
$ aptos account balance --account jason
{
"Result": [
{
"asset_type": "coin",
"coin_type": "0x1::aptos_coin::AptosCoin",
"balance": 10000
}
]
}
参考资料
https://gushi10546.gitbook.io/aptos-kai-fa-zhe-wen-dang/aptos-cli/shi-yong-aptos-cli
配置开发环境
A beautifully styled message.
A beautifully styled message.
A beautifully styled message.
A beautifully styled message.
A plain note.
示例学习:transfer_coin.ts
示例说明
本示例会创建两个账号(Alice 和 Bob),并向 Alice 账号领水,然后 Alice 向 Bob 进行转账。
示例来源
https://github.com/aptos-labs/aptos-ts-sdk/blob/main/examples/typescript/transfer_coin.ts
运行效果
$ npm run transfer_coin
> ts-test@1.0.0 transfer_coin
> ts-node transfer_coin.ts
This example will create two accounts (Alice and Bob), fund Alice, and transfer between them using transferCoinTransaction.
=== Addresses ===
Alice's address is: 0x740b7c81913e7ebff0ae610d468b6db46ba04267685234cc792c3c335b64f64c
Bob's address is: 0xc7ac915a9ebd1f0a1bda1b682b2127c549036de015f07044641095bb23f544ea
=== Funding accounts ===
=== Initial Balances ===
Alice's balance is: 100000000
Bob's balance is: 0
=== Transfer 1000000 from Alice to Bob ===
Committed transaction: 0x19c20fa1364ef1f7fe0b95644ec24984054196f286496fa3d71e7bacca54873b
=== Balances after transfer ===
Alice's balance is: 98900100
Bob's balance is: 1000000
SDK 学习
(1) 初始化客户端
import {
Account,
AccountAddress,
Aptos,
AptosConfig,
Network,
NetworkToNetworkName,
} from "@aptos-labs/ts-sdk";
const ALICE_INITIAL_BALANCE = 100_000_000;
const BOB_INITIAL_BALANCE = 0;
const TRANSFER_AMOUNT = 1_000_000;
// Setup the client
const APTOS_NETWORK: Network =
NetworkToNetworkName[process.env.APTOS_NETWORK ?? Network.TESTNET];
const config = new AptosConfig({ network: APTOS_NETWORK });
const aptos = new Aptos(config);
(2) 创建测试账号
// Create two accounts
const alice = Account.generate();
const bob = Account.generate();
console.log("=== Addresses ===\n");
console.log(`Alice's address is: ${alice.accountAddress}`);
console.log(`Bob's address is: ${bob.accountAddress}`);
(3) Alice 账号领水
// Fund the accounts
console.log("\n=== Funding accounts ===\n");
// Fund alice account
await aptos.fundAccount({
accountAddress: alice.accountAddress,
amount: ALICE_INITIAL_BALANCE,
});
// Show the balances
console.log("\n=== Initial Balances ===\n");
const aliceBalance = await balance("Alice", alice.accountAddress);
const bobBalance = await balance("Bob", bob.accountAddress);
if (aliceBalance !== ALICE_INITIAL_BALANCE)
throw new Error("Alice's balance is incorrect");
if (bobBalance !== BOB_INITIAL_BALANCE)
throw new Error("Bob's balance is incorrect");
(4) Alice 向 Bob 转账
// Transfer between users
console.log(`\n=== Transfer ${TRANSFER_AMOUNT} from Alice to Bob ===\n`);
const transaction = await aptos.transferCoinTransaction({
sender: alice.accountAddress,
recipient: bob.accountAddress,
amount: TRANSFER_AMOUNT,
});
const pendingTxn = await aptos.signAndSubmitTransaction({
signer: alice,
transaction,
});
const response = await aptos.waitForTransaction({
transactionHash: pendingTxn.hash,
});
console.log(`Committed transaction: ${response.hash}`);
(5) 验证转账结果
console.log("\n=== Balances after transfer ===\n");
const newAliceBalance = await balance(
"Alice",
alice.accountAddress,
BigInt(response.version)
);
const newBobBalance = await balance("Bob", bob.accountAddress);
// Bob should have the transfer amount
if (newBobBalance !== TRANSFER_AMOUNT + BOB_INITIAL_BALANCE)
throw new Error("Bob's balance after transfer is incorrect");
// Alice should have the remainder minus gas
if (newAliceBalance >= ALICE_INITIAL_BALANCE - TRANSFER_AMOUNT)
throw new Error("Alice's balance after transfer is incorrect");
(6) 查询账户余额方法封装
const balance = async (aptos: Aptos, name: string, address: AccountAddress) => {
type Coin = { coin: { value: string } };
const resource = await aptos.getAccountResource<Coin>({
accountAddress: address,
resourceType: COIN_STORE,
});
const amount = Number(resource.coin.value);
console.log(`${name}'s balance is: ${amount}`);
return amount;
};
示例学习:keyless.ts
示例说明
本示例用于展示 Aptos 无密钥帐户的创建和转账。
Aptos Keyless 允许用户使用他们现有 OpenID Connect (OIDC) 帐户(即他们在 Google、GitHub 或 Apple 等 OIDC 提供商的 Web2 帐户)进行保护,而不是使用传统的密钥或助记词。
示例来源
https://github.com/aptos-labs/aptos-ts-sdk/blob/main/examples/typescript/keyless.ts
运行效果
$ ts-node examples/typescript/keyless.ts
=== Keyless Account Example ===
https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&prompt=consent&response_type=code&client_id=407408718192.apps.googleusercontent.com&scope=openid&access_type=offline&service=lso&o2v=2&theme=glif&flowName=GeneralOAuthFlow&nonce=17467935072969263488480768409145005791958785027130051114412344202040832217364
1. Open the link above
2. Log in with your Google account
3. Click 'Exchange authorization code for tokens
4. Copy the 'id_token' - (toggling 'Wrap lines' option at the bottom makes this easier)
Paste the JWT (id_token) token here and press enter: eyJhbGciOiJSUzI1NiIsImtpZCI6IjVhYWZmNDdjMjFkMDZlMjY2Y2NlMzk1YjIxNDVjN2M2ZDQ3MzBlYTUiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDYzOTI3OTA2ODg4MDcyMjE5ODkiLCJhdF9oYXNoIjoieFVZN3JDVWxuRm8wTDl6dF9aN3dmdyIsIm5vbmNlIjoiMTc0Njc5MzUwNzI5NjkyNjM0ODg0ODA3Njg0MDkxNDUwMDU3OTE5NTg3ODUwMjcxMzAwNTExMTQ0MTIzNDQyMDIwNDA4MzIyMTczNjQiLCJpYXQiOjE3MjczNDc0OTAsImV4cCI6MTcyNzM1MTA5MH0.eAhUw2upTky71FkPwdM1AM3ZUbVvZB4ZI491QSF1DSNk7IcVTLiqzpApW786LA1b9_iFgVK0CCec-n6qWmt1iHUK2nC9ljP7w9A77gQXlhCUBig3lVBx-OE74AUTcGkZ-6tkTOKXEHo7O2jtlCCEX_X8Cm-h_z7WyM5119KWIup1roX8r9ASnX9XEeVB93fCkRIxFTrDOmoHEkyknG_0zlfUP-OILPuqdudP5lTyoGIN48epSdYrx1bPVDiy-qfiv0TEQ1i7fdV51vzgzDXKjGvHLx4K8qWucPHsD1WgVxasFbRcjXbWEjACn-c_-L5ec3XlHffjJu9IKDTTTZHGuA
=== Addresses ===
Alice's keyless account address is: 0x6312a314941e675c71b491ffb8b8bd1a799bb57ee276b8f58f2213f5ae6a298c
Alice's nonce is: 17467935072969263488480768409145005791958785027130051114412344202040832217364
Alice's ephem pubkey is: 0x0020208f671cecff3f94fd01f0d492eadac3ed660e344e0cd6e0844019e0c4779c1b
Bob's address is: 0x563ab13d7709797e67cd2c07442d1ebfa7ed8eb457fcbc85102d6d52aa5d8b70
=== Funding accounts ===
=== Balances ===
Alice's balance is: 199985900
Bob's balance is: 100
Committed transaction: 0x87e430811df0537e25327fd296cfe8efc596dc31ebc6758587a3571287c4b7bb
=== Balances after transfer ===
Alice's balance is: 199971800
Bob's balance is: 10100
SDK 学习
(1) 初始化客户端
import {
Account,
AccountAddress,
Aptos,
AptosConfig,
EphemeralKeyPair,
Network,
} from "@aptos-labs/ts-sdk";
import * as readlineSync from "readline-sync";
const COIN_STORE = "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>";
const ALICE_INITIAL_BALANCE = 100_000_000;
const BOB_INITIAL_BALANCE = 100;
const TRANSFER_AMOUNT = 10_000;
const config = new AptosConfig({ network: Network.TESTNET });
const aptos = new Aptos(config);
(2) 创建 Alice 临时密钥
// Generate the ephemeral (temporary) key pair that will be used to sign transactions.
const aliceEphem = EphemeralKeyPair.generate();
(3) 登陆 Alice 谷歌账户获取 JWT
const link = `https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&prompt=consent&response_type=code&client_id=407408718192.apps.googleusercontent.com&scope=openid&access_type=offline&service=lso&o2v=2&theme=glif&flowName=GeneralOAuthFlow&nonce=${aliceEphem.nonce}`;
console.log(`${link}\n`);
console.log("1. Open the link above");
console.log("2. Log in with your Google account");
console.log("3. Click 'Exchange authorization code for tokens");
console.log(
"4. Copy the 'id_token' - (toggling 'Wrap lines' option at the bottom makes this easier)\n"
);
function inputJwt(): string {
const jwt: string = readlineSync.question(
"Paste the JWT (id_token) token here and press enter: ",
{
hideEchoBack: false,
}
);
return jwt;
}
const jwt = inputJwt();
(4) 使用 JWT 及 Alice 临时密钥创建 Keyless 账户密钥对
// Derive the Keyless Account from the JWT and ephemeral key pair.
const alice = await aptos.deriveKeylessAccount({
jwt,
ephemeralKeyPair: aliceEphem,
});
console.log("=== Addresses ===\n");
console.log(`Alice's keyless account address is: ${alice.accountAddress}`);
console.log(`Alice's nonce is: ${aliceEphem.nonce}`);
console.log(`Alice's ephem pubkey is: ${aliceEphem.getPublicKey().toString()}`);
(5) 创建传统 Bob 账号并分别领水
const bob = Account.generate();
console.log(`Bob's address is: ${bob.accountAddress}`);
// Fund the accounts
console.log("\n=== Funding accounts ===\n");
await aptos.fundAccount({
accountAddress: alice.accountAddress,
amount: ALICE_INITIAL_BALANCE,
});
await aptos.fundAccount({
accountAddress: bob.accountAddress,
amount: BOB_INITIAL_BALANCE,
options: { waitForIndexer: false },
});
console.log("\n=== Balances ===\n");
const aliceBalance = await balance(aptos, "Alice", alice.accountAddress);
const bobBalance = await balance(aptos, "Bob", bob.accountAddress);
(6) Alice 给 Bob 进行转账
// Transfer between users
const transaction = await aptos.transferCoinTransaction({
sender: alice.accountAddress,
recipient: bob.accountAddress,
amount: TRANSFER_AMOUNT,
});
const committedTxn = await aptos.signAndSubmitTransaction({
signer: alice,
transaction,
});
await aptos.waitForTransaction({ transactionHash: committedTxn.hash });
console.log(`Committed transaction: ${committedTxn.hash}`);
(7) 查看转账后余额
console.log("\n=== Balances after transfer ===\n");
const newAliceBalance = await balance(aptos, "Alice", alice.accountAddress);
const newBobBalance = await balance(aptos, "Bob", bob.accountAddress);
// Bob should have the transfer amount
if (TRANSFER_AMOUNT !== newBobBalance - bobBalance)
throw new Error("Bob's balance after transfer is incorrect");
// Alice should have the remainder minus gas
if (TRANSFER_AMOUNT >= aliceBalance - newAliceBalance)
throw new Error("Alice's balance after transfer is incorrect");