BTC
ETH
HTX
SOL
BNB
Xem thị trường
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

DAOrayaki: Aptos & Di chuyển giải thích thực tế

DAOrayaki
特邀专栏作者
2022-09-21 03:19
Bài viết này có khoảng 13659 từ, đọc toàn bộ bài viết mất khoảng 20 phút
Bài viết này chủ yếu giải thích cách vận hành aptos cli và aptos sdk.
Tóm tắt AI
Mở rộng
Bài viết này chủ yếu giải thích cách vận hành aptos cli và aptos sdk.

Nhóm tiền thưởng nghiên cứu DAOrayaki DAO:

Địa chỉ tài trợ: DAOrayaki.eth

Tiến độ bình chọn: DAO Reviewer 3/0 đã thông qua

Loại nghiên cứu: Aptos,Layer1

Tác giả: FF@DoraFactory

Bài viết này chủ yếu giải thích hoạt động của aptos cli và aptos sdk

Clone Aptos-core Repo

# Clone the Aptos repo.
git clone 
# cd into aptos-core directory.
cd aptos-core
# Run the scripts/dev_setup.sh Bash script as shown below. This will prepare your developer environment.
./scripts/dev_setup.sh
# Update your current shell environment.
source ~/.cargo/env
# Skip this step if you are not installing an Aptos node.
git checkout --track origin/devnet

Bắt đầu chuỗi địa phương Aptos

Using CLI to Run a Local Testnet | Aptos Docs[1]

  • Bắt đầu chuỗi địa phương

ps: Chuỗi cục bộ và dữ liệu được bắt đầu bằng phương pháp này sẽ được lưu trong thư mục hiện tại nơi lệnh này được bắt đầu và tồn tại trong tệp .aptos/
aptos node run-local-testnet --with-faucet

Bắt đầu thành công:

Completed generating configuration:
        Log file: "/Users/greg/.aptos/testnet/validator.log"
        Test dir: "/Users/greg/.aptos/testnet"
        Aptos root key path: "/Users/greg/.aptos/testnet/mint.key"
        Waypoint: 0:74c9d14285ec19e6bd15fbe851007ea8b66efbd772f613c191aa78721cadac25
        ChainId: TESTING
        REST API endpoint: 0.0.0.0:8080
        FullNode network: /ip4/0.0.0.0/tcp/6181
Aptos is running, press ctrl-c to exit
Faucet is running.  Faucet endpoint: 0.0.0.0:8081

Sau khi khởi động thành công, nó sẽ nhắc địa chỉ của api còn lại và api vòi. Sau đó, hai phần thông tin này cần được cấu hình trong môi trường aptos cli.

  • Định cấu hình môi trường aptos cli

Để truy cập và gọi local test chain thông qua dòng lệnh, chúng ta cần cấu hình config cho aptos cli theo thông tin triển khai ở trên.

PROFILE=local
aptos init --profile $PROFILE --rest-url  --faucet-url 

Trong quá trình thực hiện, chúng ta sẽ nhận được đầu ra sau. Chúng tôi có thể chọn nhập khóa bí mật hoặc có thể được tạo ngẫu nhiên theo mặc định.

Configuring for profile local
Using command line argument for rest URL 
Using command line argument for faucet URL 
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]

Sau khi xác nhận, một tài khoản sẽ được tạo và tài trợ với số lượng mã thông báo mặc định.

No key given, generating key...
Account 7100C5295ED4F9F39DCC28D309654E291845984518307D3E2FE00AEA5F8CACC1 doesn't exist, creating it and funding it with 10000 coins
Aptos is now set up for account 7100C5295ED4F9F39DCC28D309654E291845984518307D3E2FE00AEA5F8CACC1!  Run `aptos help` for more information about commands
{
  "Result": "Success"
}

Từ giờ trở đi, chúng ta có thể chạy chúng trên mạng thử nghiệm cục bộ bằng cách thêm --profile local vào lệnh.

ps: --profile ở đây giống như kube-config trong k8s, có thể đặt các môi trường cấu hình khác nhau và kiểm soát các mạng khác nhau.

Cấu hình cấu hình sẽ đặt địa chỉ người thực thi, thông tin về nút-phần còn lại-api và vòi-api.

