เข้าใจ ERC20 Protocol
บน Ethereum นอกจากใช้โอนเหรียญ Ether ไปมาได้แล้ว เรายังสามารถสร้าง Smart Contract หรือเรียกว่าหนังสือสัญญาที่มี programming logic ได้ด้ว
สกุลเงินบนระบบปิด
หนึ่งในการประยุกต์ใช้ Smart Contract ที่นิยมกันคือการสร้างสกุลเงิน โดยปกติถ้าเราสร้างสกุลเงินในโปรแกรมที่อยู่ในรูปแบบ centralized อาทิ เงินใน เกม Online เราจะไม่สามารถแลกเปลี่ยนเป็นเงินสกุลอื่นได้อย่างสบายใจ เพราะข้อมูลบัญชีถูกเก็บอยู่ในใน server ตัวเดียว และถูกปิดไว้ไม่ให้คนอื่นตรวจสอบ
สกุลเงินบนระบบเปิด
แต่เมื่อสกุลเงินมาอยู่ในรูปแบบ Smart Contract บน Ethereum ข้อมูลจะถูกเก็บอยู่ใน decentralized database ดังนั้น ทุกคนสามารถตรวจสอบได้, ปลอมแปลงไม่ได้ และที่สำคัญที่สุดเราสามารถแลกเปลี่ยนเป็นสกุลเงินอื่นได้ โดยไม่ต้องขออนุญาติคนสร้างเหรียญเลยด้วยซ้ำ
เพียงแต่เราต้องทำให้ตรงมาตรฐาน ซึ่งมาตรฐานที่ได้รับความนิยมมากที่สุดบน Ethereum คงเป็นอะไรไปไม่ได้ นอกจาก ERC20
มาตรฐาน ERC20 Token
มาตรฐานในแง่ของ solidity คือ Smart Contract เราต้องมี function ตามที่กำหนด โดยมี function 6 ตัว และมี event 2 ตัว ดังนี้
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
ฟังชั่นเหล่านี้เอาไว้ให้ App เข้ามาใช้งาน Smart Contract ของเรา ขอย้ำอีกทีว่าข้อมูลเหรียญเราเป็น public อยู่บน decentralized database ดังนั้นใครก็เข้ามาใช้งาน Smart Contract ตรงนี้ได้
ข้อสังเกต: ตัวเลขที่เกี่ยวข้องกับสกุลเงิน ในภาษา solidity มักจะไม่เก็บเป็นทศนิยม เพราะเสี่ยงต่อการปัดทศนิยมผิด และจะไม่มี ประจุ +/- สังเกตจากตัวแปรข้างล่างเป็น uint หรือ unsigned interger ทั้งหมด
ผมจะยกตัวอย่างการเรียก function ผ่าน web3
ไปด้วย
totalSupply()
ต้องตรวจสอบปริมาณเหรียญทั้งหมดได้
const dcen = await DcenCoin.deployed()
const balance = await dcen.totalSupply()
// 12000000000000000000000000
balanceOf(address tokenOwner)
ต้องเช็คยอด token ของแต่ละ address ได้
const dcen = await DcenCoin.deployed()
let balance = await dcen.balanceOf('0x3F3783Be816135bDC8210E998f9409559258295B')
// 50000000000000
transfer(address to, uint tokens)
สั่งโอนเงินได้โดยระบุ address ปลายทาง และ จำนวนเงิน เมื่อโอนเสร็จ เราจะได้ transaction log ที่ถูกเซฟบน Ethereum กลับมา
const dcen = await DcenCoin.deployed()
await dcen.transfer('0x413E8682a1Ff2F31da606cCa7CA266c2fC71d959', 10000)
//{ tx:
'0x28a43bff4a19743b67bcc746cab0bb8fd56e6abbcacbf8ba866c2ce6a59dac14'............. other fields }
transfer()
จะได้ transaction log กลับมา เพราะเป็นการโอนเงิน จึงมีการบันทึกข้อมูลผ่านการทำ transaction ในขณะที่totalSupply()
และ balanceOf()
เป็นการอ่านข้อมูลอย่างเดียว
approve(address spender, uint tokens)
ใช้กันเงินให้อีก address เหมือนกับทำแคชเชียร์เช็คโอนเงินให้
const dcen = await DcenCoin.deployed()
const approve = await dcen.approve(accountB, 500))//{ tx:
'0x2f41c168ec9ab0270487662ad03e24c9c28d3eb8e9a0f2d52d67f247bd162634'............. other fields }
ได้ transaction log กลับมา เพราะเป็นการบันทึกข้อมูลลง transaction เหมือนกับ transfer()
allowance(address tokenOwner, address spender)
ใช้ตรวจสอบยอดเงินที่ approve()
ไว้
const dcen = await DcenCoin.deployed()
const approve = await dcen.allowance(accountA, accountB))//500
transferFrom(address from, address to, uint tokens) public returns (bool success)
สั่งโอนเงินที่ approve()
ไว้ เหมือนเอาเช็คไปเบิก
const dcen = await DcenCoin.deployed()
const transfer = await dcen.transferFrom(accountA, accountB, 500, { from: accountB })//{ tx:
'0x2f41c168ec9ab0270487662ad03e24c9c28d3eb8e9a0f2d52d67f247bd162634'............. other fields }
ข้อสังเกต ต้องเป็นฝั่งรับไปสั่งเบิก
Transfer(address indexed from, address indexed to, uint tokens)
เป็น event ที่ถูกเรียก เมื่อโอนเกิดขึ้น มาตรฐานบังคับให้ใส่ emit Transfer()
ในฟังชั่น transfer()
และ transferFrom()
ด้วย
const dcen = await DcenCoin.deployed()dcen.Transfer().watch(function(error, event) {
if (!error) {
console.log(event)
}
})//{ logIndex: 0,
transactionIndex: 0,
transactionHash:
'0x2a078c49881317937d488fe4f66c9edbccc062ec9f2a2722247f5c83e2f6b83f',
blockHash:
'0xcfddbf63817699a8d05f3f057444807966b6cb919562b6008b2d881b0a1b8810',
blockNumber: 24,
address: '0x999afcad66cf38b00c4e46765c6529f3ebb38aaa',
type: 'mined',
event: 'Transfer',
args:
{ from: '0x3f3783be816135bdc8210e998f9409559258295b',
to: '0x413e8682a1ff2f31da606cca7ca266c2fc71d959',
value: BigNumber { s: 1, e: 4, c: [Array] } } }
Approval(address indexed tokenOwner, address indexed spender, uint tokens)
เป็น event ที่ถูกเรียก เมื่อมีการกันเงิน มาตรฐานบังคับให้ใส่ emit Approval()
ในฟังชั่น approve()
ด้วย
const dcen = await DcenCoin.deployed()dcen.Approval().watch(function(error, event) {
if (!error) {
console.log(event)
}
})//{ logIndex: 0,
transactionIndex: 0,
transactionHash:
‘0x565a74d183baa57c4626813d893fbbc7f2d10931ce9cdf3682ffce64a7ad4be2’,
blockHash:
‘0x505e2399b9b5cbe137462e9e96282929282343445b7acac8e5a537123cbcfa97’,
blockNumber: 30,
address: ‘0xb78ad8dfdea449b1299294eec8f186def98fc7d6’,
type: ‘mined’,
event: ‘Approval’,
args:
{ owner: ‘0x3f3783be816135bdc8210e998f9409559258295b’,
spender: ‘0x413e8682a1ff2f31da606cca7ca266c2fc71d959’,
value: BigNumber { s: 1, e: 12, c: [Array] } } }
จับรวมกลุ่ม
totalSupply(), balanceOf()
และ transfer()
เป็น basic function ที่ตรงตัวตามความหมาย
approve(), allowance()
และ transferFrom()
เป็น advanced function ที่ใช้เมื่อเชื่อมต่อกับ Smart Contract ตัวอื่น โดยปกติจะ transferFrom()
จะถูกเรียกภายใน function ของ Smart Contract อีกตัว โดย function นั้นจะเช็คยอดผ่าน allowance()
และ execute ฟังชั่นที่ต้องใช้ token แลกเปลี่ยน จากนั้นกลับมาสั่ง transferFrom()
เพื่อสั่งโอนเงิน
เช่น function sendDigitalDogs()
ใน Smart Contract ของเว็บขายสุนัข digital ในคำสั่งนี้จะเช็คยอดผ่านคำสั่ง allowance()
เมื่อมั่นใจว่ายอดถึงตามกำหนด ก็ส่ง digital dog และ สั่งโอนเงินผ่าน transferFrom()
Transfer() Approval()
จะถูก listener ใช้รอเฝ้าดูว่ามีการโอน หรือ การกันเงินให้
เช่น เว็บขายสุนัข digital จะสร้างตัวเฝ้าดู Approval()
event เมื่อมีการ approval และเช็ค address to address from เมื่อตรงตามเงื่อนไข ก็จะสั่ง sendDigitalDogs()
เพื่อโอนเงิน
สรุป
ด้วยธรรมชาติของ decentralized database และการมี Smart Contract ของ Ethereum ช่วยให้เราสร้างสกุลเงินใหม่ที่แลกเปลี่ยนเป็นสกุลอื่นได้สะดวก ด้วยมาตรฐาน ERC20
มาตรฐานในแง่ของ Smart Contract คือ มี function ที่ให้คนอื่นเรียกใช้งานได้สะดวก มีแบบพื้นฐานอย่าง totalSupply(), balanceOf(), transfer() และแบบซับซ้อนอย่าง approve(), allowance() และ transferFrom() นอกจากนี้ยังบังคับให้มี event เตือนการ Transfer และ Approve