วิธีการ Create/Build/Deploy Smart Contract บน Localterra

เริ่มต้นด้วยการรัน LocalTerra ก่อนเลย

Clone Localterra มาเพื่อรัน Terra Node บนเครื่องก่อน

$ git clone --depth 1 https://www.github.com/terra-money/LocalTerra
$ cd localterra && docker-compose up

รอสักพักจนกว่า Node จะเริ่มเขียน Block ตามปกติ

lcd_1            | I[2021-08-15|06:29:53.480] Served RPC HTTP response                     module=rest-server method=GET url=/validatorsets/latest status=200 duration=23 remoteAddr=172.19.0.5:36956
lcd_1            | I[2021-08-15|06:29:53.481] Served RPC HTTP response                     module=rest-server method=GET url="/validatorsets/latest?page=2" status=500 duration=23 remoteAddr=172.19.0.5:36954
lcd_1            | I[2021-08-15|06:29:53.482] Served RPC HTTP response                     module=rest-server method=GET url=/oracle/parameters status=200 duration=26 remoteAddr=172.19.0.6:4768
lcd_1            | I[2021-08-15|06:29:53.519] Served RPC HTTP response                     module=rest-server method=GET url=/oracle/denoms/exchange_rates status=200 duration=10 remoteAddr=172.19.0.5:36954
lcd_1            | I[2021-08-15|06:29:54.707] Served RPC HTTP response                     module=rest-server method=GET url=/blocks/latest status=200 duration=17 remoteAddr=172.19.0.6:47696
lcd_1            | I[2021-08-15|06:29:54.708] Served RPC HTTP response                     module=rest-server method=GET url=/oracle/parameters status=200 duration=19 remoteAddr=172.19.0.6:47692
terrad_1         | I[2021-08-15|06:29:54.772] Executed block                               module=state height=15683 validTxs=0 invalidTxs=0
terrad_1         | I[2021-08-15|06:29:54.779] Committed state                              module=state height=15683 txs=0 appHash=E28FEAB65E5F034A1B83BF250757F0263913587D6D8A91A6D8E14D3EFFA4983C
mantle_1         | 2021/08/15 06:29:54 [mantle] Indexing finished for block(15683), processed in 32ms

Compile Smart Contract (Rust)

สมมุติว่าเรามี smart contract ที่เขียนด้วย Cosmos SDK แล้ว หรือถ้าใครที่ยังไม่มี ก็สามารถสร้างโปรเจ็คจาก template คำสั่งนี้ได้เลย

$ cargo generate --git https://github.com/CosmWasm/cosmwasm-template.git --branch 0.10 --name smart_contract
$ cd smart_contract

โดยใน tempate นี้จะเป็น smart contract แบบง่าย คือ ที่สามารถเขียนค่า count และอ่านค่า count ออกมาได้ … เมื่อได้ smart contract สำหรับทดสอบแล้ว ต่อไปก็เพิ่ม rust target ที่จำเป็นสำหรับ compile smart contract บน Terra ด้านล่าง

$ rustup default stable
$ rustup target add wasm32-unknown-unknown

การ compile smart contract ของ Rust จะสามารถทำได้ 2 วิธี คือ

a. Compile ท่าปกติ (แต่จะได้ wasm ที่ใหญ่มาก อาจจะมีปัญหาตอน deploy ไม่ค่อยแนะนำ)

$ cargo wasm

ถ้าใช้วิธีนี้ wasm ที่ได้จะอยู่ในพาร์ท ./target/wasm32-unknown-unknown/release/smart_contract.wasm

b. Compile โดยใช้ rust-optimizer (แนะนำวิธีการการนี้มากกว่า) วิธีนี้ ตัว compiler จะพยายาม optimize ขนาดของ smart contract ให้เล็กที่สุด เพื่อให้สามารถ deploy ขึ้นไปบน network ได้ง่ายกว่า ซึ่งขั้นตอนในการ compile แบบ optimization สามารถทำได้ตามนี้

