마스터링 Sui DeepBook: 실전 DeFi DEX 시리즈 (3)

발행: (2025년 12월 18일 오후 01:39 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

Note 계약 이해하기

아래는 이번 튜토리얼에서 사용할 노트 계약의 코드입니다. 이 노트 계약은 사용자가 노트를 생성하고 삭제할 수 있게 하는 아주 간단한 개념 증명(Proof‑of‑Concept)입니다. 코드의 각 부분을 이해할 수 있도록 자세한 주석을 추가했습니다.

Note 모듈

새 파일 sources/notes.move를 만들고 다음 코드를 추가하세요:

#[lint_allow(self_transfer)]
module dacade_zklogin::notes {
    use sui::tx_context::{TxContext, Self};
    use sui::transfer::Self;
    use sui::object::{Self, UID};
    use std::string::String;

    /// Notes(공유 객체)의 ID를 저장하기 위한 구조체
    struct Notes has key {
        id: UID
    }

    /// 개별 Note를 나타내는 구조체
    struct Note has key, store {
        id: UID,
        title: String,
        body: String
    }

    /// Notes 공유 객체를 생성하는 모듈 초기화 함수
    #[allow(unused_function)]
    fun init(ctx: &mut TxContext) {
        let notes = Notes {
            id: sui::object::new(ctx),
        };
        // 모든 사용자가 접근할 수 있도록 Notes 객체를 공유
        transfer::share_object(notes)
    }

    /// 새로운 노트를 생성하는 함수
    /// @param title: 노트의 제목
    /// @param body: 노트의 본문
    /// @param ctx: 트랜잭션 컨텍스트
    public fun create_note(title: String, body: String, ctx: &mut TxContext) {
        let note = Note {
            id: object::new(ctx),
            title,
            body
        };
        // 트랜잭션 발신자에게 노트를 전송
        transfer::transfer(note, tx_context::sender(ctx))
    }

    /// 노트를 삭제하는 함수
    /// @param note: 삭제할 노트 객체
    /// @param _ctx: 트랜잭션 컨텍스트
    public fun delete_note(note: Note, _ctx: &mut TxContext) {
        // Note 구조체를 풀어 필드에 접근
        let Note { id, title: _, body: _ } = note;
        // 객체 ID를 삭제하여 노트를 실제로 삭제
        sui::object::delete(id)
    }
}

코드 상세 분석

이 계약은 매우 직관적입니다.

구조체 – 두 개의 구조체가 있습니다: NotesNote.

  • Notesinit에서 생성·공유되는 공유 객체입니다. 이 간단한 버전에서는 UID만 보관합니다.
  • Note – 개별 노트를 나타냅니다. keystore 능력을 가지고 있어 주소가 소유하고 전송할 수 있습니다. id, title, body를 저장합니다.

init 함수 – 패키지가 배포될 때 한 번 실행됩니다. Notes 구조체를 만들고 공유하여 모든 사람이 접근할 수 있게 합니다.

create_note 함수 – 누구나 새로운 노트를 만들 수 있습니다. 제목과 본문을 받아 Note 객체를 생성하고, 이를 발신자(tx_context::sender(ctx))에게 전송합니다. 호출자가 노트의 소유자가 됩니다.

delete_note 함수 – 노트 소유자가 해당 노트를 삭제할 수 있습니다. Note 객체를 값으로 받아(소모하고) 풀어 UID를 삭제함으로써 노트를 제거합니다.

포괄적인 테스트 작성

스마트 계약 개발에서는 테스트가 필수입니다. 노트를 올바르게 생성하고 삭제할 수 있는지 검증하는 테스트 모듈을 작성해 보겠습니다.

새 파일 sources/notes_tests.move를 만들거나 기존 테스트 파일에 아래 코드를 추가하세요:

#[test_only]
module dacade_zklogin::notes_tests {
    use dacade_zklogin::notes::{Self, Note};
    use sui::test_scenario;
    use std::string::{Self};

    #[test]
    fun test_create_and_delete_note() {
        let user = @0xA;
        // `user`를 발신자로 하는 테스트 시나리오 시작
        let scenario = test_scenario::begin(user);

        // 1. 노트 생성
        {
            let ctx = test_scenario::ctx(&mut scenario);
            let title = string::utf8(b"My First Note");
            let body = string::utf8(b"This is the body of my note.");
            notes::create_note(title, body, ctx);
        };

        // 2. 노트 생성 및 소유권 검증
        test_scenario::next_tx(&mut scenario, user);
        {
// Take the Note object from the sender's inventory
let note = test_scenario::take_from_sender(&scenario);

// If we successfully took it, the note was created and transferred to the user.
// Now, let's delete it.

// 3. Delete the note
let ctx = test_scenario::ctx(&mut scenario);
notes::delete_note(note, ctx);
};

// 4. Verify note deletion
test_scenario::next_tx(&mut scenario, user);
{
    // Check that the user no longer has the note.
    // `has_most_recent_for_sender` returns false if the object is no longer accessible/owned.
    assert!(!test_scenario::has_most_recent_for_sender(&scenario), 0);
};

test_scenario::end(scenario);
}
}

테스트 실행

테스트를 실행하려면 contract 디렉터리에서 터미널을 열고 다음 명령을 실행하세요:

sui move test

테스트가 성공했음을 나타내는 출력이 표시됩니다:

Running Move unit tests
[ PASS    ] dacade_zklogin::notes_tests::test_create_and_delete_note
Test result: OK. Total tests: 1; passed: 1; failed: 0

“Note” 계약 튜토리얼 끝.

계약 배포

이제 계약을 테스트했으니 Sui Devnet에 배포할 차례입니다.

Devnet으로 전환

Sui 클라이언트가 devnet 환경에 연결되어 있는지 확인하세요.

sui client switch --env devnet

배포

배포 명령을 실행합니다. 트랜잭션이 실행될 충분한 가스를 확보하기 위해 가스 예산을 설정합니다.

sui client publish --gas-budget 100000000

Note: 아직 주소에 자금을 충전하지 않았다면 sui client faucet 명령을 실행해 테스트용 SUI를 받아오세요.

중요한 정보 저장

패키지를 배포하면 Sui CLI가 트랜잭션 요약을 출력합니다. 이 출력에는 나중에 프론트엔드 애플리케이션을 스마트 계약에 연결하기 위해 반드시 저장해야 하는 중요한 정보가 들어 있습니다.

출력에서 Object Changes 섹션을 찾아 다음 ID들을 식별하고 저장하세요:

  • Package ID – 배포된 코드의 ID (Published Objects 아래에 표시).
  • Shared Object IDinit 함수에서 생성된 Notes 객체의 ID (Created Objects 아래에 Owner: Shared 로 표시).

예시 출력 분석

╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                   │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects:                                                                                 │
│  ┌──                                                                                             │
│  │ ObjectID: 0x81833f94d4019d03fdc0d63abdf179950740f513bf434ae182e1031e0568a2b7                  │
│  │ Owner: Shared( 5 )                                                                            │
│  │ ObjectType: 0xfea5f1839d675fa03d5b02208adf2e6167336b4646399cb2248b9a7347a48998::notes::Notes  │
│  └──                                                                                             │
│ ...                                                                                              │
│ Published Objects:                                                                               │
│  ┌──                                                                                             │
│  │ PackageID: 0xfea5f183d675fa03d5b02208adf2e6167336b4646399cb2248b9a7347a48998                 │
│  │ Version: 1                                                                                    │
│  │ Digest: 93isZkd3bCKDqeMUL1wUhWnxYvJT4KLc72U6buFAPS4F                                          │
│  │ Modules: notes                                                                                │
│  └──                                                                                             │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯

저장할 내용

  • Package ID: 0xfea5...8998 (Published Objects 섹션에서)
  • Notes Shared Object ID: 0x8183...a2b7 (Created Objects 섹션에서 Owner가 Shared인 경우)

Tip: 지금 바로 프론트엔드 프로젝트에 .env 파일이나 constants.ts 파일을 만들어 위 값을 저장해 두세요. UI에서 계약과 상호작용하려면 이 값들이 필요합니다.


축하합니다! 여기까지 오셨다면 스스로에게 충분히 칭찬해 주세요—이제 공식적으로 블록체인‑프로 배지를 획득하셨습니다. 😄

첫 번째 Sui Move 스마트 계약을 작성하고, 테스트하고, 배포까지 성공했습니다. 꽤 훌륭하지 않나요?

다음 파트에서는 이 개념들을 실제로 적용해 DeepBook DEX 프론트엔드의 핵심 컴포넌트를 구축할 것입니다. 이론과 실습이 만나면서 이야기가 본격적으로 흥미로워집니다.

Back to Blog

관련 글

더 보기 »