Aptos 네트워크가 10월 18일 메인넷을 출시함에 따라, Move 프로그래밍 언어와 그 생태계는 지속적으로 영향력을 확대하고 있습니다. 커뮤니티 참여를 위해, 저희는 Move에서의 안전한 개발 방법론을 제공하는 일련의 글을 발표할 예정입니다. 예제, 설명, 그리고 무엇보다도 보안 방법론을 통해 여러분을 Move의 세계로 안내하겠습니다.
TL;DR
이 글에서는 다음 내용을 다룹니다:
- Aptos 애플리케이션을 생성하고 개발하는 방법;
- 모듈(즉, Move의 스마트 컨트랙트)이 어떻게 생겼는지;
- 로컬 네트워크에서 모듈을 컴파일하고 배포하는 방법;
- 모듈과 상호작용하고 브라우저에서 발생한 이벤트를 확인하는 방법.
0x1. Move와 그 생태계에 대하여
Move는 스마트 컨트랙트 개발을 위해 설계된 Diem(2020년 12월 이전의 이름은 Libra)의 유산입니다. 안전하고, 빠르며, 유연하다고 알려져 있으며, 차세대 언어를 목표로 하고 있습니다. 그러나 Aptos와 Sui와 같이 새롭게 등장한 프로젝트들은 원래의 Move를 그대로 채택하지 않고, 자신들의 필요에 맞게 일부 수정을 가했습니다.
별도로 명시되지 않는 한, 저희는 주로 Aptos 컨텍스트에서의 개발 방법론에 집중할 것입니다. 이 아이디어들은 다른 Move 기반 프로젝트에도 일반적으로 적용됩니다. 또한 Move 프로그래밍 언어에 대한 기본적인 이해를 위해 이미 MoveBook을 읽었다고 가정합니다.
0x2. 환경 준비
0x2.1 Aptos 툴체인
Aptos는 이미 CLI에 Move를 통합했습니다. 따라서 해당 툴체인을 설치하려면 CLI 설치 가이드를 따르는 것을 권장합니다. 설치가 완료되면 터미널에 aptos를 입력하면 다음과 같은 출력을 볼 수 있습니다:
$ aptos
aptos 1.0.1
Aptos Labs <[email protected]>
Command Line Interface (CLI) for developing and interacting with the Aptos blockchain
USAGE:
aptos <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
account Tool for interacting with accounts
config Tool for interacting with configuration of the Aptos CLI tool
genesis Tool for setting up an Aptos chain Genesis transaction
governance Tool for on-chain governance
help Print this message or the help of the given subcommand(s)
info Show build information about the CLI
init Tool to initialize current directory for the aptos tool
key Tool for generating, inspecting, and interacting with keys
move Tool for Move related operations
node Tool for operations related to nodes
stake Tool for manipulating stake and stake pools
0x2.2 로컬 테스트넷 및 계정
Aptos는 개발 및 배포를 위해 여러 네트워크(메인넷, 테스트넷, 데브넷, 로컬 테스트넷)를 제공합니다. 이 글에서는 로컬 테스트넷을 사용할 것입니다.
로컬 테스트넷을 실행하려면 다음 명령어를 입력하세요:
$ aptos node run-local-testnet --with-faucet --force-restart
다음과 같은 출력이 표시될 것입니다:
......
Aptos is running, press ctrl-c to exit
Faucet is running. Faucet endpoint: 0.0.0.0:8081
이제 다음 명령어를 입력하여 계정을 생성할 수 있습니다(이전 터미널을 포그라운드로 유지하려면 다른 터미널 창에서 입력하세요):
$ aptos init
이 명령어는 몇 가지 속성 지정이 필요한 대화형 셸을 실행합니다. 여기서는 local 네트워크를 선택합니다. 그 후, 현재 디렉토리에 기본 계정 구성이 담긴 .aptos 폴더가 생성됩니다. 파일을 확인하고 account 주소(예: c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd)를 복사하세요.
팁#1: 계정 구성 파일을 안전하게 보관하세요! 개인 키가 파일 안에 저장되어 있습니다!
0x3. 첫 번째 Hello World 프로그램
Hello World 프로그램은 코드 작성 학습의 첫 번째 단계로 항상 사용됩니다. 저희는 이 관례를 따라 Move 애플리케이션 개발 방법을 시연하고자 합니다.
0x3.1 패키지 준비
원하는 디렉토리를 선택하고 다음 명령어를 입력하세요:
$ aptos move init --framework-local-dir "../../aptos-core/aptos-move/framework/aptos-framework" --name hello
이 명령어는 지정된 위치(즉, 개발 워크스페이스)에 새로운 Move 패키지를 생성합니다. Aptos 프레임워크의 일부 라이브러리 함수가 필요하므로 Aptos 프레임워크의 로컬 디렉토리를 지정합니다(다른 위치의 경우 상대 경로를 변경해야 할 수 있습니다). 또는 --framework-git-rev를 사용하여 Aptos 프레임워크의 git 리비전이나 브랜치를 지정할 수도 있습니다.
이제 디렉토리에서 Move.toml 파일을 확인할 수 있습니다. 이 파일은 일부 의존성 구성을 나열할 뿐만 아니라 패키지 이름과 버전도 설명합니다. 또한 Move 소스 코드를 저장하는 데 사용되는 sources라는 폴더도 있습니다. sources 디렉토리에 .move 파일을 생성하면 워크스페이스를 사용할 준비가 됩니다.
[package]
name = 'hello'
version = '1.0.0'
[dependencies.AptosFramework]
local = '../../aptos-core/aptos-move/framework/aptos-framework'
[addresses]
BlockSec="c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd"
Move.toml의 마지막 줄에서 (앞서 생성한) 계정 주소를 BlockSec과 연결합니다. 이는 이 패키지의 모듈을 배포(즉, 스마트 컨트랙트 배포)하는 데 사용됩니다(나중에 설명). 위의 주소는 단순한 자리 표시자이므로, 반드시 자신의 계정 주소로 교체해야 합니다.
0x3.2 모듈 준비
아래는 move 파일(예: hello.move)에 직접 넣을 수 있는 간단하지만 완전한 샘플 모듈입니다. 다음에서는 Move와 다른 프로그래밍 언어의 차이점을 설명하기 위해 코드를 살펴보겠습니다. 이미 잘 알고 있다면 이 섹션을 건너뛰어도 됩니다.
module BlockSec::hello{
use aptos_framework::account;
use aptos_framework::event;
use std::signer;
use std::string::{String, utf8};
struct SecEventStore has key{
event_handle: event::EventHandle<String>,
}
public entry fun say_hello_script(account: &signer) acquires SecEventStore{
say_hello(account);
}
public fun say_hello(account: &signer) acquires SecEventStore{
let address_ = signer::address_of(account);
if(!exists<SecEventStore>(address_)){
move_to(account, SecEventStore{event_handle: account::new_event_handle(account)});
};
event::emit_event<String>(&mut borrow_global_mut<SecEventStore>(address_).event_handle, utf8(b"Hello World!"));
}
}
여기서 BlockSec 주소에 배포될 hello라는 모듈을 정의합니다. 이 모듈의 엔트리 함수는 say_hello_script로, say_function 함수를 호출합니다. 이 모듈이 say_hello 함수에서 "Hello World!" 메시지와 함께 이벤트를 발생시키는 데 사용된다는 것을 쉽게 알 수 있습니다. 그러나 명확히 설명이 필요한 세부 사항들이 여전히 존재합니다.
구체적으로, aptos_framework 네임스페이스의 event::emit_event 함수를 사용하기 위해서는 emit_event 함수의 선언이 다음과 같으므로 event::EventHandle 구조체가 필요합니다:
/// Emit an event with payload `msg` by using `handle_ref`'s key and counter.
public fun emit_event<T: drop + store>(handle_ref: &mut EventHandle<T>, msg: T)
struct EventHandle<phantom T: drop + store> has store {
/// Total number of events emitted to this event stream.
counter: u64,
/// A globally unique ID for this event stream.
guid: GUID,
}
EventHandle은 key 능력(ability)을 가지지 않으므로, 다른 구조체에 저장해야 합니다. 따라서 EventHandle을 저장하기 위해 SecEventStore라는 구조체를 정의합니다:
struct SecEventStore has key{
event_handle: event::EventHandle<String>,
}
팁#2: Move에서 구조체의 능력(abilities)을 반드시 고려해야 합니다.
_****_key_****_능력만이_****_move_to_****_될 수 있다는 것을 기억하세요. 모듈이_****_store_****_능력만 가진 구조체를 반환하고 이를 전역 스토리지에 보존하려면, 래퍼로서 새 구조체를 정의하는 것을 고려하세요.
단순화를 위해 메시지를 나타내는 데 String을 사용합니다. 따라서 say_hello 함수의 최종 단계는 다음과 같습니다:
event::emit_event<String>(&mut borrow_global_mut<SecEventStore>(address_).event_handle, utf8(b"Hello World!"));
팁#3: Move는 기본적으로
_****_String_****_타입을 지원하지 않습니다. 표준 라이브러리는 바이트 벡터를_****_String_****_으로 변환하는 기능을 제공합니다. 자세한 내용은 GitHub 저장소의 소스 코드를 확인하세요.
모든 새로운 사용자가 SecEventStore에 등록해야 하도록 하기 위해, exists 함수를 통해 사용자 계정에 구조체가 존재하는지 먼저 확인해야 합니다. 사용자가 리소스를 가지고 있지 않다면, 함수는 하나를 생성하여 사용자 계정으로 이동시킵니다.
if(!exists<SecEventStore>(address_)){
move_to(account, SecEventStore{event_handle: account::new_event_handle(account)});
};
0x3.3 모듈 컴파일 및 배포
모듈이 준비되면 다음 명령어로 컴파일할 수 있습니다:
$ aptos move compile
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
{
"Result": [
"c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd::hello"
]
}
필요하다면 테스트도 할 수 있습니다:
$ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
Running Move unit tests
Test result: OK. Total tests: 0; passed: 0; failed: 0
{
"Result": "Success"
}
이제 Aptos 네트워크에 모듈을 배포할 수 있습니다. 사용자는 자신이 제어하는 계정에만 모듈을 배포할 수 있으므로, 계정을 BlockSec과 연결한 것을 기억하세요. 또한 파우셋이 가스비 지불을 위해 이미 계정에 일부 APT를 지급했습니다. 남은 것은 Move 패키지의 모듈을 Aptos 네트워크에 배포하는 것입니다:
$ aptos move publish --package-dir ./ --profile default
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
package size 1271 bytes
Do you want to submit a transaction for a range of [672200 - 1008300] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result":
...
}
이것도 대화형 셸이며, Result의 내용은 생략되었습니다.
0x3.4 모듈과 상호작용
모듈이 이벤트를 발생시키도록 하려면 다음 명령어를 입력하세요:
$ aptos move run --function-id default::hello::say_hello_script
Do you want to submit a transaction for a range of [34500 - 51700] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "0x9af16532de5e79803c823fe28e3251703927d93809274b76972d8e83c6fcd433",
...
}
}
엔트리 함수로서 say_hello_script 함수를 직접 호출할 수 있습니다. 스크립트를 작성하여 스크립트에서 say_hello 함수를 호출할 수도 있습니다.
팁#4: 더 나은 상호작용 경험을 위해, 일부 엔트리 함수를 정의하는 것이 좋은 방법입니다. 사용자가 프로젝트와 상호작용할 수 있도록 일부 스크립트를 개발할 수도 있습니다.
전통적인 Web2 Hello World 프로그램과 달리, 발생한 이벤트는 셸에 표시되지 않습니다. Aptos 탐색기를 확인하고 local 네트워크를 선택하세요.