ติดตั้ง plugin ก่อน

$ cargo install cargo-run-script

ในไฟล์ Cargo.toml ให้เพิ่ม configuration ด้านล่างนี้ เพื่อเรียก script ของ rust-optimizer (ผมใช้เครื่อง Apple Silicon จะเติม --platform linux/amd64/v8 ไปด้วย

[package.metadata.scripts]
optimize = """docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  --platform linux/amd64/v8 \
  cosmwasm/rust-optimizer:0.11.5
"""

ตอน compile ก็เรียก script ที่ใส่ไปเมื่อกี้เลย

cargo run-script optimize

ผลลัพธ์ที่ได้จะอยู่ที่พาร์ท ./artifacts/smart_contract.wasm ซึ่งจะต่างจากวิธี a. อย่าเลือกเลิกใช้ให้ถูกที่นะ…!

วิธีการ Deploy WASM บน Localterra

ในการ deploy smart contract บน Terra สิ่งที่เราต้องเตรียมมีดังต่อไปนี้

  1. wasm ที่ได้จากการ compile ในหัวข้อข้างบน
  2. อย่าลืมรัน localterra ทิ้งไว้ก่อนด้วยนะ

ถ้าเตรียมครบเรียบร้อยแล้วก็มาเริ่มกันเลย ก่อนอื่นเริ่มติดตั้ง terracli ก่อน

$ git clone https://github.com/terra-money/core
$ cd core
$ git checkout master
$ make install

พอติดตั้ง terracli ได้แล้ว ก็ทำการ deploy wasm ด้วย terracli เลย โดยพิมพ์คำสั่งด้านล่างนี้ (อย่าลืมเลือกที่อยู่ของ wasm ที่จะใช้ให้ถูกที่ด้วยนะ)

$ terracli tx wasm store ./artifacts/smart_contract.wasm --from test1 --chain-id=localterra --gas=auto --fees=100000uluna --broadcast-mode=block

และเมื่อส่งคำสั่ง deploy จะมี dialog ขึ้นให้ comfirm ก็พิมพ์ “y” ไปเพื่อยืนยัน

confirm transaction before signing and broadcasting [y/N]: y
height: 113
txhash: 37CB8316AC35F70FB92D0CFC6D859860A7F5E6E405264BABD9DA5660BE286998
codespace: ""
code: 0
data: ""
rawlog: '[{"msg_index":0,"log":"","events":[{"type":"message","attributes":[{"key":"action","value":"store_code"},{"key":"module","value":"wasm"}]},{"type":"store_code","attributes":[{"key":"sender","value":"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8"},{"key":"code_id","value":"3"}]}]}]'
logs:
- msgindex: 0
  log: ""
  events:
  - type: message
    attributes:
    - key: action
      value: store_code
    - key: module
      value: wasm
  - type: store_code
    attributes:
    - key: sender
      value: terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8
    - key: code_id
      value: "3"
info: ""
gaswanted: 696179
gasused: 694534
tx: null
timestamp: ""

ด้านบนเป็นตัวอย่างผลลัพธ์ที่ได้จากการ deploy สำเร็จ ในผลลัพธ์เราจะได้ code_id มา (ในตัวอย่างคือ 3) ให้จำเลขนี้เอาไว้ จากนั้นให้เราสั่ง instantiate smart contract โดยระบุ code_id ที่ได้จากการ deploy ไปเมื่อกี้โดยใช้คำสั่งนี้

$ terracli tx wasm instantiate 3 '{"count":0}' --from test1 --chain-id=localterra --fees=10000uluna --gas=auto --broadcast-mode=block

การยิงคำสั่งนี้มันเป็นการสร้าง initial state ของ smart contract ครั้งแรกบน terra อย่างเช่นในตัวอย่าง จะมีการส่งค่า '{"count":0}' ไปด้วย หมายความว่าให้ intitial ค่า count เท่ากับ 0 ในตอนเริ่ม state ถ้า smart contract ของใครมี initial พารามิเตอร์อื่นๆ ก็ต้องใส่ไปด้วยตาม init ฟังก์ชัน

confirm transaction before signing and broadcasting [y/N]: y
height: 122
txhash: 7626CA46B4F45A403300561E40E119A9009183BFE7948C9D02E32086601AABD2
codespace: ""
code: 0
data: ""
rawlog: '[{"msg_index":0,"log":"","events":[{"type":"instantiate_contract","attributes":[{"key":"owner","value":"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8"},{"key":"code_id","value":"3"},{"key":"contract_address","value":"terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62"}]},{"type":"message","attributes":[{"key":"action","value":"instantiate_contract"},{"key":"module","value":"wasm"},{"key":"sender","value":"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8"}]}]}]'
logs:
- msgindex: 0
  log: ""
  events:
  - type: instantiate_contract
    attributes:
    - key: owner
      value: terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8
    - key: code_id
      value: "3"
    - key: contract_address
      value: terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62
  - type: message
    attributes:
    - key: action
      value: instantiate_contract
    - key: module
      value: wasm
    - key: sender
      value: terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8
info: ""
gaswanted: 120675
gasused: 119959
tx: null
timestamp: ""

ในขั้นตอนนี้ จะทำให้ได้ address ของ smart contract มาเรียบร้อย (ในตัวอย่างคือ terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62) ทีนี้เราจะใช้ address ที่ deploy มาลอง execute transaction กัน..!!!

ลอง Execute Smart Contract

ใน smart contract ที่อยู่บน EVM (บน Ethereum, Binance Smart Chain, Polygon และอื่นๆ) เวลาเรารับส่งข้อมูลไป execute หรือ query กับ smart contract ข้อมูลต่างๆ จะถูก encode ให้อยู่ในรูปแบบ binary ที่เข้ากันได้กับฟังก์ชันของ smart contract ที่กำลังเรียกอยู่เท่านั้น หรือเราเรียกมันอีกอย่างว่า Application Binary Interface (ABI) แต่ในเคสของ Terra (หรืออาจจะทั้ง CosmosSDK ที่ Terra ใช้) ข้อมูลต่างๆ ที่ถูกส่งไปยัง smart contract จะอยู่ในรูปแบบ JSON Serialize แทน ซึ่งส่วนตัวคิดว่ามันง่ายต่อการใช้งานมากกว่า EVM เยอะมากเลยนะ

$ terracli tx wasm execute terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62 '{"increment":{}}' --from test1 --chain-id=localterra --fees=100000uluna

ในตัวอย่างด้านบน จะเป็นการส่งคำสั่ง execute ผมสามารถเรียกฟังก์ชัน Increment ที่อยู่บน smart contract ได้ง่ายๆ ก็แค่ระบุ key และ object value ในรูปแบบ JSON ไปตรงๆ เลย ไม่เหมือน EVM ที่ต้องใช้ ABI มา encode (เดี่ยวตรงนี้มันค่อนข้างลึก อาจจะหาเวลามาเขียนเป็นบทความใหม่แทน)

ลอง Query Smart Contract

เวลาที่จะ query ก็ทำแบบเดียวกันกับการ execute เพียงแค่ใส่ ชื่อฟังก์ชั่น query บน smart contract ให้ถูกต้อง ผลลัพธ์ที่ได้ก็จะออกมาในรูปแบบ JSON เช่นกัน

$ terracli query wasm contract-store terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62 '{"get_count":{}}'
{"count":1}

หมดละครับ Create/Build และ Deploy Smart Contract บน Localterra หวังว่าจะเป็นประโยชน์กับผู้อ่านไม่มากก็น้อยนะ ส่วนตัวผู้เขียนเองก็ใหม่กับเรื่องนี้เหมือนกัน ถ้าผิดหรือตกหล่นตรงไหนก็แนะนำกันได้เลยคร้าบ…. 🌕

Leave a Reply