모네로 서브주소와 페이먼트 ID: 지금도 통하는 것
최근 모네로 거래 1,463건 중 92.8%가 '페이먼트 ID처럼 보이는 것'을 달고 있었고, 구식 32바이트 롱 ID는 단 한 건도 없었습니다. 서브주소의 정체, 패딩이 존재하는 이유, 수취 측이 자주 틀리는 다섯 가지를 정리합니다.
모네로 거래의 약 93%에 페이먼트 ID가 붙어 있지만, 의미 있는 것은 거의 없습니다. 2026년 10월 24일 블록 3,791,102~3,791,141에는 일반 거래 1,463건이 있었습니다. 그중 1,357건(92.8%)의 extra 필드에 nonce가 있었고, 그 1,355건은 정확히 9바이트, 즉 0x01 마커 + 8바이트 암호화 페이먼트 ID였습니다. 2017년 거래소가 쓰던 32바이트 롱 ID를 가진 거래는 한 건도 없습니다. 공식 Moneropedia는 분명합니다 — 롱 페이먼트 ID는 0.15에서 제거되어 더는 쓸 수 없습니다. 그러니 온체인에서 '페이먼트 ID처럼 보이는 것'은 대부분 지갑이 일부러 넣은 패딩입니다.
주소와 페이먼트 ID는 서로 다른 객체이고, 이 둘을 혼동하는 것이 대부분의 문의를 만듭니다. 모네로 주소는 95자입니다: 1바이트 네트워크 접두사, 32바이트 spend 공개키, 32바이트 view 공개키, 4바이트 체크섬을 base58로 8바이트 블록 단위로 인코딩합니다 — 11자 블록 8개에 5바이트 꼬리(7자)를 더해 95자가 됩니다. 접두사가 첫 글자를 결정하며, cryptonote_config.h에서 표준 주소는 18(4로 시작), 서브주소는 42(8로 시작), 통합 주소는 19입니다. 통합 주소는 같은 내용에 8바이트 페이먼트 ID를 넣은 것으로 77바이트·106자이고 여전히 4로 시작합니다. 페이먼트 ID는 (통합 형식을 빼면) 주소 안에 있지 않고, 거래 extra 필드에 메타데이터로 실립니다.
서브주소는 이미 가진 주소에 키를 한 번 더한 것일 뿐, 두 번째 지갑이 아닙니다. 서브주소(계정, 인덱스)의 spend 공개키는 주 spend 공개키에 '주 view 비밀키 + 계정 번호 + 서브주소 번호'의 해시를 더한 값이고, view 키는 공유됩니다. 계정 0의 인덱스 0이 바로 주 주소이며, 지갑이 목록 맨 앞에 두는 이유입니다. 인덱스는 32비트 정수라 한 계정으로 4,294,967,295개의 용도에 라벨을 붙일 수 있고, 두 번째 시드도 두 번째 백업도 필요 없습니다. 고객마다·주문마다·청구서마다 별도 모네로 주소를 줄 수 있는 근거가 이것입니다. 체인은 서로 무관해 보이는 목적지를 보고, 지갑에는 라벨이 붙은 하나의 계정만 남습니다.
이 패딩은 의도된 것이고 소스 코드에도 적혀 있습니다. cryptonote_tx_utils.cpp의 거래 생성 코드는 `bool add_dummy_payment_id = true;`로 시작하고, 롱 ID도 숏 ID도 없으면 null hash8을 암호화해 덧붙입니다. 주석에는 '시간이 지나면 대다수 거래가 이렇게 될 것'이라고 되어 있습니다. 두 경우에 꺼집니다: 이미 페이먼트 ID가 있는 거래, 또는 '수취 1개 + 거스름돈'보다 목적지가 많은 거래입니다. 온체인 표본은 이 규칙과 거의 일치했습니다. nonce가 있는 1,357건은 모두 출력이 정확히 2개였고, nonce가 없는 106건 중 96건은 출력이 3개 이상(3개 49건, 4개 16건, 16개 1건)이었습니다. 예외 10건은 출력 2개인데 패딩하지 않은 지갑입니다.
프라이버시 효과는 양방향이고, 그게 핵심입니다. 보내는 쪽에는 이점입니다. 실제로 페이먼트 ID가 있는 거래와 없는 거래를 구분할 수 없으니, 누가 거래소로 보내는지가 새지 않습니다. 받는 쪽에는 의지하던 신호가 사라집니다. 체인을 봐도 보낸 사람이 입력한 ID인지 지갑이 만든 ID인지 알 수 없습니다. 그래서 입금 매칭은 주소, 더 나아가 전용 서브주소에 걸어야 하고 페이먼트 ID에 걸면 안 됩니다. 아직 페이먼트 ID로 고객과 입금을 연결한다면, 93%가 노이즈인 필드로 대조하고 있는 셈입니다.
서브주소도 8바이트 페이먼트 ID도 추가 비용이 없고, 수수료는 어느 쪽인지 보지 않습니다. 2026년 10월 24일 14:00 UTC 이전 10개 블록의 326건에서 수수료율은 바이트당 20,000 / 80,000 / 320,000 piconero 세 구간으로 나뉘었고 각각 179·74·39건이었습니다. 수수료 중앙값은 44,570,000 piconero, 즉 0.00004457 XMR로 CoinGecko XMR 597.78달러 기준 약 0.027달러입니다. 입력 1·출력 2 거래는 1,534바이트, 입력 2·출력 2는 2,220바이트였습니다. 서브주소 출력은 평범한 출력이라 같은 tagged key, 같은 30여 바이트이고 할증이 없습니다. 8바이트 페이먼트 ID는 tx_extra에 9바이트를 더하지만 그 필드는 어차피 패딩되므로 켜도 크기가 변하지 않습니다. 실제 변수는 지갑이 고르는 우선순위 등급이고, 같은 거래에서 최대 16배 차이가 납니다.
스왑 주문에서는 규칙이 하나로 좁혀집니다 — 95자를 붙여넣고 끝. 주문 폼은 XMR 주소 하나만 받습니다. 통화 목록에서 xmr의 hasExtraId가 false이므로 채울 태그 칸도, 지어낼 페이먼트 ID도 없습니다. 주문 API는 주소가 256자 미만 문자열인지만 확인하므로 106자 통합 주소도 검증을 통과하고 온체인에서도 받힙니다. 다만 주문이 요구하는 형식이 아니고, 이런 차이가 입금을 수동 검토로 밀어넣습니다. 2026년 10월 24일 14:05 UTC 견적 API는 100 USDT-TRC20 → 0.16382091 XMR, 500 → 0.82593, 1,000 → 1.652442, 5,000 → 8.264534를 반환했고 1 XMR은 592.31 USDT였습니다. 거래소 출금 폼이 페이먼트 ID를 물으면 비워 두세요. 우리가 요구한 적 없는 ID는 매칭에 도움이 되지 않고, 32바이트 롱 ID는 브로드캐스트 자체가 불가능합니다. (XMR→USDT 출구 루트)
수취 측이 지금도 틀리는 다섯 가지. 첫째, 페이먼트 ID를 필수로 취급해 ID 없이 도착한 입금을 거절하는 것. 자금은 주소에 있고, 빠진 것은 결제가 아니라 칸입니다. 둘째, 95자라고 명시된 폼에 106자 통합 주소를 붙여넣는 것. 업체에 따라 즉시 무효 처리합니다. 셋째, 모든 용도에 서브주소 하나를 공유하는 것. 서브주소가 풀려던 '공유 주소' 문제를 스스로 다시 만드는 셈입니다. 넷째, 통합 주소로 일괄 지급하는 것. 암호화 페이먼트 ID 경로는 목적지가 정확히 하나여야 하고, cryptonote_tx_utils.cpp의 생성 로직은 다중 출력 목적지에서 오류를 냅니다. 다섯째, 새 서브주소면 금액과 시점도 숨겨진다고 믿는 것. 숨겨지지 않습니다. 고객끼리 분리해 줄 뿐입니다.
서브주소를 제대로 운영하는 데 필요한 습관은 세 가지입니다. 만들 때 라벨을 붙이세요. 라벨 없는 행이 200개인 지갑은 대조할 수 없는 장부입니다. 환불 주소는 같은 시드의 다른 서브주소로 두세요. 실패한 주문이 고객에게 보이는 주소로 되돌아가는 사고를 막습니다. 읽기 전용 회계에는 시드가 아니라 view 키를 쓰세요. view 키는 금액을 보여주되 지출 권한은 주지 않아, 질문에 답할 수 있는 최소 노출입니다. 시간은 어떤가. 표본 40개 블록의 평균 간격은 105.9초(목표 120초)였으므로 10컨펌은 약 20분입니다. 이 대기는 목적지가 주 주소든 계정 3의 87번 서브주소든 같습니다.
기억할 규칙. 페이먼트 ID는 공유 주소에 붙인 라벨이고, 서브주소는 그 자체가 주소인 라벨입니다. 2026년에는 수취 측을 내가 통제하는 곳마다 후자를 쓰고, 남의 폼이 페이먼트 ID를 물으면 비워 두세요. 위의 모든 수치는 2026년 10월 24일 14:00 UTC 전후의 체인과 자체 엔드포인트에서 나왔습니다 — 거래 1,463건, 수수료 표본 326건, 1 XMR = 592.31 USDT(현물 597.78). 가격은 움직이므로 구속력이 있는 것은 스왑 페이지의 실시간 견적뿐입니다. (XMR→USDT 출구 루트)