สวัสดี!

จากคราวก่อนที่เราเคยเขียน 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 ตามภาพนี้

    create project

  • จะได้น่าตาประมาณนี้ รอให้ IntelliJ initialize สักพัก (สังเกตที่มุมขวาล่าง)

    home

  • เพิ่ม dependency web3j ที่ build.sbt

    add dependency

  • refesh sbt เพิ่มที่จะให้มัน download dependency เข้ามา

    sbt refresh

สร้าง Contract Wrapper

ในตัวอย่างนี้เราจะมาลองต่อ CakePool contract ของ pancakeswap เพื่อที่จะเช็คดูว่าเรา stake cake ไว้เท่าไหร่

  • ให้ copy abi กับ binary ของ CakePool constract จาก bscscan มา save ไว้ที่ root ของ folder ที่สร้าง project IntelliJ เอาไว้ ตั้งชื่อไฟล์ว่า CakePool.json สำหรับ abi กับ CakePool.bin สำหรับ binary

    abi bin

  • 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

    CakePool

เริ่มเขียน 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 อยู่)

    result

จบเเล้วนะครับสำหรับการใช้ Scala ในการ interact กับ smart contract หวังว่าจะเอาไปใช้ประโยชน์ได้บ้างไม่มากก็น้อยนะครับ :)

ป.ล. link project ตัวอย่าง web3j-example

References

See ya!