Terra Network SmartContract Migration

zapkub

Rungsikorn Rungsikavanich

Posted on October 31, 2021

Terra Network SmartContract Migration

Terra network มีอัพเดทครั้งใหญ่ เพื่อเพิ่มประสิทธิภาพของ Network แต่ในบทความนี้ ผมจะไม่พูดเรื่อง Network แต่จะไป focus เรื่อง Smart Contract แทน โดยถ้าอยากรู้ว่ามีอะไรเปลี่ยนไปบ้าง ลองดูได้ลิ้งนี้แทน

https://medium.com/terra-money/columbus-5-launches-welcome-to-the-future-of-terra-8a9ebfa570c5

หนึ่งในการอัพเดทคือการ Bump cosmwasm ไปเป็น version 0.16 ( ซึ่ง breaking change กระจาย ) เรามาดูกันว่า เราต้องเปลี่ยนอะไรบ้างจาก contract version เดิม ( 0.10 )

นอกจากนี้ feature ที่เพิ่มมาก็เยอะมาก เพราะมัน upgrade กันข้ามมา 6 version ถ้าต้องการไล่อ่าน ตามไปที่ https://github.com/CosmWasm/cosmwasm/blob/main/CHANGELOG.md ได้เลย

image

ของ Avareum protocol พังไป 240 errors 😱

มีอะไรเปลี่ยนไปบ้าง?

  • API มีความกระชับขึ้น Type ต่างๆ Generic ต่างๆใช้ง่ายขึ้น
  • Support การทำ Migration ผ่าน Contract ได้แล้ว

โดยบทความนี้จะยกเอาแค่ Major change หลักๆ ที่ทีม Avareum ต้อง Migrate ซึ่งทางทีมก็ยังใช้ Feature ของมันไม่หมด (เยอะเกิน)


Support On-chain Contract Migration

อันนี้คือที่รอคอยมานาน ซึ่งพึ่งมาเพิ่มใน coswasm 0.14 ทำให้ Contract สามารถ Migrate กันเองได้แบบ On-chain
Image description

โดยที่ก่อนหน้านี้ จะจำกัดเรื่องการ migrate contract สามารถทำได้โดยผ่าน Off Chain API อย่างเดียว ทำให้ต้องเป็นหน้าที่ของ Owner ของ Contract เท่านั้นที่สามารถ Migrate ได้และหากมีหลาย Contract ก็ต้องทำทีละอันจาก Off chain

จาก Feature นี้ทำให้เราสามารถ Deploy contract set ที่มี Logic ในการ ทำ Migration ออกมาและสั่ง Migrate ที่เดียวจาก Off chain จาก Entrypoint ที่เดียว

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
    let cfg = query_config(&deps.as_ref())?;
    Ok(Response::new().add_messages(vec![
        CosmosMsg::Wasm(WasmMsg::Migrate {
            contract_addr: cfg.executor_mirror_address.into(),
            new_code_id: msg.sub_contract.executor_mirror_code_id,
            msg: to_binary(&msg.sub_contract.executor_mirror_migrate_msg)?,
        }),
        CosmosMsg::Wasm(WasmMsg::Migrate {
            contract_addr: cfg.executor_anchor_address.into(),
            new_code_id: msg.sub_contract.executor_anchor_code_id,
            msg: to_binary(&msg.sub_contract.executor_anchor_migrate_msg)?,
        }),
        CosmosMsg::Wasm(WasmMsg::Migrate {
            contract_addr: cfg.executor_terraswap_address.into(),
            new_code_id: msg.sub_contract.executor_terraswap_code_id,
            msg: to_binary(&msg.sub_contract.executor_terraswap_migrate_msg)?,
        }),
    ]))
}
Enter fullscreen mode Exit fullscreen mode

วิธี binding Entrypoint เปลี่ยนใหม่

จากปกติก่อนหน้านี้ การกำหนด entrypoint ทั้งหมดจะอยู่ที่ lib.rs ให้ลบตรงนั้นทิ้งออกให้หมดแล้วไปใช้ macro กับ function ชื่อ entry_point แทน
พร้อมกับ เปลี่ยนชื่อ init เป็น instantiate และ handle เป็น execute

https://github.com/CosmWasm/cosmwasm/blob/main/CHANGELOG.md#changed-6


#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: InitMsg,
) -> Result<Response, ContractError> 
....


#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {

...


Enter fullscreen mode Exit fullscreen mode

Extern API เปลี่ยนเป็น Deps และ DepsMut

จากการใช้งาน Extern กับ Generic type ทาง cosmwasm ได้เปลี่ยนมาเป็น type alias ทำให้ ปกติที่ใช้ Extern ให้เปลี่ยนเป็น Deps และ mut Extern เปลี่ยนเป็น DepsMut
Reference

