Deploying a Module

What is Module?

Module이란 다양한 구조체를 정의하고 사용하는 함수로 구성된 라이브러리 입니다. Aptos에서는 네트워크에 Module을 배포하고 이를 이용해 스마트 컨트랙트 로직을 구현할 수 있습니다.


How to make Module?

Module은 Move라는 언어를 이용해 작성할 수 있습니다. Aptos에서는 사용자가 편리하게 Aptos 개발 환경을 구축할 수 있도록 CLI를 지원하고 있습니다. 이번 튜토리얼에서는 Aptos CLI를 이용하여 Module 개발 환경을 구축하고 간단한 Message Module을 작성할 것 입니다.

📘

이 튜토리얼을 통해 아래 내용을 배울 수 있습니다!

  • Module 작성 및 배포를 위한 환경 설정 방법을 알 수 있습니다.
  • Module에 대한 기초적인 내용을 이해할 수 있습니다.
  • Module을 Aptos 네트워크에 배포하는 방법을 알 수 있습니다.
  • 전체 튜토리얼 코드는 아래 링크를 통해 확인할 수 있습니다.

Step 1. Initializing Move environment and Profile

Module을 작성 및 관리하기 위한 새로운 프로젝트 디렉토리를 생성합니다.

$ mkdir Message
$ cd Message

Move를 편리하게 작성할 수 있는 환경을 구성하기 위해 아래 명령어를 입력합니다. (경로가 새로 만든 Message 디렉토리와 일치하는지 확인해 주세요.)

$ aptos move init --name <your_porject_name>

성공적으로 init이 완료되면 현재 디렉토리 내에 scripts, sources, tests 라는 이름의 디렉토리와 Move.toml 파일이 생성됩니다.

.
├── Move.toml
├── scripts
├── sources
└── tests

Move.toml 파일에서는 해당 패키지에 대한 정보를 확인할 수 있습니다.

  1. name : 패키지 이름입니다.
  2. version : 패키지의 버전을 의미합니다.
  3. addresses : 모듈에서 이용할 주소를 작성합니다.
  4. dependenciesAptosFramework : Aptos의 프레임워크나 Third Party Dependency를 명시합니다.
[package]
name = "<your project name>"
version = "1.0.0"

[addresses]

[dependencies.AptosFramework]
git = "https://github.com/aptos-labs/aptos-core.git"
rev = "mainnet"
subdir = "aptos-move/framework/aptos-framework"


아래 명령어를 실행하여 초기 계정 정보를 설정합니다.

$ aptos init --network testnet

—network 명령어를 이용하여 사용하고자 하는 Aptos 네트워크를 설정할 수 있습니다. 또한 이 명령어를 통해 Account를 생성할 수 있습니다. 성공적으로 생성이 되면 config.yaml 파일을 포함하고 있는 .aptos 라는 디렉토리가 자동으로 생성되며 config.yaml 파일에는 사용자가 이용할 Account에 대한 정보가 작성되어 있습니다.

// config.yaml

---
profiles:
  default:
    private_key: "your_private_key"
    public_key: "your_public_key"
    account: "your_account_address"
    rest_url: "Your_Nodit_Aptos_Endpoint"
    faucet_url: "https://faucet.testnet.aptoslabs.com"


config.yaml 파일에서 account 값을 복사한 뒤 Move.toml 파일의 [addresses]에 붙여넣어 Key 값을 이용해 해당 Account를 move 파일에서 이용할 수 있습니다.

[package]
name = "<your project name>"
version = "1.0.0"

[addresses]
myAddress = "and_paste_your_account_address"

[dependencies.AptosFramework]
git = "https://github.com/aptos-labs/aptos-core.git"
rev = "mainnet"
subdir = "aptos-move/framework/aptos-framework"


패키지 초기화 완료 후 sources 디렉토리 내에 move 파일을 생성합니다.

$ cd ../sources
$ touch message.move

Step 2. Writing Message Module

전체적인 Message 코드는 다음과 같습니다. message.move에 아래와 같이 작성합니다. 그리고 Tutorial 3에서 각 코드가 어떤 역할을 하는지 알아보겠습니다.

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;

	#[view]
  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);
  }
}

Step 3. Understanding Module

fungible_asset.move 파일에 작성된 각 코드가 어떤 역할을 하는지 알아보겠습니다.

  • Module 선언
module ownerAddress::message {}

Module을 배포하는 주소와 Module의 이름입니다. {} 안에 코드를 작성합니다.

ownerAddress는 Move.toml에서 설정한 [addresses] 필드의 ownerAddress 값 입니다.


  • 모듈 불러오기
use std::signer;
use std::string::{Self,utf8, String};
use std::error;

다른 모듈을 재사용할 수 있는 use 명령어를 이용해 Aptos에서 지원하는 Standard 모듈의 함수, 구조체 등을 import합니다. use <address>::<Module> 혹은 use <address>::<ModuleName>::<Resource> 형태로 작성합니다. 이 외에도 Aptos는 다양한 기능을 제공합니다. 0x1 주소의 Module을 확인해 보세요!


  • Message 구조체 정의
  struct Message has key {
    message_counter : u64,
    message : String,
  }