# Liệt kê tất cả các tài khoản được kiểm soát bởi cli
aptos account list
# Nạp tiền vào tài khoản:
aptos account fund --profile $PROFILE --account $PROFILE
# Tạo tài khoản tài nguyên mới
aptos account create-resource-account --profile $PROFILE --seed 1
# Soạn hợp đồng chuyển nhà
aptos move compile --package-dir hello_blockchain
# Triển khai hợp đồng
aptos move publish --package-dir hello_blockchain --named-addresses basecoin= --profile local
# gọi hợp đồng
aptos move run --function-id :::: --profile local
# Liệt kê thông tin mô-đun/tài nguyên của tài khoản được chỉ định
aptos account list --query modules --account 0xa1285adb4b8abedf5faf7a46d260c5844f1f64d59dd9b8869db1543cf5bbadf4 --profile local
aptos account list --query resources --account 0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf --profile local
# nâng cấp hợp đồng
aptos move publish --upgrade-policy
    `arbitrary`, `compatible`,`bất biến` tương ứng với 0, 1, 2
0 không thực hiện bất kỳ kiểm tra nào, mã thay thế bắt buộc,
1 Thực hiện kiểm tra tính tương thích (cùng chức năng chung không thể thay đổi bố cục bộ nhớ của Tài nguyên hiện có)
2 Cấm nâng cấp
Mỗi khi nó được xuất bản, nó sẽ so sánh chính sách trên chuỗi với chính sách của lần xuất bản này (mặc định là 1),
Nâng cấp hợp đồng chỉ được phép khi chính sách lần này nhỏ hơn chính sách trên chuỗi

Triển khai hợp đồng Move đơn giản

module MyCounterAddr::MyCounter {
    use std::signer;
    struct Counter has key, store {
        value:u64,
    }
    public fun init(account: &signer){
        move_to(account, Counter{value:0});
    }
    public fun incr(account: &signer) acquires Counter {
        let counter = borrow_global_mut(signer::address_of(account));
        counter.value = counter.value + 1;
    }
    public entry fun init_counter(account: signer){
        Self::init(&account)
    }
    public entry fun incr_counter(account: signer)  acquires Counter {
        Self::incr(&account)
    }
}

Phân tích mã nguồn MyCounter

Một mô-đun là một tập hợp các chức năng và cấu trúc được đóng gói được xuất bản dưới một địa chỉ cụ thể. Khi sử dụng tập lệnh, nó cần chạy với mô-đun hoặc thư viện chuẩn đã xuất bản và bản thân thư viện chuẩn là một nhóm các mô-đun được phát hành dưới địa chỉ 0x1.

mô-đun MyCounterAddr::MyCounter{ } nằm dưới địa chỉ MyCounterAddr (tương ứng với MyCounterAddr ="0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf") để tạo một mô-đun.

sử dụng std::signer là sử dụng mô-đun người ký trong thư viện tiêu chuẩn. Người ký là một loại gốc không thể sao chép tương tự như Tài nguyên, chứa địa chỉ của người gửi giao dịch. Một trong những lý do giới thiệu kiểu người ký là để làm rõ chức năng nào yêu cầu quyền của người gửi và chức năng nào không. Do đó, một chức năng không thể lừa người dùng để giành quyền truy cập trái phép vào Tài nguyên của nó. Để biết chi tiết, vui lòng tham khảo mã nguồn [2].

module std::signer {
    // Borrows the address of the signer
    // Conceptually, you can think of the `signer` as being a struct wrapper arround an
    // address
    // ```
    // struct signer has drop { addr: address }
    // ```
    // `borrow_address` borrows this inner field
    native public fun borrow_address(s: &signer): &address;
    // Copies the address of the signer
    public fun address_of(s: &signer): address {
        *borrow_address(s)
    }
    /// Return true only if `s` is a transaction signer. This is a spec function only available in spec.
    spec native fun is_txn_signer(s: signer): bool;
    /// Return true only if `a` is a transaction signer address. This is a spec function only available in spec.
    spec native fun is_txn_signer_addr(a: address): bool;
}

Struct & Abilities


struct Counter has key, store {
    value:u64,
}

Sử dụng struct để định nghĩa một cấu trúc có tên là Bộ đếm, đồng thời, nó được sửa đổi bởi hai loại bộ giới hạn, khóa và bộ lưu trữ.

