Upgrading the Module

How to upgrade your module?

Aptos์—์„œ๋Š” ์ด๋ฏธ ๋ฐฐํฌ๊ฐ€ ๋˜์–ด์žˆ๋Š” module์ด๋ผ๋„ ์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ Module Upgrade ๋ผ๊ณ  ํ•˜๋ฉฐ ์ด๋ฒˆ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ๊ธฐ์กด์— ์ž‘์„ฑ๋œ Module์„ ์ด์šฉํ•ด ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿšง

๋ณธ ํŠœํ† ๋ฆฌ์–ผ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐฐํฌํ•œ Fungible Asset Module๊ณผ ๋ฐฐํฌ ํ™˜๊ฒฝ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค!

๋ฐฐํฌํ•œ ๋ชจ๋“ˆ์ด ์—†๋Š” ๊ฒฝ์šฐ ์•„๋ž˜ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜์—ฌ Nodit Aptos Tutorial์„ ๋”ฐ๋ผ Message Module์„ ๋ฐฐํฌํ•ด ๋ณด์„ธ์š”!


๐Ÿ“˜

์ด ํŠœํ† ๋ฆฌ์–ผ์„ ํ†ตํ•ด ์•„๋ž˜ ๋‚ด์šฉ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

  • Module์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜์—ฌ Module์—์„œ ์ด์šฉํ•˜๋Š” ๋กœ์ง์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ „์ฒด ํŠœํ† ๋ฆฌ์–ผ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ๋งํฌ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Nodit Aptos Upgrading the Module ํŠœํ† ๋ฆฌ์–ผ ์ฝ”๋“œ ํ™•์ธํ•˜๊ธฐ

Upgrade your Module

Nodit ํŠœํ† ๋ฆฌ์–ผ์„ ํ†ตํ•ด ๋ฐฐํฌํ•œ Message Module์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

module ownerAddress::message {
  use std::signer;
  use std::string::{Self,utf8, String};
  use std::error;

  struct Message has key {
    message_counter : u64,
    message : String,
  }

  const ENO_MESSAGE: u64 = 0;

  public fun get_message(message_owner : address) : string::String acquires Message {
    assert!(exists<Message>(message_owner), error::not_found(ENO_MESSAGE));
    borrow_global<Message>(message_owner).message
  }

  public entry fun set_message(admin: &signer, message : String) acquires Message{
    let message_owner_address = signer::address_of(admin);
    if (exists<Message>(message_owner_address)) {
      let stored_message = borrow_global_mut<Message>(message_owner_address);
      stored_message.message = message;
    } else {
      move_to(admin, Message{
        message_counter : 1,
        message : message
      });
    }
  }

#[test(account = @ownerAddress)]
  public entry fun test_message(account: &signer) acquires Message {
    let message = utf8(b"Hello, World!");
    set_message(account, message);
    let message_owner_address = signer::address_of(account);
    let stored_message = get_message(message_owner_address);
    assert!(message == stored_message, 0);
  }
}

์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด set_message์—์„œ ๋กœ์ง์ด ์ด์ƒํ•œ ๋ถ€๋ถ„์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ ๊ธฐ์กด ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ ์ž…๋ ฅํ•œ ๋ฉ”์‹œ์ง€๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ, ๋ฉ”์‹œ์ง€๋Š” ์ •์ƒ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋‚˜ message_counter๊ฐ€ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Module์„ ์—…๋ฐ์ดํŠธ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


Step 1. Module์˜ ํ•จ์ˆ˜ ๋ณ€๊ฒฝ

๊ธฐ์กด์˜ Module์— ์žˆ๋Š” set_message ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ message๋งŒ ๋ณ€๊ฒฝํ•˜๊ณ  message_counter๋Š” ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ๋กœ์ง์ด์—ˆ์Šต๋‹ˆ๋‹ค.

public entry fun set_message(admin: &signer, message : String) acquires Message{
  let message_owner_address = signer::address_of(admin);
  if (exists<Message>(message_owner_address)) {
    let stored_message = borrow_global_mut<Message>(message_owner_address);
    stored_message.message = message;
  } else {
    move_to(admin, Message{
      message_counter : 1,
      message : message
    });
  }
}

์ด๋Ÿฌํ•œ ๋กœ์ง์„ ์ˆ˜์ •ํ•œ ์ƒˆ๋กœ์šด set_message ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ ๋งˆ๋‹ค message_counter ์—ญ์‹œ 1 ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

  public entry fun set_message_with_message_counter(admin: &signer, message : String) acquires Message{
    let message_owner_address = signer::address_of(admin);
    if (exists<Message>(message_owner_address)) {
      let stored_message = borrow_global_mut<Message>(message_owner_address);
      // ํ‘œ์‹œ
      stored_message.message_counter = stored_message.message_counter+1;
      stored_message.message = message;

    } else {
      move_to(admin, Message{
        message_counter : 1,
        message : message
      });
    }
  }

๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ํ˜ผ์„ ์„ ๊ฒช์ง€ ์•Š๋„๋ก ๊ธฐ์กด์˜ set_message ํ•จ์ˆ˜์— #[deprecated] ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

  #[deprecated]
  public entry fun set_message(admin: &signer, message : String) acquires Message{
    let message_owner_address = signer::address_of(admin);
    if (exists<Message>(message_owner_address)) {
      let stored_message = borrow_global_mut<Message>(message_owner_address);
      stored_message.message = message;
    } else {
      move_to(admin, Message{
        message_counter : 1,
        message : message
      });
    }
  }

์ „์ฒด์ ์ธ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