사용자가 입력하는 Message 저장하기 위한 구조체 입니다. “has key”라는 구조체의 속성에 의해 해당 구조체를 Account의 Resource로 할당할 수 있습니다.


  • 에러 처리용 상수
const ENO_MESSAGE: u64 = 0;

에러 처리를 위한 상수 입니다. 이를 이용하여 assert 문에서 error::not_found(ENO_MESSAGE) 함수의 인자로 이용해 에러 처리를 할 수 있습니다.


  • get_message 함수 정의
#[view]  
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
}

Message 구조체에 입력되어 있는 message를 확인할 수 있는 get_message 함수를 정의합니다. 인자로 받는 message_owner의 주소에 Message 구조체가 없는 경우 에러를 반환하고 Message 구조체가 있는 경우 Message 구조체의 message를 반환합니다.


  • set_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
    });
  }
}

Message 구조체에 message를 입력할 수 있는 set_message 함수를 정의합니다. 모듈의 Owner가 호출하여 message를 작성할 수 있습니다. 해당 주소에 Message 구조체가 있는지 확인하고 Message 구조체가 있는 경우 기존 message를 사용자가 입력한 message로 변경하고 Message 구조체가 없는 경우 사용자의 주소에 사용자가 입력한 message와 message_counter가 1인 Message 구조체를 할당합니다.

(set_message의 로직 중 이상한 걸 발견하셨나요? 이 부분은 Tutorial 6에서 계속됩니다!)


  • Test 코드 작성 (Optional)
#[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);
  }
}

Module에 작성한 함수를 이용해 Module을 배포하기 전 기능 테스트를 진행할 수 있습니다. 해당 코드의 로직은 “Hello World!”라는 메시지를 set_message를 이용해 ownerAddress에 Resource로 할당한 후 get_message를 이용해 불러온 값과 “Hello World!”라는 값이 동일한지 확인합니다.


터미널에 아래의 명령어를 입력하여 테스트를 진행할 수 있습니다.

$ aptos move test

Step 4. Deploy your Module

최종적으로 완성한 Module은 Aptos CLI를 이용해 Aptos 네트워크에 배포할 수 있습니다. 배포 방법은 다음과 같습니다.

  1. Module Compile

move 파일이 작성되어 있는 경로에서 Aptos CLI를 이용해 Module을 컴파일 합니다.

$ aptos move compile

성공적으로 컴파일이 완료되면 다음과 같은 응답을 받을 수 있습니다.

UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING <your Package Name>
{
  "Result": [
    "<address>::<module_name>"
  ]
}

  1. Module Deploy

Compile이 완료된 move 파일을 Aptos CLI를 이용해 Aptos 네트워크에 배포합니다. move 파일이 작성되어 있는 경로에서 아래 명령어를 실행합니다.

$ aptos move publish

성공적으로 배포가 완료되면 배포 트랜잭션에 대한 트랜잭션 결과를 확인할 수 있습니다.

{
  "Result": {
    "transaction_hash": "0x1234...",
    "gas_used": 3540,
    "gas_unit_price": 100,
    "sender": "abc...90",
    "sequence_number": 0,
    "success": true,
    "timestamp_us": 1720593360929545,
    "version": 26759186,
    "vm_status": "Executed successfully"
  }
}

Nodit에서 제공하는 Aptos Node API 중 Get account module API를 이용하면 특정 Account가 배포한 Module을 확인할 수 있습니다.


📘

Nodit Aptos Node API는 어떻게 사용할 수 있나요?

Nodit은 Aptos Node API 사용 가이드를 제공하고 있습니다! 아래 링크를 클릭하여 Get account module API를 더욱 자세히 알아보세요!


Get account module API는 Query Params로 Account Address와 moduleName을 이용합니다. header로 X-API-KEY를 추가하고 Nodit을 통해 발급받은 X-API-KEY를 입력한 후 API를 호출해 보세요!

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

아래와 같이 배포한 Module을 확인할 수 있습니다.

{
  "bytecode": "0xa11ceb0b060000...",
  "abi": {
    "address": "0xabc...90",
    "name": "<your_module_name>",
		...
  }
}

위의 코드를 실행하여 Module을 확인할 수 있나요?


  • 확인이 되지 않는다면 위의 코드와 다른 부분이 있는지 확인해 보세요.
  • 위의 코드와 차이가 없는데 되지 않나요? 여기[QnA 링크]를 클릭하여 QnA로 남겨주세요!

📘

Aptos는 매우 빠르게 업데이트 되고 있습니다!

Aptos 재단에서 배포한 SDK 버전에 따라 변경되는 점이 있을 수 있습니다. Nodit은 항상 이를 확인하고 있으나 시점에 따라 코드 변경으로 인한 오류가 발생할 수 있습니다.