สร้าง ERC-20 Token ด้วย ink! Part 1/2
วันนี้มาลองสร้าง ERC-20 token ด้วย ink! ครับ ซึ่งถ้าหากใครไม่เคยเขียน ink! มาก่อน หรือภาษา Rust มาก่อน แนะนำอ่านบทความก่อนหน้านี้ที่ผมได้เขียนไว้ครับ ทดลองเขียน Smart Contract ด้วย ink! + Rust + Substrate
ซึ่งตัว ERC-20 Token หลักๆ ก็จะเหมือนกับ ERC-20 ของฝั่ง EVM นั่นแหละครับ โดยเนื้อหา Tutorial ผมอ้างอิงจาก Build an ERC-20 token contract
เนื้อหามี 2 ตอนนะครับ
- สร้าง ERC-20 Token ด้วย ink! Part 1/2 (บทความนี้)
- สร้าง ERC-20 Token ด้วย ink! Part 2/2
เตรียมตัวกันก่อน
สำหรับใครที่เพิ่งมาอ่านบทความนี้ ก็ลองเตรียมความพร้อม Rust และ Toolchain รวมถึง Substrate Contract Node จากบทความนี้ได้ครับ เตรียมเครื่องมือสำหรับ Substrate Development และควรมีพื้นฐาน Rust และ ink! เบื้องต้นครับ แนะนำอ่านบทความก่อนหน้าของผมได้ครับ สำหรับคนที่ยังไม่เคยเขียน ink!
ERC-20 Standard
เราจะอ้างอิงตัว ERC-20 นี้นะครับ ซึ่งเป็น standard ที่ใช้มากที่สุดใน Ethereum blockchain หน้าตาคร่าวๆ ของมันก็มีดังนี้
หลักๆ ก็คือ เป็น Interace ที่บอกให้รู้ไว้ว่า Token มีความสามารถอะไรบ้าง เช่น
totalSupply
- แสดง totalSupply ได้balanceOf
- เพื่อดู balance ของ address นั้นๆtransfer
,trasferFrom
- สำหรับ ส่ง token ระหว่าง address เป็นต้น
จะเห็นว่า Interface ด้านบนเป็น Solidity แต่ว่าสำหรับ ink! ที่เขียนด้วย Rust ตัว return ทีเป็น bool
ใน Rust ก็จะใช้ Result
แทนนะครับ ส่วนที่เหลือ ก็แทบจะเหมือนๆกัน
Step 1 - Create new contract
สร้างโปรเจ็คขึ้นมา โดยใช้ Cargo Contract
จะได้โฟลเดอร์ชื่อ erc20 เปลี่ยนข้างในไฟล์ lib.rs
เป็น ด้านล่าง
ตัว Source Code จากเว็บ Substrate ink! workshop
ทดสอบ verify ดูว่า test ผ่านมั้ย
รอ cargo compile ซักนิด ถ้าไม่มี dependencies เลย มันก็จะไปดาวน์โหลดและ compiled ครับ ถ้าเทสผ่าน จะได้ผลลัพธ์ประมาณนี้
เมื่อเทสผ่าน ลอง build เป็น WebAssembly contract ดู
เมื่อ build เสร็จเราจะได้ไฟล์ erc20.contract
ในโฟลเดอร์ target/ink
สามารถ นำไฟล์นี้ไป deploy ผ่าน Contract UI ดูได้ครับ
สามารถกลับไปอ่านบทความก่อนหน้านี้ เรื่องของการ Deploy ผ่าน Contracts UI ได้ที่บทความ ทดลองเขียน Smart Contract ด้วย ink! + Rust + Substrate
Step 2 - Transfer tokens
ณ ตอนนี้ ตัว ERC-20 contract ของเรา จะมีแค่ 1 user account ที่เป็นเจ้าของ total_supply ของ token อยู่ วิธีที่จะทำให้ contract สมบูรณ์ ก็คือ ต้องสามารถ transfer tokens ให้ accounts อื่นๆ ได้
Logic ในการ transfer คือ
- ดูค่า balance ของ account
from
และto
- เช็คดูว่าเงินของ
from
น้อยกว่าvalue
หรือเปล่า? มีเงินแค่ 100 เดียว แต่จะส่ง 1แสน ต้องส่งไม่ได้ :) - หักเงินจาก
from
และเพิ่มเงินให้to
ด้วยจำนวนvalue
เพิ่ม Error type ที่บรรทัดที่ 8 ต่อจาก use ink_storage::
ในไฟล์ lib.rs
เขียน function transfer()
เพื่อให้ contract caller สามารถส่ง token ให้ account อื่นได้
วางต่อจากฟังค์ชั่น balance_of()
ได้เลย
ลองเทส ดูว่า ว่าผลลัพธ์เป็นยังไง
Step 3 - Events
ต่อมาเราจะสร้าง Event โดยปกติแล้ว ตัว contract ไม่สามารถ return value ตรงๆ ได้ (ต้องรอ confirm) ฉะนั้น วิธีที่จะทำให้ client รู้ได้ ก็คือรู้ผ่าน Event นั่นเอง
Event ใน ink! เราจะกำหนดเป็น strcut ครับ โดยใช้ attribute #[ink(event)]
เพิ่ม struct ต่อจากบรรทัด pub type Result<T> = core::result::Result<T, Error>;
ได้เลย
การ Emit event เราจะกำหนด ให้ emit 2 ส่วนคือ
- ตอนที่
new
- เพื่อ initialize contract (ขั้นตอนนี้ไม่มีto
ฉะนั้นto
จึงเป็นNone
ได้) - ทุกๆ ครั้งที่เรียก function
transfer_from_to
เพิ่ม emit event ที่ function new_init()
และเพิ่ม emit ใน transfer_from_to()
แบบนี้
ลองเพิ่มเทส transfer ใน mod tests
ดู
ทดสอบรันเทสอีกครั้ง
จะมี 3 tests และผ่านหมด แสดงว่า เราทำถูกต้อง
🎉 เบื้องต้น ตอนนี้เราก็สามารถทำเหรียญ ERC-20 token โดยใช้ ink! ได้แล้ว แต่ความสามารถของมันก็ยังไม่ได้มีแค่ transfer ต่อไป Part 2 เราจะมาต่อด้วยเรื่องของการ Approve token และการ transfer เหรียญจาก account คนอื่น (ขอสิทธ์แล้ว) ว่าทำยังไงนะครับ
สำหรับตอนนี้ แนะนำว่า ลองทบทวน และลองอ่านโค๊ดดูครับ และพยายามทำความเข้าใจดูว่าโค๊ดมันทำงานยังไง ถ้าอ่านไม่เข้าใจ แนะนำ ลองไปอ่าน Rust Book บท 1-6 เพิ่มเติมครับ รวมถึง ink! Doc เพิ่มเติม เรื่องของ Attributes นะครับ
ไว้มาต่อ Part 2 เร็วๆนี้ครับ
Happy Coding ❤️
References
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust