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
파일에서는 해당 패키지에 대한 정보를 확인할 수 있습니다.
- name : 패키지 이름입니다.
- version : 패키지의 버전을 의미합니다.
- addresses : 모듈에서 이용할 주소를 작성합니다.
- 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 네트워크에 배포할 수 있습니다. 배포 방법은 다음과 같습니다.
- 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>"
]
}
- 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은 항상 이를 확인하고 있으나 시점에 따라 코드 변경으로 인한 오류가 발생할 수 있습니다.
Updated 4 months ago