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 12 days ago