그런 다음 셸에서 transaction_hash 값을 복사하여 검색창에 붙여넣으면 트랜잭션 세부 정보를 볼 수 있습니다.

마지막으로 Events를 클릭하면, Aptos 네트워크가 여러분에게 인사를 건넬 것입니다.

0x4. 다음 단계는?
Hello World 프로그램은 Move 애플리케이션 개발을 위한 작은 첫걸음에 불과합니다. 앞으로 연재될 글에서는 Aptos에서 안전하고 보안성 높은 Move 애플리케이션을 개발하는 방법에 대해 더 많이 소개할 예정입니다. 많은 기대 부탁드립니다!
BlockSec 소개
BlockSec은 전 세계적으로 著名한 보안 전문가들이 2021년에 설립한 선구적인 블록체인 보안 회사입니다. 이 회사는 대중적 채택을 촉진하기 위해 신흥 Web3 세계의 보안성과 사용성을 향상시키는 데 전념하고 있습니다. 이를 위해 BlockSec은 스마트 컨트랙트 및 EVM 체인 보안 감사 서비스, 보안 개발 및 능동적 위협 차단을 위한 Phalcon 플랫폼, 자금 추적 및 조사를 위한 MetaSleuth 플랫폼, 그리고 Web3 빌더들이 크립토 세계를 효율적으로 탐색할 수 있도록 돕는 MetaSuites 확장 프로그램을 제공합니다.
현재까지 MetaMask, Uniswap Foundation, Compound, Forta, PancakeSwap 등 300개 이상의 저명한 고객사를 대상으로 서비스를 제공했으며, Matrix Partners, Vitalbridge Capital, Fenbushi Capital 등 저명한 투자사로부터 두 차례의 투자 라운드를 통해 수천만 달러를 유치했습니다.
공식 웹사이트: https://blocksec.com/
공식 트위터 계정: https://twitter.com/BlockSecTeam