Hệ thống loại của Move rất linh hoạt và mỗi loại có thể xác định bốn khả năng.

Chúng xác định xem các giá trị của loại có thể được sao chép, loại bỏ và lưu trữ hay không.

Bốn vòng loại khả năng là: Sao chép, Thả, Lưu trữ và Chìa khóa.

Chức năng của chúng là:

  • Sao chép - Giá trị có thể được sao chép.

  • Drop - Các giá trị có thể được drop ở cuối phạm vi.

  • Khóa - Giá trị có thể được truy cập dưới dạng khóa bằng "hoạt động lưu trữ toàn cầu".

  • Lưu trữ - Các giá trị có thể được lưu trữ vào trạng thái toàn cầu.

Được sửa đổi bằng khóa và lưu trữ ở đây, điều đó có nghĩa là nó không thể được sao chép, loại bỏ hoặc sử dụng lại, nhưng nó có thể được lưu trữ và chuyển giao một cách an toàn.

Cú pháp cho khả năng

Khả năng của các kiểu nguyên thủy và kiểu dựng sẵn được xác định trước và không thay đổi: giá trị của số nguyên, vectơ, địa chỉ và kiểu boolean vốn có khả năng sao chép, thả và lưu trữ.

Tuy nhiên, khả năng của cấu trúc có thể được thêm vào theo cú pháp sau:

struct NAME has ABILITY [, ABILITY] { [FIELDS] }

Một ví dụ thư viện đơn giản:

module Library {
    // each ability has matching keyword
    // multiple abilities are listed with comma
    struct Book has store, copy, drop {
        year: u64
    }
    // single ability is also possible
    struct Storage has key {
        books: vector
    }
    // this one has no abilities
    struct Empty {}
}

Tài nguyên là gì

Khái niệm về Tài nguyên được mô tả chi tiết trong sách trắng Move. Ban đầu, nó được triển khai dưới dạng một loại cấu trúc được gọi là tài nguyên, kể từ khi khả năng ra đời, nó đã được triển khai dưới dạng cấu trúc với hai khả năng Khóa và Lưu trữ. Tài nguyên có thể đại diện cho tài sản kỹ thuật số một cách an toàn, không thể sao chép, cũng như không thể loại bỏ hoặc tái sử dụng, nhưng có thể lưu trữ và chuyển giao một cách an toàn.

Định nghĩa tài nguyên

Tài nguyên là một cấu trúc bị giới hạn với khả năng lưu trữ và khóa:

module M {
    struct T has key, store {
        field: u8
    }
}Giới hạn tài nguyên

Trong mã, loại Tài nguyên có một số hạn chế chính:

  • Tài nguyên được lưu trữ dưới các tài khoản. Do đó, nó chỉ tồn tại khi một tài khoản được chỉ định và chỉ có thể được truy cập thông qua tài khoản đó.

  • Một tài khoản chỉ có thể chứa một tài nguyên thuộc một loại nhất định tại một thời điểm.

  • Tài nguyên không thể sao chép được; tương ứng với nó là một loại đặc biệt: tài nguyên, khác với tài nguyên có thể sao chép, đã được giới thiệu trong chương tổng quát. (Điều này có thể được trừu tượng hóa thành quyền sở hữu của Rust)

  • Tài nguyên phải được sử dụng, nghĩa là Tài nguyên mới được tạo phải được di chuyển trong một tài khoản và Tài nguyên được di chuyển từ một tài khoản phải được giải cấu trúc hoặc lưu trữ trong một tài khoản khác.

Vụ vừa rồi

struct Counter has key, store {
    value:u64,
}

Vì vậy, đây là một sự khác biệt so với solidity, nếu một tài sản mới cần được phát hành trên eth, chẳng hạn như usdc. Sau đó, tài sản này được ghi lại trong một bản đồ trong hợp đồng. Nhưng di chuyển thì khác, tài sản được lưu trữ dưới địa chỉ của người dùng dưới dạng tài nguyên.

xác định chức năng

