Query smart contract with Web3j in Scala
สวัสดี!
จากคราวก่อนที่เราเคยเขียน go เพื่อเชื่อมต่อกับ smart contract แล้ว รอบนี้เราจะมาลองใช้ฝั่ง Scala หรือ Java บ้าง ทั้งนี้ผมถนัด Scala มากกว่าเลยจะใช้ Scala
สำหรับตัวอย่าง code ในครั้งนี้ ทุกวันนี้ผมมีโปรแกรมที่คอยแจ้งเตือนจำนวนเงินของ crypto currency ที่มีอยู่ เผื่อใครสนใจอยู่ลองเอาไปใช้ได้นะครับ crypto-notify เมื่อไม่นานมานี้ pancakeswap ได้มีการ migrate smart contract ในการ stake cake นิดหน่อย ทำให้จากเดิมที่จะไป query ที่ bscscan ต้องเปลี่ยนไปอ่าน smart contract ตรง ๆ แทน โดยในตัวอย่างนี้จะใช้ web3j-cli ซึ่งเป็นโปรแกรมในการสร้าง contract wrapper เพื่อให้เราสามารถ interact กับ smart contract ได้ง่าย ๆ
เรามาเริ่มกันเลยดีกว่าครับ
ป.ล. ผมใช้ linux เป็นหลักนะครับ
โปรแกรมที่ใช้
- IntelliJ IDEA Community with Scala plugin
- Scala 2.x.x (ในตัวอย่างจะใช้ 2.13.8)
- Java sdk (ในตัวอย่างจะใช้ openjdk-16)
- sbt (ในตัวอย่างจะใช้ 1.6.2)
- web3j-cli สำหรับสร้าง contract wrapper
สร้าง Project
-
เปิด IntelliJ IDEA ขึ้นมาเเล้วสร้าง project ตามภาพนี้
-
จะได้น่าตาประมาณนี้ รอให้ IntelliJ initialize สักพัก (สังเกตที่มุมขวาล่าง)
-
เพิ่ม dependency web3j ที่ build.sbt
-
refesh sbt เพิ่มที่จะให้มัน download dependency เข้ามา
สร้าง Contract Wrapper
ในตัวอย่างนี้เราจะมาลองต่อ CakePool contract ของ pancakeswap เพื่อที่จะเช็คดูว่าเรา stake cake ไว้เท่าไหร่
-
ให้ copy abi กับ binary ของ CakePool constract จาก bscscan มา save ไว้ที่ root ของ folder ที่สร้าง project IntelliJ เอาไว้ ตั้งชื่อไฟล์ว่า CakePool.json สำหรับ abi กับ CakePool.bin สำหรับ binary
- Download web3j-cli จาก link ด้านบน เอามาไว้ที่ root เช่นเดียวกัน จากนั้นก็ unzip ไฟล์
- รัน command
$ ./web3j-1.4.1/bin/web3j generate solidity -a=./CakePool.json -b=./CakePool.bin -o=./src/main/scala -p=contract.pancake
-
กลับไปที่ IntelliJ IDEA จะเห็นว่ามี CakePool.java อยู่ใน
src/main/scala/contract
เริ่มเขียน code
- สร้าง Object ที่ชื่อว่า Main.scala ไว้ใน
src/main
- เขียน code ตามด้านล่างนี้ (
<your wallet addres>
ให้แทนทีด้วย address ของ wallet ที่ทำการ staking cake อยู่)
import contract.pancake.CakePool
import org.web3j.crypto.Credentials
import org.web3j.protocol.Web3j
import org.web3j.protocol.http.HttpService
import org.web3j.tx.gas.DefaultGasProvider
import scala.math.BigDecimal.RoundingMode
object Main extends App {
val bscRpcNode = "https://bsc-dataseed.binance.org"
val cakePoolContractAddress = "0x45c54210128a065de780C4B0Df3d16664f7f859e"
val web3j: Web3j = Web3j.build(new HttpService(bscRpcNode))
val cakePool: CakePool = CakePool.load(cakePoolContractAddress, web3j, Credentials.create("0") , new DefaultGasProvider())
val userAddress = "<your wallet address>"
val userInfo = cakePool.userInfo(userAddress).send()
val pricePerFullShare = cakePool.getPricePerFullShare.send()
val shares = BigInt(userInfo.component1())
val userBoostedShare = userInfo.component7()
val stakedCakeWei = (BigDecimal(shares * BigInt(pricePerFullShare)) / Math.pow(10, 18)) - BigDecimal(userBoostedShare)
val stakedCake = (stakedCakeWei / Math.pow(10, 18)).setScale(6, RoundingMode.HALF_UP)
println(s"Your cake: $stakedCake")
}
-
ลองรันโปรแกรม (ในรูปเป็นจำนวน cake ที่ผม stake อยู่)
จบเเล้วนะครับสำหรับการใช้ Scala ในการ interact กับ smart contract หวังว่าจะเอาไปใช้ประโยชน์ได้บ้างไม่มากก็น้อยนะครับ :)
ป.ล. link project ตัวอย่าง web3j-example