컴플라이언스는 지갑 시스템 옆에 붙는 보조 기능이 아닙니다.

출금이 서명되기 전에 반드시 통과해야 하는 gate입니다.

이 글은 국내 규제 요구사항을 수탁형 지갑 시스템 흐름에 넣는 아키텍처를 정리합니다.

권고 아키텍처

flowchart LR
  channel[고객 채널<br/>web, mobile, ops]
  kyc[KYC / CDD / EDD]
  orchestrator[수탁 오케스트레이터<br/>deposit, withdrawal, settlement]
  ledger[내부원장<br/>고객별 balance, hold, settlement]
  aml[AML / KYT / Travel Rule]
  policy[정책 검사<br/>amount, asset, destination, velocity]
  provider[Signer / Custody Provider<br/>Fireblocks or other]
  hot[Hot Withdrawal Wallet]
  cold[Cold Reserve Wallet]
  deposit[Deposit / Collection Wallet]
  evidence[SIEM / WORM Archive]
  report[규제 보고 Workflow<br/>FIU, FSS, KISA]
  bank[은행 예치/신탁<br/>보험/준비금]

  channel --> kyc
  channel --> orchestrator
  kyc --> ledger
  orchestrator --> ledger
  orchestrator --> aml
  aml --> policy
  policy --> provider
  provider --> hot
  provider --> cold
  provider --> deposit
  provider --> evidence
  ledger --> evidence
  aml --> evidence
  evidence --> report
  ledger --> report
  bank --> ledger

이 구조에서 signer/provider는 중간에 있습니다.

가장 앞에는 KYC/AML/정책 gate가 있고, 가장 뒤에는 증적과 보고 체계가 있습니다.

출금 compliance gate

출금 흐름은 아래처럼 직렬화되어야 합니다.

sequenceDiagram
  participant USER as 고객/운영자
  participant APP as 수탁 오케스트레이터
  participant LEDGER as 내부원장
  participant KYC as KYC/AML/Travel Rule
  participant POLICY as 정책엔진
  participant SIGN as Signer/Provider
  participant BC as Blockchain
  participant EVID as SIEM/WORM

  USER->>APP: 출금 요청
  APP->>LEDGER: available balance 확인 및 hold
  APP->>KYC: CDD 상태, AML/KYT, Travel Rule 검사
  KYC-->>APP: pass / hold / reject
  APP->>POLICY: 금액, 자산, 목적지, 속도 제한 검사
  POLICY-->>APP: approve / require approval / block
  APP->>SIGN: transaction 생성/서명 요청
  SIGN-->>APP: provider transaction id / tx hash
  SIGN->>BC: broadcast
  APP->>EVID: 요청, verdict, 승인, tx id 저장
  BC-->>APP: receipt / confirmation
  APP->>LEDGER: finalize or release hold
  APP->>EVID: 최종 상태 저장

여기서 중요한 점은 signer 호출 전에 compliance verdict가 있어야 한다는 것입니다.

상태 분리

컴플라이언스 때문에 출금 상태는 단순하지 않습니다.

flowchart TB
  START([start])
  REQUESTED[REQUESTED]
  KYC_CHECK[KYC_CHECK]
  AML_CHECK[AML_CHECK]
  TRAVEL_RULE_CHECK[TRAVEL_RULE_CHECK]
  WAITING_FOR_TRAVEL_RULE[WAITING_FOR_TRAVEL_RULE]
  LEDGER_HOLD[LEDGER_HOLD]
  POLICY_CHECK[POLICY_CHECK]
  MANUAL_REVIEW[MANUAL_REVIEW]
  MANUAL_APPROVAL[MANUAL_APPROVAL]
  SUBMITTED_TO_PROVIDER[SUBMITTED_TO_PROVIDER]
  BROADCASTED[BROADCASTED]
  CONFIRMED[CONFIRMED]
  FINALIZED[FINALIZED]
  REJECTED[REJECTED]
  END([end])

  START --> REQUESTED
  REQUESTED --> KYC_CHECK
  KYC_CHECK -- "KYC pass" --> AML_CHECK
  KYC_CHECK -- "KYC fail" --> REJECTED
  AML_CHECK -- "AML pass" --> TRAVEL_RULE_CHECK
  AML_CHECK -- "AML hold" --> MANUAL_REVIEW
  TRAVEL_RULE_CHECK -- "required data ready" --> LEDGER_HOLD
  TRAVEL_RULE_CHECK -- "missing data" --> WAITING_FOR_TRAVEL_RULE
  LEDGER_HOLD --> POLICY_CHECK
  POLICY_CHECK -- "approved" --> SUBMITTED_TO_PROVIDER
  POLICY_CHECK -- "approval required" --> MANUAL_APPROVAL
  SUBMITTED_TO_PROVIDER --> BROADCASTED
  BROADCASTED --> CONFIRMED
  CONFIRMED --> FINALIZED
  MANUAL_REVIEW --> REJECTED
  MANUAL_APPROVAL --> SUBMITTED_TO_PROVIDER
  FINALIZED --> END
  REJECTED --> END

MANUAL_REVIEWMANUAL_APPROVAL은 다릅니다.

MANUAL_REVIEW
-> AML/위험/규제 판단이 필요한 상태

MANUAL_APPROVAL
-> 정책상 추가 승인자가 필요한 상태

evidence model

감사와 보고를 위해서는 transaction 하나를 재구성할 수 있어야 합니다.

필요한 증적입니다.

withdrawal_request_id
user_id
KYC/CDD status
AML/KYT verdict
Travel Rule message id
ledger hold entry id
policy rule version
approval actor
provider transaction id
tx hash
receipt
final ledger entry id
webhook event id
operator action log

이 증적은 서로 다른 시스템에서 나옵니다.

따라서 공통 correlation id가 필요합니다.

withdrawal_request_id
-> ledger
-> KYC/AML
-> Travel Rule
-> provider transaction
-> blockchain tx
-> archive

설계 원칙

KYC/AML/Travel Rule은 signer 앞의 gate다.
ledger hold 없이 provider transaction을 만들지 않는다.
provider webhook은 event source이고, chain watcher와 reconciliation이 필요하다.
규제 보고는 운영 기능이 아니라 별도 workflow로 둔다.
모든 verdict와 승인 판단은 15년 보존 대상 후보로 본다.

추가 확인 필요

Travel Rule provider를 어디로 둘 것인가?
KYC/CDD 상태를 출금 시스템이 어떤 API로 확인할 것인가?
AML hold 상태에서 ledger hold를 유지할 최대 기간은 얼마인가?
STR 후보가 된 출금을 자동 차단할지 수동 검토로 둘지 결정해야 한다.
provider transaction id와 내부 request id 매핑을 어디에 저장할 것인가?

참고 자료