DAOrayaki: Aptos & Move คำอธิบายเชิงปฏิบัติ
กลุ่มโบนัสการวิจัย DAOrayaki DAO:
ที่อยู่ของทุน: DAOrayaki.eth
ความคืบหน้าการลงคะแนน: DAO Reviewer 3/0 ผ่าน
ประเภทงานวิจัย: Aptos,Layer1
ผู้สร้าง: FF@DoraFactory
บทความนี้อธิบายการทำงานของ aptos cli และ 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
เริ่มเครือข่ายท้องถิ่นของ Aptos
Using CLI to Run a Local Testnet | Aptos Docs[1]
เริ่มห่วงโซ่ท้องถิ่น
ps: โลคัลเชนและข้อมูลที่เริ่มต้นโดยวิธีนี้จะถูกบันทึกไว้ในโฟลเดอร์ปัจจุบันที่คำสั่งนี้เริ่มทำงาน และมีอยู่ในไฟล์ .aptos/
aptos node run-local-testnet --with-faucet
เริ่มสำเร็จ:
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
หลังจากเริ่มต้นสำเร็จ ระบบจะแสดงที่อยู่ของ API ที่เหลือและ Faucet API ในภายหลัง ข้อมูลทั้งสองส่วนนี้จำเป็นต้องได้รับการกำหนดค่าในสภาพแวดล้อม aptos cli
กำหนดค่าสภาพแวดล้อม aptos cli
ในการเข้าถึงและเรียกใช้ห่วงโซ่การทดสอบในเครื่องผ่านบรรทัดคำสั่ง เราจำเป็นต้องกำหนดค่า config สำหรับ aptos cli ตามข้อมูลการปรับใช้ด้านบน
PROFILE=local
aptos init --profile $PROFILE --rest-url --faucet-url
ในระหว่างการดำเนินการ เราจะได้ผลลัพธ์ดังต่อไปนี้ เราสามารถเลือกใส่รหัสลับหรือจะสร้างแบบสุ่มก็ได้
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)]
หลังจากการยืนยัน บัญชีจะถูกสร้างขึ้นและเติมเงินด้วยจำนวนโทเค็นเริ่มต้น
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"
}
จากนี้ไป เราสามารถเรียกใช้งานได้บน local testnet โดยเพิ่ม --profile local ในคำสั่ง
ps: --profile ที่นี่เหมือนกับ kube-config ใน k8s ซึ่งสามารถตั้งค่าสภาพแวดล้อมโปรไฟล์ที่แตกต่างกันและควบคุมเครือข่ายต่างๆ
การกำหนดค่าโปรไฟล์จะตั้งค่าที่อยู่ตัวดำเนินการ node-rest-api และข้อมูล faucet-api
# รายชื่อบัญชีทั้งหมดที่ควบคุมโดย cli
aptos account list
# เติมเงินในบัญชี:
aptos account fund --profile $PROFILE --account $PROFILE
# สร้างบัญชีทรัพยากรใหม่
aptos account create-resource-account --profile $PROFILE --seed 1
#ทำสัญญาย้ายบ้าน
aptos move compile --package-dir hello_blockchain
#ทำตามสัญญา
aptos move publish --package-dir hello_blockchain --named-addresses basecoin= --profile local
#ทวงสัญญา
aptos move run --function-id :::: --profile local
# แสดงรายการข้อมูลโมดูล/ทรัพยากรของบัญชีที่ระบุ
aptos account list --query modules --account 0xa1285adb4b8abedf5faf7a46d260c5844f1f64d59dd9b8869db1543cf5bbadf4 --profile local
aptos account list --query resources --account 0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf --profile local
#สัญญาอัพเกรด
aptos move publish --upgrade-policy
`arbitrary`, `compatible`,`ไม่เปลี่ยนรูป' สอดคล้องกับ 0, 1, 2
0 ไม่ได้ทำการตรวจสอบใด ๆ บังคับให้เปลี่ยนรหัส
1 ตรวจสอบความเข้ากันได้ (ฟังก์ชันสาธารณะเดียวกันไม่สามารถเปลี่ยนเค้าโครงหน่วยความจำของทรัพยากรที่มีอยู่ได้)
2 ข้อห้ามในการอัพเกรด
ทุกครั้งที่เผยแพร่ จะเปรียบเทียบนโยบายในเครือข่ายกับนโยบายของสิ่งพิมพ์นี้ (ค่าเริ่มต้นคือ 1)
อนุญาตให้อัปเกรดสัญญาได้เฉพาะเมื่อนโยบายในครั้งนี้มีขนาดเล็กกว่านโยบายในเครือข่าย
ปรับใช้สัญญาการย้ายอย่างง่าย
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)
}
}
การวิเคราะห์ซอร์สโค้ด MyCounter
โมดูลคือชุดของฟังก์ชันและโครงสร้างแบบแพ็กเกจที่เผยแพร่ภายใต้ที่อยู่เฉพาะ เมื่อใช้สคริปต์ สคริปต์จำเป็นต้องรันด้วยโมดูลที่เผยแพร่หรือไลบรารีมาตรฐาน และไลบรารีมาตรฐานเองก็เป็นกลุ่มของโมดูลที่เผยแพร่ภายใต้แอดเดรส 0x1
โมดูล MyCounterAddr::MyCounter{ } อยู่ภายใต้ที่อยู่ MyCounterAddr (ตรงกับ MyCounterAddr ="0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf") เพื่อสร้างโมดูล
ใช้ std::signer คือการใช้โมดูล signer ภายใต้ไลบรารีมาตรฐาน Signer เป็นชนิดดั้งเดิมที่ไม่สามารถคัดลอกได้ คล้ายกับ Resource ซึ่งมีที่อยู่ของผู้ส่งธุรกรรม เหตุผลประการหนึ่งในการแนะนำประเภทผู้ลงนามคือเพื่อให้ชัดเจนว่าฟังก์ชันใดต้องการสิทธิ์ผู้ส่งและฟังก์ชันใดไม่ต้องการ ดังนั้น ฟังก์ชันจึงไม่สามารถหลอกลวงผู้ใช้ให้เข้าถึงทรัพยากรโดยไม่ได้รับอนุญาต สำหรับรายละเอียด โปรดดูที่ซอร์สโค้ด [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,
}
ใช้ struct เพื่อกำหนดโครงสร้างที่เรียกว่า Counter และในขณะเดียวกันก็แก้ไขโดยตัวจำกัด 2 ชนิด ได้แก่ คีย์และสโตร์
ระบบประเภทของ Move นั้นยืดหยุ่น และแต่ละประเภทสามารถกำหนดความสามารถได้สี่อย่าง
กำหนดว่าค่าของประเภทสามารถคัดลอก ทิ้ง และจัดเก็บได้หรือไม่
ตัวระบุความสามารถทั้งสี่ ได้แก่: คัดลอก วาง จัดเก็บ และคีย์
หน้าที่ของพวกเขาคือ:
คัดลอก - สามารถคัดลอกค่าได้
Drop - สามารถทิ้งค่าได้เมื่อสิ้นสุดขอบเขต
คีย์ - ค่าสามารถเข้าถึงได้เป็นคีย์โดย "การดำเนินการจัดเก็บข้อมูลส่วนกลาง"
ร้านค้า - สามารถเก็บค่าไว้ในสถานะส่วนกลางได้
แก้ไขด้วยคีย์และจัดเก็บที่นี่ หมายความว่าไม่สามารถคัดลอก ทิ้ง หรือใช้ซ้ำได้ แต่สามารถจัดเก็บและถ่ายโอนได้อย่างปลอดภัย
ไวยากรณ์สำหรับความสามารถ
ความสามารถของประเภทดั้งเดิมและประเภทในตัวนั้นถูกกำหนดไว้แล้วและไม่เปลี่ยนรูป: ค่าของจำนวนเต็ม, เวกเตอร์, ที่อยู่และประเภทบูลีนมีความสามารถคัดลอก, วางและจัดเก็บโดยเนื้อแท้
อย่างไรก็ตาม สามารถเพิ่มความสามารถของโครงสร้างได้ตามไวยากรณ์ต่อไปนี้:
struct NAME has ABILITY [, ABILITY] { [FIELDS] }
ตัวอย่างไลบรารีอย่างง่าย:
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 {}
}
ทรัพยากรคืออะไร
แนวคิดของทรัพยากรได้รับการอธิบายโดยละเอียดในเอกสารทางเทคนิค Move ในขั้นต้น มันถูกนำไปใช้เป็นประเภทโครงสร้างที่เรียกว่า ทรัพยากร นับตั้งแต่เปิดตัวความสามารถ มันถูกนำไปใช้เป็นโครงสร้างที่มีความสามารถสองอย่างคือ คีย์ และ สโตร์ ทรัพยากรสามารถเป็นตัวแทนของสินทรัพย์ดิจิทัลได้อย่างปลอดภัย ไม่สามารถคัดลอกหรือทิ้งหรือใช้ซ้ำไม่ได้ แต่สามารถจัดเก็บและถ่ายโอนได้อย่างปลอดภัย
ความหมายของทรัพยากร
ทรัพยากรเป็นโครงสร้างที่จำกัดด้วยคีย์และความสามารถในการจัดเก็บ:
module M {
struct T has key, store {
field: u8
}
}ขีดจำกัดของทรัพยากร
ในโค้ด ประเภททรัพยากรมีข้อจำกัดที่สำคัญหลายประการ:
ทรัพยากรถูกจัดเก็บภายใต้บัญชี ดังนั้นจึงมีอยู่เฉพาะเมื่อมีการกำหนดบัญชีและสามารถเข้าถึงได้ผ่านบัญชีนั้นเท่านั้น
บัญชีสามารถเก็บทรัพยากรประเภทใดประเภทหนึ่งได้ครั้งละหนึ่งรายการเท่านั้น
ไม่สามารถคัดลอกทรัพยากรได้ สอดคล้องกันเป็นชนิดพิเศษ: ทรัพยากรซึ่งแตกต่างจากที่คัดลอกได้ซึ่งได้รับการแนะนำในบทเกี่ยวกับข้อมูลทั่วไป (สิ่งนี้สามารถสรุปได้ถึงความเป็นเจ้าของของ Rust)
ต้องใช้ทรัพยากร ซึ่งหมายความว่าทรัพยากรที่สร้างขึ้นใหม่จะต้องถูกย้ายภายใต้บัญชี และทรัพยากรที่ย้ายจากบัญชีจะต้องแยกส่วนหรือจัดเก็บภายใต้บัญชีอื่น
เรื่องเมื่อกี้
struct Counter has key, store {
value:u64,
}
ดังนั้นนี่คือความแตกต่างจาก solidity หากจำเป็นต้องออกสินทรัพย์ใหม่บน eth เช่น usdc จากนั้นสินทรัพย์นี้จะถูกบันทึกไว้ในแผนที่ในสัญญา แต่การย้ายนั้นแตกต่างออกไป เนื้อหาจะถูกเก็บไว้ภายใต้ที่อยู่ของผู้ใช้เป็นทรัพยากร
กำหนดฟังก์ชัน
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)
}
รูปแบบคำจำกัดความคือ:
ชื่อฟังก์ชัน public fun (พารามิเตอร์: ประเภทพารามิเตอร์) { }
ฟังก์ชันการย้ายเป็นแบบส่วนตัวโดยค่าเริ่มต้น และสามารถเข้าถึงได้ภายในโมดูลที่กำหนดไว้เท่านั้น คำหลักสาธารณะจะเปลี่ยนการเปิดเผยเริ่มต้นของฟังก์ชันและทำให้เป็นสาธารณะ กล่าวคือ สามารถเข้าถึงได้จากภายนอก
พารามิเตอร์ของเมธอด init คือ &signer ซึ่งหมายความว่าเมธอดนี้สามารถเรียกได้หลังจากบัญชีได้รับการเซ็นชื่ออย่างถูกต้องตามกฎหมายเท่านั้น move_to เป็นคำสั่งดั้งเดิมของ move ซึ่งใช้เพื่อเผยแพร่และเพิ่มทรัพยากร Counter ไปยังที่อยู่ของผู้ลงนาม ในรูปแบบบัญชีของ Move รหัสและข้อมูลจะถูกเก็บไว้ภายใต้ที่อยู่บัญชี
ต่อไปนี้เป็นรายการของพื้นฐานที่ใช้กันทั่วไป
move_to< T >(&signer,T): เผยแพร่และเพิ่มทรัพยากรประเภท T ไปยังที่อยู่ของผู้ลงนาม
move_from< T >(addr: ที่อยู่): T - ลบทรัพยากรประเภท T ออกจากที่อยู่และส่งคืนทรัพยากรนี้
borrow_global< T >(addr: ที่อยู่): &T - ส่งกลับการอ้างอิงที่ไม่เปลี่ยนรูปไปยังทรัพยากรประเภท T ที่ที่อยู่
borrow_global_mut< T >(addr: ที่อยู่): &mut T - ส่งกลับการอ้างอิงที่ไม่แน่นอนไปยังทรัพยากรประเภท T ที่ที่อยู่
exists< T >(ที่อยู่): บูล: กำหนดว่ามีทรัพยากรประเภท T อยู่ใต้ที่อยู่หรือไม่
พารามิเตอร์ของเมธอด incr ยังเป็น &signer ซึ่งหมายความว่าเมธอดต้องได้รับการเซ็นชื่อตามกฎหมายโดยบัญชีก่อนจึงจะสามารถเรียกใช้ได้
คำสำคัญที่ได้รับซึ่งวางไว้หลังค่าส่งคืนของฟังก์ชัน ใช้เพื่อกำหนดทรัพยากรทั้งหมดที่ได้รับจากฟังก์ชันนี้อย่างชัดเจน
ผู้ลงนาม::address_of(บัญชี) รับที่อยู่จากผู้ลงนาม
ดังที่กล่าวไว้ข้างต้น border_global_mut ตัวแปรจะยืมตัวนับทรัพยากรภายใต้ที่อยู่ จากนั้นจึงดำเนินการ +1 กับค่าภายใต้โครงสร้างตัวนับ
สองเมธอดต่อไปนี้คือเมธอดของสคริปต์ อะไรคือความแตกต่างระหว่างเมธอดทั้งสองและฟังก์ชันข้างต้น
ความสนุกสาธารณะ : สามารถเรียกใช้เมธอดในโมดูลใดก็ได้
public(script) fun / public entry fun: ฟังก์ชันสคริปต์เป็นเมธอดการป้อนข้อมูลในโมดูล ซึ่งหมายความว่าสามารถเรียกเมธอดได้โดยเริ่มต้นธุรกรรมผ่านคอนโซล เช่นเดียวกับการรันสคริปต์ในเครื่อง
Move เวอร์ชันถัดไปจะแทนที่ความสนุกแบบสาธารณะ (สคริปต์) ด้วยความสนุกแบบสาธารณะ
Self แสดงถึงโมดูลของตัวเอง
ใช้ Aptos Cli เพื่อคอมไพล์ ปรับใช้ และเรียกสัญญา
# สร้างสภาพแวดล้อมการทดสอบใหม่
aptos init --profile devtest --rest-url --faucet-url
#ทำสัญญาย้ายบ้าน
aptos move compile --package-dir my-counter
#ทำตามสัญญา
# ตัวอย่างเช่น: 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
#ทวงสัญญา
# ตัวอย่างเช่น:
# 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
# แสดงรายการข้อมูลโมดูล/ทรัพยากรของบัญชีที่ระบุ
aptos account list --query modules --account 0xa1285adb4b8abedf5faf7a46d260c5844f1f64d59dd9b8869db1543cf5bbadf4 --profile devtest
aptos account list --query resources --account 0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf --profile devtest
Aptos SDK เรียกสัญญา Move
หลังจากรวบรวมสัญญาแล้ว เราสามารถเรียกสัญญาของเราผ่าน sdk
เราสามารถเลือกที่จะปรับใช้สัญญาผ่าน sdk หรือเรียกสัญญาการย้ายผ่าน sdk
ปรับใช้สัญญาผ่าน sdk
เมื่อเรารวบรวม build/ โฟลเดอร์จะถูกสร้างขึ้นภายใต้โฟลเดอร์สัญญาการย้าย
เราจำเป็นต้องคัดลอกไฟล์ my-counter/build/Examples/bytecode_modules/MyCounter.mv ไปยังสคริปต์ SDK
aptos move compile --package-dir my-counter
cp MyCounter.mv my-counter-sdk-demo/
ปรับใช้รหัส sdk ที่เกี่ยวข้องกับสัญญา
/** 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;
}
ส่งธุรกรรมผ่าน SDK
ที่นี่ เราใช้ init_counter และ incr_counter ในสัญญา my-counter เป็นตัวอย่าง
สร้างเมธอดสองเมธอดเพื่อเรียกเมธอดทั้งสองนี้ เพื่อให้ไคลเอนต์สามารถเรียกใช้ฟังก์ชัน init และ incr ได้
async function initCounter(contractAddress: string, accountFrom: AptosAccount): Promise
const scriptFunctionPayload = new TxnBuilderTypes.TransactionPayloadScriptFunction(
TxnBuilderTypes.ScriptFunction.natural(
`${contractAddress}::MyCounter`,// ที่อยู่สัญญา::ชื่อสัญญา
"init_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;
}
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;
}
รับข้อมูลทรัพยากรในบัญชีผ่าน SDK
ทรัพยากรถูกจัดเก็บภายใต้ที่อยู่บัญชีที่เป็นเจ้าของ และเราสามารถสืบค้นข้อมูลทรัพยากรที่เกี่ยวข้องตามที่อยู่บัญชีได้
เมธอด getCounter() คือการรับทรัพยากร **Counter** ภายใต้ my-counter
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 "";
}
}
อันที่จริงแล้วเอฟเฟกต์นี้คล้ายกับใน sdk
aptos account list --query resources --account 0x4200c2b801870f20a709abba80b6edb90a45ecd9b8acce9842b93d597602edcf
หน้าที่หลักขั้นสุดท้าย
async function main() {
assert(process.argv.length == 3, "Expecting an argument that points to the helloblockchain module");
const contractAddress = "0x173d51b1d50614b03d0c18ffcd958309042a9c0579b6b21fc9efeb48cdf6e0b0"; // ระบุที่อยู่ของสัญญาที่ใช้งานก่อนหน้านี้
const bob = new AptosAccount(); // สร้างที่อยู่ทดสอบ Bob
console.log("\n=== Addresses ===");
console.log(`Bob: ${bob.address()}`);
await faucetClient.fundAccount(bob.address(),5_000); // ส่งโทเค็นทดสอบ Airdrop 5,000 รายการไปยังที่อยู่ของ Bob
console.log("\n=== Initial Balances ===");
console.log(`Bob: ${await accountBalance(bob.address())}`);
await new Promise
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); // init Counter ทรัพยากรภายใต้ bob ขณะนี้ค่าของ Counter ภายใต้ bob คือ 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 เรียกใช้เมธอด incrCounter หนึ่งครั้ง และตอนนี้ Counter เป็น 1
console.log(txHash);
await client.waitForTransaction(txHash);
await Sleep(100);
console.log(`New value: ${await getCounter(contractAddress,bob.address())}`); // รับค่า Counter ใต้ address ของ bob แล้วส่งออก
console.log('========== Incr Counter Value, 2th ==========');
txHash = await incrCounter(contractAddress,bob); // bob เรียกใช้เมธอด incrCounter หนึ่งครั้ง และตัวนับคือ 2
console.log(txHash);
await client.waitForTransaction(txHash);
await Sleep(100);
console.log(`New value: ${await getCounter(contractAddress,bob.address())}`); // รับค่า Counter ใต้ address ของ bob แล้วแสดงผลออกมา
console.log('========== Incr Counter Value, 3th ==========');
txHash = await incrCounter(contractAddress,bob); // bob เรียกใช้เมธอด incrCounter หนึ่งครั้ง และตัวนับคือ 3
console.log(txHash);
await client.waitForTransaction(txHash);
await Sleep(100);
console.log(`New value: ${await getCounter(contractAddress,bob.address())}`); // รับค่า Counter ใต้ address ของ bob แล้วส่งออก
}
if (require.main === module) {
main().then((resp) => console.log(resp));
}
ผลการดำเนินการ
การดำเนินการสำเร็จ ที่นี่ ผ่าน SDK บัญชีที่สร้างขึ้นแบบสุ่มเริ่มต้นด้วยทรัพยากรตัวนับ (ตัวนับ=0) จากนั้นเพิ่มขึ้นสามครั้ง ดังนั้นค่าสุดท้ายของตัวนับคือ 3
image-20220831200516865
อ้างอิง
อ้างอิง
[1]Using CLI to Run a Local Testnet | Aptos Docs: https://aptos.dev/nodes/local-testnet/using-cli-to-run-a-local-testnet
[2] ซอร์สโค้ด: https://github.com/aptos-labs/aptos-core/blob/main/aptos-move/framework/move-stdlib/sources/signer.move