module ownerAddress::message {
  use std::signer;
  use std::string::{Self,utf8, String};
  use std::error;

  struct Message has key {
    message_counter : u64,
    message : String,
  }

  const ENO_MESSAGE: u64 = 0;

  public fun get_message(message_owner : address) : string::String acquires Message {
    assert!(exists<Message>(message_owner), error::not_found(ENO_MESSAGE));
    borrow_global<Message>(message_owner).message
  }

  #[deprecated]
  public entry fun set_message(admin: &signer, message : String) acquires Message{
    let message_owner_address = signer::address_of(admin);
    if (exists<Message>(message_owner_address)) {
      let stored_message = borrow_global_mut<Message>(message_owner_address);
      stored_message.message = message;
    } else {
      move_to(admin, Message{
        message_counter : 1,
        message : message
      });
    }
  }
  
  public entry fun set_message_with_message_counter(admin: &signer, message : String) acquires Message{
    let message_owner_address = signer::address_of(admin);
    if (exists<Message>(message_owner_address)) {
      let stored_message = borrow_global_mut<Message>(message_owner_address);
      stored_message.message_counter = stored_message.message_counter+1;
      stored_message.message = message;

    } else {
      move_to(admin, Message{
        message_counter : 1,
        message : message
      });
    }
  }

#[test(account = @ownerAddress)]
  public entry fun test_message(account: &signer) acquires Message {
    let message = utf8(b"Hello, World!");
    set_message_with_counter(account, message);
    let message_owner_address = signer::address_of(account);
    let stored_message = get_message(message_owner_address);
    assert!(message == stored_message, 0);
  }
}

Step 2. Compile ๋ฐ ๋ฐฐํฌ

์ฝ”๋“œ ๋ณ€๊ฒฝ์„ ์™„๋ฃŒํ•˜์˜€๋‹ค๋ฉด ํ„ฐ๋ฏธ๋„์— ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ์ด ๋˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

$ aptos move compile

์ •์ƒ์ ์œผ๋กœ ์ปดํŒŒ์ผ์ด ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Compiling, may take a little while to download git dependencies...
UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING myFungibleAsset
{
  "Result": [
    "<your_account_address>::<your_module_name>"
  ]
}

์ปดํŒŒ์ผ ์™„๋ฃŒ ํ›„ ํ„ฐ๋ฏธ๋„์— ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ Aptos ๋„คํŠธ์›Œํฌ์— ๋ณ€๊ฒฝ๋œ Module์„ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฐฐํฌ ์‹œ owner์˜ Account๊ฐ€ ๊ธฐ์กด์˜ owner์™€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์‹ ๊ทœ ๋ชจ๋“ˆ๋กœ ๋ฐฐํฌ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ธฐ์กด์˜ ํ•จ์ˆ˜๊ฐ€ ์ง€์›Œ์ง€๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ ๋ฐฐํฌ์— ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Move.toml, module name ๋“ฑ ๊ธฐ์กด ์„ค์ •์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ๋ฐฐํฌ์— ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
$ aptos move publish

์ •์ƒ์ ์œผ๋กœ ๋ฐฐํฌ๊ฐ€ ๋˜์—ˆ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{
  "Result": {
    "transaction_hash": "<Your_transaction_hash>",
    "gas_used": 165,
    "gas_unit_price": 150,
    "sender": "<Your_Account_Address>",
    "sequence_number": 2,
    "success": true,
    "timestamp_us": 1720774008922260,
    "version": 5066304958,
    "vm_status": "Executed successfully"
  }
}

Step 3. ๋ณ€๊ฒฝ๋œ module ํ™•์ธ

Nodit์—์„œ ์ œ๊ณตํ•˜๋Š” Aptos Node API์˜ Get account module API๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐฐํฌ๋œ Module์˜ ABI๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

curl --request GET \
     --url https://aptos-testnet.nodit.io/v1/accounts/<your_account_address>/module/<your_module_name> \
     --header 'X-API-KEY: <your X-API-KEY>' \
     --header 'accept: application/json'

๋‹ค์Œ๊ณผ ๊ฐ™์ด Module์— ์ˆ˜์ •ํ•˜์—ฌ ๋ฐฐํฌํ•œ set_message_with_message_counter ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‚˜์š”?

...
{
	name:"set_message_with_message_counter"
	visibility:"public"
	is_entry:true
	is_view:false
	generic_type_params:[]
	params:[
		0:"&signer"
		1:"0x1::string::String"
	]
	return:[]
}
...

  • ํ™•์ธ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์œ„์˜ ์ฝ”๋“œ์™€ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์„ธ์š”.
  • ์œ„์˜ ์ฝ”๋“œ์™€ ์ฐจ์ด๊ฐ€ ์—†๋Š”๋ฐ ๋˜์ง€ ์•Š๋‚˜์š”? ์—ฌ๊ธฐ[QnA ๋งํฌ]๋ฅผ ํด๋ฆญํ•˜์—ฌ QnA๋กœ ๋‚จ๊ฒจ์ฃผ์„ธ์š”!

๐Ÿ“˜

Aptos๋Š” ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค!

Aptos ์žฌ๋‹จ์—์„œ ๋ฐฐํฌํ•œ SDK ๋ฒ„์ „์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋˜๋Š” ์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Nodit์€ ํ•ญ์ƒ ์ด๋ฅผ ํ™•์ธํ•˜๊ณ  ์žˆ์œผ๋‚˜ ์‹œ์ ์— ๋”ฐ๋ผ ์ฝ”๋“œ ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.