public fun init(account: &signer){
    move_to(account, Counter{value:0});
}
public fun incr(account: &signer) acquires Counter {
    let counter = borrow_global_mut(signer::address_of(account));
    counter.value = counter.value + 1;
}
public entry fun init_counter(account: signer){
    Self::init(&account)
}
public entry fun incr_counter(account: signer)  acquires Counter {
    Self::incr(&account)
}

Định dạng định nghĩa là:

tên hàm công khai (tham số: loại tham số) { }

các chức năng di chuyển là riêng tư theo mặc định và chỉ có thể được truy cập trong mô-đun mà chúng được xác định. Từ khóa công khai sẽ thay đổi khả năng hiển thị mặc định của một chức năng và đặt nó ở chế độ công khai, nghĩa là có thể truy cập được từ bên ngoài.

Tham số của phương thức init là &signer, có nghĩa là phương thức này chỉ có thể được gọi sau khi một tài khoản được ký hợp pháp. Trong mô hình tài khoản của Move, mã và dữ liệu được lưu trữ dưới một địa chỉ tài khoản.

Sau đây là danh sách các nguyên thủy thường được sử dụng

  • move_to< T >(&signer,T): Xuất bản và thêm Tài nguyên loại T vào địa chỉ của người ký.

  • move_from< T >(addr: address): T - Xóa Tài nguyên loại T khỏi địa chỉ và trả về tài nguyên này.

  • borrow_global< T >(addr: address): &T - Trả về một tham chiếu bất biến đến Tài nguyên loại T tại địa chỉ.

  • borrow_global_mut< T >(addr: address): &mut T - Trả về một tham chiếu có thể thay đổi tới Tài nguyên của loại T tại địa chỉ.

  • exists< T >(địa chỉ): bool: Xác định xem có Tài nguyên loại T dưới địa chỉ hay không.

Tham số của phương thức incr cũng là &signer, có nghĩa là phương thức phải được ký hợp pháp bởi một tài khoản trước khi có thể gọi phương thức này.

Từ khóa có được, được đặt sau giá trị trả về của hàm, được sử dụng để xác định rõ ràng tất cả các tài nguyên mà hàm này có được.

Signer::address_of(account) Lấy địa chỉ từ người ký

Như đã đề cập ở trên loan_global_mut, biến mượn tài nguyên Bộ đếm theo địa chỉ, sau đó thực hiện thao tác +1 trên giá trị trong cấu trúc Bộ đếm.

Hai phương thức sau đây là các phương thức tập lệnh. Sự khác biệt giữa chúng và hai hàm trên là gì?

  • public fun : phương thức có thể được gọi trong bất kỳ mô-đun nào.

  • public(script) fun / public entry fun: hàm script là phương thức nhập trong mô-đun, có nghĩa là phương thức này có thể được gọi bằng cách bắt đầu giao dịch thông qua bảng điều khiển, giống như thực thi tập lệnh cục bộ

Phiên bản tiếp theo của Move sẽ thay thế niềm vui công khai (tập lệnh) bằng niềm vui nhập cảnh công khai

Bản thân đại diện cho mô-đun của chính nó.

Sử dụng Aptos Cli để biên dịch, triển khai và gọi hợp đồng

# Tạo môi trường thử nghiệm mới
aptos init --profile devtest --rest-url  --faucet-url 
# Soạn hợp đồng chuyển nhà
aptos move compile --package-dir my-counter
# Triển khai hợp đồng
# Ví dụ: aptos move publish --package-dir my-counter --named-addresses basecoin=0x8e00bd9827faf171996ef37f006dd622bb5c3e43ec52298a8f37fd38cd59664 --profile devtest
aptos move publish --package-dir my-counter --named-addresses basecoin= --profile devtest
# gọi hợp đồng
# Ví dụ:
# aptos move run --function-id 0x8e00bd9827faf171996ef37f006dd622bb5c3e43ec52298a8f37fd38cd59664::MyCounter::init_counter --profile devtest
# aptos move run --function-id 0x8e00bd9827faf171996ef37f006dd622bb5c3e43ec52298a8f37fd38cd59664::MyCounter::incr_counter --profile devtest
aptos move run --function-id :::: --profile devtest
# Liệt kê thông tin mô-đun/tài nguyên của tài khoản được chỉ định
aptos account list --query modules --account 0xa1285adb4b8abedf5faf7a46d260c5844f1f64d59dd9b8869db1543cf5bbadf4 --profile devtest
aptos account list --query resources --account 0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf --profile devtest

