สร้าง Smart Contract บน Near Protocol ด้วย Assembly Script
เป้าหมายคือ ต้องการสร้าง Smart Contract ด้วย Assembly Script ตั้งแต่เริ่มต้น โดยดูจาก NEAR Example - Guestbook ซึ่งจริงๆ แค่เรา clone โปรเจ็คมารัน ก็ได้แล้ว และถ้าอ่านโค๊ดก็เข้าใจไม่ยาก แต่อยากรู้ว่าถ้าเราเริ่มสร้างตั้งแต่เริ่มต้นเลย มันมีขั้นตอนยังไง มันก็จะทำให้เราเข้าใจมากขึ้นรึเปล่า ก็เลยเป็นที่มาของการทดลอง และสรุปเป็นบทความนี้ขึ้นมา
- Near Examples - มีตัวอย่างหลายโปรเจ็ค สามารถไปดูได้ครับ (จริงๆ ตัว Project Counter น่าจะง่ายสุด เผื่อบางคนไม่รู้จะเริ่มตัวไหน)
สิ่งที่ต้องการเรียนรู้คือวิธีการสร้าง Smart Contract ด้วย AssemblyScript ทำให้ในบทความนี้ไม่ได้พูดถึงส่วนของ Frontend นะครับ แต่จะเป็นการ call / view ผ่าน near-cli เพื่อดูว่า ตัว smart contract เรา deploy ถูกต้อง
ทำไมถึงเลือก AssemblyScript?
จริงๆ แล้ว ไม่มีอะไรมาก แค่อยากลองดูและเปรียบเทียบกับ Rust และตัว AssemblyScript ก็เหมือน TypeScript มากๆ สิ่งที่ต่างคือ ตัว AssemblyScript เวลา compiled จะเป็นไฟล์ WebAssembly (WASM) ไม่ใช่ JavaScript แบบ TypeScript แต่ตัว syntax เรียกได้ว่าแทบจะเหมือนกัน ใครเขียน TypeScript ได้ ก็เขียน AssemblyScript ได้ครับ
Prerequisites
สิ่งที่ต้องมีเลย แน่ๆ คือ
- near-cli ถ้าไม่มีก็ติดตั้งด้วยคำสั่ง :
npm install --global near-cli
- Near Wallet ถ้าไม่มี? สมัคร Near Wallet (Testnet)
Setup Project
ขั้นตอนแรก ทำการสร้างโปรเจ็คขึ้นมา ผมตั้งชื่อว่า near-guestbook-as โดยข้างในจะมี folder คือ
- contract - เป็นไฟล์ที่เอาไว้เก็บ smart contract เขียนด้วย assemblyscript
เริ่มต้นสร้าง โฟลเดอร์ contract ก่อน
mkdir contract
cd contract
จากนั้น initial project (ข้างในโฟลเดอร์ contract นะครับ)
npm init -y
และติดตั้งพวก dependencies ลงไป
npm install @assemblyscript/loader@latest assemblyscript@latest asbuild near-cli near-sdk-as
Note: ตัว AS ล่าสุดคือ 0.20.4 และคิดว่าน่าจะมีอัพเดทเรื่อยๆ ณ ตอนเขียนบทความคือไม่มีปัญหา แต่ถ้าอนาคต มีเวอร์ชั่นใหม่ อาจจะมี breaking change ถ้าเจอปัญหา ลองดู changelog ดูนะครับ หรือ fix เวอร์ชั่นครับ
สำหรับ Mac M1 จะมีปัญหาการติดตั้ง near-sdk-as ขึ้นว่า Error: Unsupported platform: Darwin arm64 ให้ทำการติดตั้งด้วย คำสั่ง
npm install near-sdk-as --ignore-scripts
ต่อมาเราจะขึ้นโปรเจ็คด้วย asinit script:
npx asinit .
ตัว asinit
จะทำการสร้าง folder และ config files ให้เรา auto เลย ก็แค่กด Y ยืนยัน
สามารถอ่าน Setting up a new project - AssemblyScript เพิ่มเติมได้ครับ วิธีการขึ้นโปรเจ็ค asinit
near-sdk-as
เราจะทำการปรับแก้ไฟล์นิดหน่อย เพื่อให้ตัว AssemblyScript มัน build และ compile ให้ตรงกับ near-sdk-as
สิ่งที่ต้องทำคือ ทำการแก้ไขไฟล์ asconfig.json
โดยเปลี่ยนที่ตัว asinit
generate มาให้ เป็น config ของ near-sdk-as แทน แบบนี้
{
"extends": "near-sdk-as/asconfig.json",
"entry": "assembly/main.ts"
}
- เราจะใช้ไฟล์
main.ts
เป็นหลัก จึงต้องระบุ entry ให้มัน
ต่อมาเพิ่ม reference type ที่ไฟล์ assembly/as_types.d.ts
/// <reference types="near-sdk-as/assembly/as_types" />
สร้าง Contract
ตัว Contract ที่เป็น AssemblyScript มี 2 ไฟล์ คือ main.ts
และ model.ts
ตัว main.ts
มีแค่นี้เอง (ถ้าลบ comment ออก)
import { PostedMessage, messages } from "./model";
const MESSAGE_LIMIT = 10;
export function addMessage(text: string): void {
const message = new PostedMessage(text);
messages.push(message);
}
export function getMessages(): PostedMessage[] {
const numMessages = min(MESSAGE_LIMIT, messages.length);
const startIndex = messages.length - numMessages;
const result = new Array<PostedMessage>(numMessages);
for (let i = 0; i < numMessages; i++) {
result[i] = messages[i + startIndex];
}
return result;
}
addMessage (call)
- ก็เพิ่ม text ลง Storage (persistent collection)getMessages (view)
- ก็แสดงข้อมูล text (PostedMessage model) ตามจำนวน max ที่เป็นค่า constants ที่เรากำหนดไว้ อันนี้ก็ loop ธรรมดา
ส่วนตัว model.ts
ก็ใช้ Collection ของ near-sdk-as
import { context, u128, PersistentVector } from "near-sdk-as";
@nearBindgen
export class PostedMessage {
premium: boolean;
sender: string;
constructor(public text: string) {
this.premium =
context.attachedDeposit >= u128.from("10000000000000000000000");
this.sender = context.sender;
}
}
export const messages = new PersistentVector<PostedMessage>("guestbook_prefix");
messages
- เป็น PersistentVector ถ้าค่าเปลี่ยน เช่น.push()
มันจะทำการเซฟลงใน storage ให้อัตโนมัติ (ลองดูไฟล์main.ts
ตรง functionaddMessage
เราแค่ push เอง แต่ข้อมูลเซฟลง storage ให้เลย)context.sender
- ก็อารมณ์คล้ายๆmsg.sender
ของ Solidity
ทดลอง build ดูว่าผ่านมั้ย เพิ่ม script ลงไปใน package.json
ส่วน scripts
"scripts": {
"build": "asb --target debug",
"build:release": "asb"
}
ลอง build ดู (ตัว asb
จะเป็น AssemblyScript build tool นะครับ คล้ายๆกับ Cargo ที่รัน rustc (rust compiler) ในขณะที่ asb
จะรัน asc
(AssemblyScript Compiler))
npm run build
ถ้าไม่มีอะไรผิดพลาด ก็ build release:
npm run build:release
ตัวไฟล์ build ที่ได้ จะอยู่ folder /build/release/main.wasm
นะครับ
Deploy & Test
สุดท้าย ทดสอบ deploy ตัว Contract โดยผมใช้ subaccount นะครับ ตอนนี้ผมใช้ supersaiyan.testnet
near create-account guestbook.supersaiyan.testnet --masterAccount supersaiyan.testnet --initialBalance 2
เวลา deploy ผมก็ใช้ คำสั่ง near deploy
ก็เลยเอาไปใส่ใน scripts ใน package.json
ซะ
"scripts": {
"deploy": "near deploy --wasmFile build/release/main.wasm --accountId guestbook.supersaiyan.testnet"
}
ทดลอง Deploy
npm run deploy
ตัวอย่าง ผม deploy ลง testnet เรียบร้อย ได้ผลลัพธ์ดังนี้
Transaction Id H9CmfDFpwDMHg5gcEVS1gf6GTGD4oHFnMy9iaz4738dU
To see the transaction in the transaction explorer, please open this url in your browser
https://explorer.testnet.near.org/transactions/H9CmfDFpwDMHg5gcEVS1gf6GTGD4oHFnMy9iaz4738dU
Done deploying to guestbook.supersaiyan.testnet
ทดลอง View contract ที่ deploy ไป
near view guestbook.supersaiyan.testnet getMessages '{}'
ตอนแรกจะไม่มีข้อมูล จนกว่าจะ call เพื่อเพิ่มข้อมูล (ถ้าใครเทสหลังจากอ่านบทความนี้ จะมีข้อมูลนะครับ เพราะผม addMessage ไปเพิ่ม)
ลอง Call เพื่อเพิ่มข้อมูล
near call guestbook.supersaiyan.testnet addMessage '{"text": "Hello Devahoy"}' --account-id supersaiyan.testnet
เป็นอันเรียบร้อย ก็รู้สึกว่าการ setup ตัว AssemblyScript ก็ไม่ได้ยุ่งยากเท่าไหร่ สิ่งที่ต้องรู้เพิ่มคือพวก Collection ว่ามันมีอะไรบ้าง?
อ่านเพิ่มเติม
- Near AssemblyScript - Introduction
- AssemblyScript Book - เผื่อหลายคนสนใจ AS
สุดท้าย Source Code ประกอบบทความ
สรุป
หลังจากบทความก่อนหน้า ผมได้ลอง Deploy Smart Contract แรกบน NEAR Protocol ไปแล้ว แต่เป็นแบบเขียนด้วย Rust วันนี้เลยลองด้วย AssemblyScript ดู ว่ามันง่ายกว่าจริงมั้ย ซึ่งหลายๆ คนก็แนะนำว่า ควรเริ่มจาก AssemblyScript เพื่อให้เข้าใจ concept คร่าวๆ แต่ถ้าไปใช้งานจริงๆ หรือทำ Smart Contract จริงๆ ตัว NEAR Official ยังแนะนำเลยว่าควรเป็น Rust และเหมือนอนาคตเค้าก็จะโฟกัสที่ Rust เป็นหลักครับ
หวังว่าการทดลองเล็กๆน้อยๆ ของผมจะเป็นประโยชน์กับหลายๆคนนะครับ ไม่รู้ว่าบทความแนวๆนี้จะมีคนชอบหรือเปล่า 😂
Happy Coding ❤️
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit