TON 스마트 계약의 3가지 인증 유형

발행: (2025년 12월 5일 오전 05:48 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

소개

스마트 계약에서는 특정 행위를 특정 행위자에게만 제한해야 할 때가 많습니다.
대표적인 예가 지갑 계약입니다: 메시지 발신자를 인증해 유효한 사용자만 자금을 보낼 수 있도록 해야 합니다.

아래는 TON 스마트 계약에서 메시지를 인증하는 세 가지 일반적인 방법입니다. 이 메커니즘들은 별도 언급이 없는 한 외부 메시지에 사용됩니다.

서명 기반 인증 (외부 메시지)

계약은 데이터에 저장된 공개키를 사용해 메시지의 서명을 검증합니다. 이 방법은 결정론적이며, 계약 저장소가 공개되어 있기 때문에 개인키를 계약 내부에 보관할 수 없다는 점에서 작동합니다.

// wallet3-code.fc (excerpt)
() recv_external(slice in_msg) impure {
  var signature = in_msg~load_bits(512);
  ;; some code
  var (stored_seqno, stored_subwallet, public_key) =
      (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
  ;; 
  throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
  accept_message();
  ;; other code
}

Source: wallet‑v3 contract on GitHub

왜 작동하는가

  1. 결정론성 – 암호학적 검증은 무작위 수 생성과 달리 결정론적입니다.
  2. 공개 저장소 – 공개키를 계약 상태에 안전하게 저장할 수 있습니다.

서명 기반 인증은 외부 메시지에 가장 널리 사용되는 방법입니다.

주소 비교 (내부 메시지)

내부 메시지의 경우 계약은 발신자의 주소를 상태에 저장된 주소와 단순히 비교합니다.

// nft-collection-editable.fc (excerpt)
() recv_internal(cell in_msg_full, slice in_msg_body) impure {
    if (in_msg_body.slice_empty?()) {
        ;; ignore empty messages
        return ();
    }
    slice cs = in_msg_full.begin_parse();
    int flags = cs~load_uint(4);

    if (flags & 1) {
        ;; ignore all bounced messages
        return ();
    }

    slice sender_address = cs~load_msg_addr();

    int op = in_msg_body~load_uint(32);
    int query_id = in_msg_body~load_uint(64);

    var (owner_address, next_item_index, content, nft_item_code, royalty_params) = load_data();

    ;; some code

    throw_unless(401, equal_slices(sender_address, owner_address));

    ;; some code
}

Source: NFT Collection contract on GitHub

계약은 소유자 주소를 저장하고, 발신자가 일치하지 않을 경우 오류를 발생시킵니다. 이 방식은 역할별로 여러 인증 주소를 저장하도록 확장할 수 있습니다.

다중 발신자 인증 (Jetton Wallet 예시)

계약이 임의의 다수 발신자를 인증해야 할 때—예를 들어 Jetton 계약—보다 유연한 접근이 필요합니다. Jetton Wallet은 발신자 지갑이 동일한 Jetton Master에 속하거나, 발신자 주소에서 파생된 결정론적 지갑 주소인지 확인합니다.

// jetton-wallet.fc (excerpt)
() receive_jettons(slice in_msg_body, slice sender_address, int my_ton_balance, int msg_value)
    impure inline_ref {
    (int status, int balance, slice owner_address, slice jetton_master_address) = load_data();
    int query_id = in_msg_body~load_query_id();
    int jetton_amount = in_msg_body~load_coins();
    slice from_address = in_msg_body~load_msg_addr();
    slice response_address = in_msg_body~load_msg_addr();

    throw_unless(error::not_valid_wallet,
        equal_slices_bits(jetton_master_address, sender_address)
        |
        equal_slices_bits(
            calculate_user_jetton_wallet_address(
                from_address,
                jetton_master_address,
                my_code()
            ),
            sender_address
        )
    );

    ;; other code
}

Source: Jetton Wallet contract on GitHub

핵심 포인트

  • calculate_user_jetton_wallet_address는 발신자 주소, Jetton Master 주소, 그리고 계약 코드(my_code())를 이용해 기대되는 지갑 주소를 파생합니다.
  • my_code()c7 레지스터를 통해 현재 계약 코드를 반환합니다(자세한 내용은 TVM 레지스터 문서를 참고).
  • 계약은 외부 계약 주소를 계산하기 위해 다른 계약의 코드를 저장할 수도 있습니다.
  • 초기화 파라미터가 필요할 경우, 두 계약이 공통으로 알고 있는 파라미터(예: 관리자 주소)가 있다면 메시지보다 자체 저장소에서 읽는 것이 안전합니다.

결론

올바른 인증 전략을 선택하는 것은 TON 스마트 계약 아키텍처를 설계할 때 핵심 요소입니다. 외부 메시지에는 서명 검증을, 간단한 내부 검증에는 주소 비교를, 다수의 발신자를 허용해야 할 경우에는 Jetton Wallet처럼 결정론적 주소 계산을 활용하세요.

행복한 코딩 되세요! 🚀

Back to Blog

관련 글

더 보기 »

스마트 계약 초보자를 위한

소개 블록체인 개념을 배우는 것은 어려울 수 있지만, 스마트 계약을 이해하는 것은 그리 어려울 필요가 없습니다. 이 가이드는 스마트 계약의 기본을 소개합니다.

크립토 결제 게이트웨이 설명

암호화폐 결제 게이트웨이 정의 암호화폐 결제 게이트웨이는 주문이나 청구서와 같은 오프체인 비즈니스 이벤트를 연결하는 서비스 또는 내부 구성 요소입니다—