ตัวอย่าง

จาก

pub fn init<S: Storage, A: Api, Q: Querier>(
    deps: &mut Extern<S, A, Q>,
    _env: Env,
    msg: InitMsg,
) -> StdResult<InitResponse> {
Enter fullscreen mode Exit fullscreen mode

เปลี่ยนเป็น

pub fn init(
    deps: DepsMut,
    _env: Env,
    msg: InitMsg,
) -> StdResult<InitResponse> {
Enter fullscreen mode Exit fullscreen mode

จากอันนี้ การ access funds ที่ส่งมาจะเปลี่ยนจาก access ที่ env ไปผ่านตัว info แทน


เพิ่ม Arguments ให้กับ Contract entry point ( init, handle, migrate )

Type Env ถูกนำเอา sender ออกและย้ายไปไว้ใน Type ชื่อ MessageInfo เข้าใจว่าเพื่อให้เป็นระเบียบมากขึ้นเฉยๆ

ตัวอย่าง

จาก

pub fn handle(
    deps: DepsMut,
    env: Env,
    msg: HandleMsg,
) -> StdResult<HandleResponse> {
.....
    let senderAddr = env.message.sender;
Enter fullscreen mode Exit fullscreen mode

เปลี่ยนเป็น

pub fn handle(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: HandleMsg,
) -> StdResult<HandleResponse> {
.....
    let senderAddr = info.sender;
Enter fullscreen mode Exit fullscreen mode

Migrate Response, HandleResponse, InitResponse กลายเป็น Response เฉยๆ และเป็น non_exhaustive

มีการรวม Response ต่างๆเป็นอันเดียว และใช้ Higher order function ในการ assign parameter ต่างๆให้กับ Response ( ไม่อนุญาตให้สร้าง Response แบบ struct expression แล้ว

ซึ่งผมชอบนะอันนี้ ดูกระชับขึ้นเยอะเลย ( ถึงจะต้องแก้ Contract เก่าเยอะหน่อย )

จาก

use cosmwasm_std::{ HandleResponse };

.....

 Ok(HandleResponse {
        messages: msgs,
        data: Option::None,
        attributes: logs,
    });
Enter fullscreen mode Exit fullscreen mode

เปลี่ยนเป็น

use cosmwasm_std::{ Response };

.....

    Ok(Response::new()
        .add_attributes(logs)
        .add_messages(msgs))

Enter fullscreen mode Exit fullscreen mode

Log API เปลี่ยนชื่อเป็น Attribute

version 0.16 เอา log ออกหมดเลย เปลี่ยนไปเรียกว่า Attribute แทน รวมถึงการ return log จาก response ก็จะเปลี่ยนไปใช้ add_attributes หรือ add_attribute จาก Response แทน ( เพราะว่า HandleResponse ถูก Deprecated ไปแล้วจากด้านบน

-- let logs: Vec<LogAttribute> = vec![log("label","value")];
++ let attrs: Vec<Attribute> = vec![attr("label", "value")];

-- HandleResponse { log: logs }
++ Response::new().add_attributes(attrs);

Enter fullscreen mode Exit fullscreen mode

HumanAddr ถูก Deprecated

ใน API version ใหม่จะมี Addr มาแทน HumanAddr โดยที่ API ส่วนใหญ่ ที่ใช้ HumanAddr จะเปลี่ยนไปใช้ String แทนแล้ว

เช่น WasmMsg:Execute จากปรกติ รับ contarct_addr เป็น HumanAddr ตอนนี้จะรับเป็น String แทน ซึ่งหากเราตัดสินใจใช้ Addr ก็จะมี to_string ให้ใช้เปลี่ยนจาก Addr เป็น String

-- let contract_addr: HumanAddr;
++ let contract_addr: Addr;
WasmMsg::Execute {
   -- contract_addr: contract_addr,
   ++ contract_addr: contract_addr.to_string(),
}
Enter fullscreen mode Exit fullscreen mode

หลักๆเราต้อง Migrate ตัว contract ประมานนี้ ส่วนใหญ่ยังไม่มีอะไรที่ Breaking Change ถึงกับขนาดต้องออกแบบ Contract ใหม่

ส่วนอื่นๆ นอกจากนี้ลึกๆ ตามไปไล่อ่านที่นี่ได้เลยจ้า
https://github.com/CosmWasm/cosmwasm/blob/main/MIGRATING.md

💖 💪 🙅 🚩
zapkub
Rungsikorn Rungsikavanich

Posted on October 31, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Terra Network SmartContract Migration
terremoney Terra Network SmartContract Migration

October 31, 2021