Devahoy Logo
PublishedAt

Ethers

Interact Smart Contract ด้วย Ethers.js

Interact Smart Contract ด้วย Ethers.js

วิธีการ Interact กับ Smart Contract ด้วยการใช้ Ethers.js ไม่ว่าจะเป็นการ call function ธรรมดา ที่ไม่ได้ไปยุ่งเกี่ยวกับ state ไม่ต้องเสียค่า gas หรือการ send transaction ที่ต้องมี signer (ทั้งจาก Private Key หรือจากการ sign, การ confirm ผ่าน Client) ทั้งหมด สามารถทำผ่าน Ethers.js ได้ทั้งหมด

แต่ในตัวอย่างนี้ จะเป็นตัวอย่างง่ายๆ ในการ call function เท่านั้นนะครับ โดยตัวอย่าง ผมยกตัวอย่าง การ call function ของเหรียญ Token USDC ซึ่งเป็น ERC-20 ครับ

  • เหรียญ USDC บน Ethereum mainnet - USDC บน Ethereum Mainnet

รายละเอียด ERC-20 - https://ethereum.org/en/developers/docs/standards/tokens/erc-20/

Setup Project

เราใช้ JavaScript ธรรมดา (Node.js) เริ่มต้น init project แล้วก็ติดตั้ง ethers

Terminal window
npm init -y
npm install ethers

ตัวอย่างผมใช้ Ethers.js version 6 นะครับ ถ้าใช้ v5 สามารถดู migrating guide ได้ที่นี่ https://docs.ethers.org/v6/migrating/

วิธีการต่อ Blockchain จาก JS Client

ตัวอย่างนี้ จะใช้การต่อผ่าน RPC (ต่อได้หลายรูปแบบ)

โค๊ดในการ connect RPC จะเป็นแบบนี้ (ลองสร้างไฟล์ app.js ขึ้นมา)

1
const { ethers } = require('ethers')
2
3
const RPC_URL = 'https://rpc.ankr.com/eth'
4
5
const provider = new ethers.JsonRpcProvider(RPC_URL)

ส่วน RPC URL เราสามารถหาได้จาก Infura, Alchemy หรือในตัวอย่างผมใช้ Public RPC ของ Ankr คือ https://rpc.ankr.com/eth

เมื่อเราต่อ Blockchain ผ่าน RPC ได้แล้ว เราสามารถดึงข้อมูลต่างๆ ของ blockchain ได้ เช่น blocknumber, balance, transaction เช่น

ตัวอย่าง การดู block number ของ ethereum

1
const { ethers } = require('ethers')
2
3
const RPC_URL = 'https://rpc.ankr.com/eth'
4
5
const run = async () => {
6
const provider = new ethers.JsonRpcProvider(RPC_URL)
7
8
const block = await provider.getBlockNumber()
9
console.log('block', block)
10
}
11
12
run()
13
.then()
14
.catch((error) => console.log(error))

ตัวอย่างการดู balance

ตัวอย่าง การดู balance ของ wallet address ที่เราต้องการ (ผมดูของ vitalik.eth)

1
const { ethers } = require('ethers')
2
3
const RPC_URL = 'https://rpc.ankr.com/eth'
4
5
const run = async () => {
6
const provider = new ethers.JsonRpcProvider(RPC_URL)
7
8
const balance = await provider.getBalance('vitalik.eth')
9
console.log('balance', balance)
10
}
11
12
run()
13
.then()
14
.catch((error) => console.log(error))

แต่ผลลัพธ์ที่ได้จะเป็นตัวเลข ที่เป็นหน่วน wei เราต้องแปลงเป็น ethers ใช้ formatEthers ของ ethers.js ได้เลย

1
const { formatEther } = require('ethers')
2
console.log('balance', formatEther(balance))

ทดสอบรันดู

Terminal window
node app.js
balance 5149.639854481921682572

ค่าที่ได้จะเท่ากับที่ etherscan

ต่อ Contract

เราสามารถ connect Contract เพื่อ call function ของ Contract ได้ เช่น ผมจะ connect USDC เพื่อเรียก function ของ USDC เช่น totalSupply() balanceOf

สิ่งที่ต้องมีคือ

  • contractAddress - Contract Address ที่เราจะ connect
  • ABI - ABI ของ Contract ถ้าเป็น ERC20 ส่วนใหญ่ ใช้ร่วมกันได้

หรือ Copy Contract ABI จาก หน้า etherscan แต่อีกวิธีที่ง่าย คือ ethers.js รองรับ ABI แบบ Human Readable เราไม่ต้องใช้ JSON ก็ได้ ตัว method ERC20 มีแบบนี้ใช่มั้ย

1
function name() public view returns (string)
2
function symbol() public view returns (string)
3
function decimals() public view returns (uint8)
4
function totalSupply() public view returns (uint256)
5
function balanceOf(address _owner) public view returns (uint256 balance)
6
function transfer(address _to, uint256 _value) public returns (bool success)
7
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
8
function approve(address _spender, uint256 _value) public returns (bool success)
9
function allowance(address _owner, address _spender) public view returns (uint256 remaining)

ทีนี้ ผมจะเอาแค่ decimals, balanceOf และ totalSupply ผมก็ทำแบบนี้แทน

1
const ERC20ABI = [
2
'function symbol() public view returns (string)',
3
'function decimals() public view returns (uint8)',
4
'function totalSupply() public view returns (uint256)',
5
'function balanceOf(address _owner) public view returns (uint256 balance)'
6
]

ทีนี้ เราก็สามารถ connect USDT ได้แบบนี้

1
const provider = new ethers.JsonRpcProvider(RPC_URL)
2
const usdcContract = new ethers.Contract(USDC, ERC20ABI, provider)

โค๊ดเต็มๆ คือ

1
const { ethers, formatUnits } = require('ethers')
2
3
const USDC = '0xdac17f958d2ee523a2206206994597c13d831ec7'
4
const RPC_URL = 'https://rpc.ankr.com/eth'
5
6
const ERC20ABI = [
7
'function symbol() public view returns (string)',
8
'function decimals() public view returns (uint8)',
9
'function totalSupply() public view returns (uint256)',
10
'function balanceOf(address _owner) public view returns (uint256 balance)'
11
]
12
13
const run = async () => {
14
const provider = new ethers.JsonRpcProvider(RPC_URL)
15
const usdcContract = new ethers.Contract(USDC, ERC20ABI, provider)
16
17
const decimals = await usdcContract.decimals()
18
19
const symbol = await usdcContract.symbol()
20
const totalSupply = await usdcContract.totalSupply()
21
console.log(`${symbol} totalSupply : `, formatUnits(totalSupply, decimals))
22
23
const balance = await usdcContract.balanceOf('vitalik.eth')
24
console.log('balance', formatUnits(balance, decimals))
25
}
26
27
run()
28
.then()
29
.catch((error) => console.log(error))

ลองรันดูว่าได้ผลลัพธ์เป็นยังไง

Terminal window
node app.js

ผลลัพธ์

Terminal window
USDT totalSupply : 35283904986.788565
balance 38.13

ทำไมใช้ formatUnits ? เพราะว่า formatEthers จะแปลงเลขด้วยการใช้ 18 decimals แต่ว่า USDT decimals ไม่ใช่ 18 เลยต้องเรียก function decimals เพื่อให้ได้ decimals จริงๆ และแปลงด้วย formatUnits นั่นเอง

🎉 จบแล้ว ตัวอย่างง่ายๆ ในการ interact Smart Contract ด้วย Ethers.js

Authors
avatar

Chai Phonbopit

เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust

Related Posts