Aptos SDK gọi hợp đồng Move

Sau khi biên dịch hợp đồng, chúng tôi có thể gọi hợp đồng của mình thông qua sdk.

Chúng tôi có thể chọn triển khai hợp đồng thông qua sdk hoặc gọi hợp đồng di chuyển thông qua sdk.

  • Triển khai hợp đồng thông qua sdk

Khi chúng tôi biên dịch, một bản dựng/thư mục sẽ được tạo trong thư mục hợp đồng di chuyển

Chúng ta cần sao chép tệp my-counter/build/Examples/bytecode_modules/MyCounter.mv vào tập lệnh SDK.

aptos move compile --package-dir my-counter
cp MyCounter.mv my-counter-sdk-demo/

  • Triển khai mã sdk liên quan đến hợp đồng

/** Publish a new module to the blockchain within the specified account */
export async function publishModule(accountFrom: AptosAccount, moduleHex: string): Promise {
  const moudleBundlePayload = new TxnBuilderTypes.TransactionPayloadModuleBundle(
    new TxnBuilderTypes.ModuleBundle([new TxnBuilderTypes.Module(new HexString(moduleHex).toUint8Array())]),
  );
  const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
    client.getAccount(accountFrom.address()),
    client.getChainId(),
  ]);
  const rawTxn = new TxnBuilderTypes.RawTransaction(
    TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
    BigInt(sequenceNumber),
    moudleBundlePayload,
    1000n,
    1n,
    BigInt(Math.floor(Date.now() / 1000) + 10),
    new TxnBuilderTypes.ChainId(chainId),
  );
  const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
  const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
  return transactionRes.hash;
}

  • Gửi giao dịch qua SDK

Ở đây, chúng tôi lấy init_counter và incr_counter trong hợp đồng my-counter làm ví dụ.

Xây dựng hai phương thức để gọi hai phương thức này nhằm thực hiện chức năng gọi init và incr của client.

async function initCounter(contractAddress: string, accountFrom: AptosAccount): Promise {
  const scriptFunctionPayload = new TxnBuilderTypes.TransactionPayloadScriptFunction(
    TxnBuilderTypes.ScriptFunction.natural(
      `${contractAddress}::MyCounter`,// Địa chỉ hợp đồng::tên hợp đồng
      "init_counter",// phương thức hàm script
      [],
      [],
    ),
  );
  const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
    client.getAccount(accountFrom.address()),
    client.getChainId(),
  ]);
  const rawTxn = new TxnBuilderTypes.RawTransaction(
    TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
    BigInt(sequenceNumber),
    scriptFunctionPayload,
    1000n,
    1n,
    BigInt(Math.floor(Date.now() / 1000) + 10),
    new TxnBuilderTypes.ChainId(chainId),
  );
  const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
  const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
  return transactionRes.hash;
}
async function incrCounter(contractAddress: string, accountFrom: AptosAccount): Promise {
  const scriptFunctionPayload = new TxnBuilderTypes.TransactionPayloadScriptFunction(
    TxnBuilderTypes.ScriptFunction.natural(
      `${contractAddress}::MyCounter`,
      "incr_counter",
      [],
      [],
    ),
  );
  const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
    client.getAccount(accountFrom.address()),
    client.getChainId(),
  ]);
  const rawTxn = new TxnBuilderTypes.RawTransaction(
    TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
    BigInt(sequenceNumber),
    scriptFunctionPayload,
    1000n,
    1n,
    BigInt(Math.floor(Date.now() / 1000) + 10),
    new TxnBuilderTypes.ChainId(chainId),
  );
  const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
  const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
  return transactionRes.hash;
}

  • Lấy thông tin tài nguyên trong tài khoản thông qua SDK.

Tài nguyên được lưu trữ dưới địa chỉ tài khoản mà nó thuộc về và chúng tôi có thể truy vấn thông tin tài nguyên có liên quan theo địa chỉ tài khoản.

Phương thức getCounter() thực chất là lấy các tài nguyên **Counter** trong bộ đếm của tôi.


async function getCounter(contractAddress: string, accountAddress: MaybeHexString): Promise {
  try {
    const resource = await client.getAccountResource(
      accountAddress.toString(),
      `${contractAddress}::MyCounter::Counter`,
    );
    return (resource as any).data["value"];
  } catch (_) {
    return "";
  }
}

Trên thực tế, hiệu ứng này tương tự như trong sdk

aptos account list --query resources --account 0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf

chức năng chính cuối cùng

async function main() {
  assert(process.argv.length == 3, "Expecting an argument that points to the helloblockchain module");
  const contractAddress = "0x173d51b1d50614b03d0c18ffcd958309042a9c0579b6b21fc9efeb48cdf6e0b0"; // Chỉ định địa chỉ của hợp đồng đã triển khai trước đó
const bob = new AptosAccount(); // tạo địa chỉ kiểm tra Bob
  console.log("\n=== Addresses ===");
  console.log(`Bob: ${bob.address()}`);
  await faucetClient.fundAccount(bob.address(),5_000); // Airdrop 5000 token thử nghiệm tới địa chỉ của Bob
  console.log("\n=== Initial Balances ===");
  console.log(`Bob: ${await accountBalance(bob.address())}`);
  await new Promise((resolve) => {
    readline.question(
      "Update the module with Alice's address, build, copy to the provided path, and press enter.",
      () => {
        resolve();
        readline.close();
      },
    );
  });
  const modulePath = process.argv[2];
  const moduleHex = fs.readFileSync(modulePath).toString("hex");
  console.log('Init Counter Moudle.');
  let txHash = await initCounter(contractAddress,bob); // khởi tạo tài nguyên Counter dưới bob, lúc này giá trị của Counter dưới bob là 0.
  await client.waitForTransaction(txHash);
  console.log("\n=== Testing Bob Get Counter Value ===");
  console.log(`Initial value: ${await getCounter(contractAddress, bob.address())}`);
  console.log('========== Incr Counter Value, 1th ==========');
  txHash = await incrCounter(contractAddress,bob); // bob gọi phương thức incrCounter một lần và lúc này Counter là 1.
  console.log(txHash);
  await client.waitForTransaction(txHash);
  await Sleep(100);
  console.log(`New value: ${await getCounter(contractAddress,bob.address())}`); // Lấy giá trị Counter dưới địa chỉ của bob và xuất nó.
  console.log('========== Incr Counter Value, 2th ==========');
  txHash = await incrCounter(contractAddress,bob); // bob gọi phương thức incrCounter một lần và Counter là 2.
  console.log(txHash);
  await client.waitForTransaction(txHash);
  await Sleep(100);
  console.log(`New value: ${await getCounter(contractAddress,bob.address())}`); // Lấy giá trị Counter dưới địa chỉ của bob và xuất nó.
  console.log('========== Incr Counter Value, 3th ==========');
  txHash = await incrCounter(contractAddress,bob); // bob gọi phương thức incrCounter một lần và Counter là 3.
  console.log(txHash);
  await client.waitForTransaction(txHash);
  await Sleep(100);
  console.log(`New value: ${await getCounter(contractAddress,bob.address())}`); // Lấy giá trị Counter dưới địa chỉ của bob và xuất nó.
}
if (require.main === module) {
  main().then((resp) => console.log(resp));
}

hiệu lực thi hành

Quá trình thực thi thành công. Tại đây, thông qua SDK, một tài khoản được tạo ngẫu nhiên được bắt đầu bằng tài nguyên Bộ đếm (Bộ đếm = 0), sau đó tăng ba lần, do đó, giá trị cuối cùng của Bộ đếm là 3.

image-20220831200516865

Người giới thiệu

Người giới thiệu

[1]Using CLI to Run a Local Testnet | Aptos Docs: https://aptos.dev/nodes/local-testnet/using-cli-to-run-a-local-testnet

[2] Mã nguồn: https://github.com/aptos-labs/aptos-core/blob/main/aptos-move/framework/move-stdlib/sources/signer.move


Aptos
Chào mừng tham gia cộng đồng chính thức của Odaily
Nhóm đăng ký
https://t.me/Odaily_News
Nhóm trò chuyện
https://t.me/Odaily_CryptoPunk
Tài khoản chính thức
https://twitter.com/OdailyChina
Nhóm trò chuyện
https://t.me/Odaily_CryptoPunk