17. Deposit Observation Lifecycle

Incoming tx flow + DCCP confirmation policy + zero-confirmation webhook
Fireblocks 명시 vs Hypothesis 분리

본 페이지는 일부 Fireblocks 명시 + 일부 hypothesis 의 혼합:

  • 명시: 17 status state machine 의 incoming flow (Stage 9), DCCP (Stage 10), zero-confirmation webhook (Stage 9), Manually confirm and credit inbound (권한표)
  • Hypothesis: deposit observation 의 DB row 모델, ledger credit 의 정확한 trigger, reorg handling 의 DB 표현 → persistence-architecture/07 패턴 사용

Incoming Transaction Flow (Fireblocks 명시)

stateDiagram-v2
  [*] --> START
  START --> PENDING_AML_SCREENING : AML/KYC enabled
  START --> BROADCASTING : network conn / exchange / gas station
  START --> CONFIRMING : AML/KYC disabled
  PENDING_AML_SCREENING --> REJECTED : reject (asset → Admin unfreeze 까지 lock)
  PENDING_AML_SCREENING --> PENDING_3RD_PARTY
  PENDING_3RD_PARTY --> CONFIRMING
  CONFIRMING --> COMPLETED : DCCP confirmation threshold 도달
  CONFIRMING --> FAILED
  CONFIRMING --> REJECTED : user-initiated freeze via API
      
Figure 10. Incoming tx flow — Stage 9 명시. AML/KYC 분기, DCCP 가 CONFIRMING → COMPLETED transition trigger.

DCCP — Deposit Control and Confirmation Policy (★ Stage 10)

about-the-deposit-control-and-confirmation-policy.md:

  • blockchain confirmation 횟수 정책 (incoming + outgoing)
  • Clear 전: inflow/outflow state 에 lock — 사용 불가
  • Clear 후: wallet available balance + UTXO outputs 즉시 spendable
  • CONFIRMING → COMPLETED transition 의 정확한 trigger
  • Override 메커니즘 + custom build 옵션 별도 존재 (TIER 3 source-lake-only)

Zero-Confirmation Webhook 의 Multiple-Notification (★ Stage 9)

primary-transaction-statuses.md, p.6: zero-confirmation Deposit Policy 의 경우 Completed status 에 대해 multiple webhook 수신 가능 (blockchain appearance + 첫 confirmation + 추가).

→ DB 측은 idempotent insert + webhook delivery 추적 필요.

Manual Confirm and Credit (★ Admin override)

user-roles.md, p.2 권한표: Manually confirm and credit inbound transactions — Admin only. Anomaly / DCCP 미달 입금에 대한 수동 처리 path.

Internal Transactions (EVM, ★ Stage 7)

blockchains-that-support-internal-transactions.md:

  • Internal tx = smart contract 실행 중 발생하는 native asset transfer
  • 별도 tx hash 없고 실행 흐름의 일부
  • Fireblocks 가 모든 EVM 의 직접 native transfer는 알림
  • Internal tx 까지 알리는 chain 은 subset (~35 mainnet + ~24 testnet — Ethereum / Optimism / Arbitrum / Avalanche / Base / Celo 등)
  • 감지 메커니즘 (trace API / archive node) 은 Fireblocks 자료 미명시

DB Schema (Fireblocks 명시 + persistence-architecture/07 hypothesis)

-- ★ append-only — chain 에서 관찰된 사건
CREATE TABLE chain_events (
  id                BINARY(16) PRIMARY KEY,
  chain             VARCHAR(32) NOT NULL,
  block_hash        VARCHAR(128) NOT NULL,
  block_height      BIGINT NOT NULL,
  tx_hash           VARCHAR(128),                    -- internal tx 는 NULL 가능
  log_index         INT,                              -- internal tx / event index
  event_type        ENUM('native-transfer', 'internal-transfer', 'erc20-transfer') NOT NULL,
  to_address        VARCHAR(128) NOT NULL,
  amount_raw        VARCHAR(80) NOT NULL,             -- decimal string for big numbers
  observed_at       DATETIME(6) NOT NULL,
  KEY (chain, block_height),
  KEY (to_address),
  UNIQUE KEY (chain, tx_hash, log_index)
);

-- 우리가 관찰 / 매핑한 deposit
CREATE TABLE deposit_observations (
  id                BINARY(16) PRIMARY KEY,
  chain_event_id    BINARY(16) NOT NULL,
  matched_address_id BINARY(16),                      -- 우리 vault 의 address (NULL = unmatched)
  asset_wallet_id   BINARY(16),
  workspace_id      BINARY(16),
  status            ENUM('observed', 'aml-pending', 'aml-rejected',
                          'confirming', 'dccp-cleared', 'ledger-credited',
                          'manually-credited', 'failed') NOT NULL,
  confirmations     INT NOT NULL DEFAULT 0,
  required_confirmations INT NOT NULL,                -- DCCP threshold
  manual_credit_actor_user_id BINARY(16),             -- Admin override
  cleared_at        DATETIME(6),                      -- ★ set-once
  KEY (workspace_id, status),
  KEY (matched_address_id)
);

-- Webhook delivery 의 idempotency
CREATE TABLE deposit_webhook_deliveries (
  id                BINARY(16) PRIMARY KEY,
  deposit_observation_id BINARY(16) NOT NULL,
  notification_type ENUM('blockchain-appearance', 'first-confirmation',
                          'additional-confirmation', 'completion') NOT NULL,
  delivered_at      DATETIME(6) NOT NULL,
  UNIQUE KEY (deposit_observation_id, notification_type)
);

Reorg Handling (hypothesis)

Fireblocks 자료에 deposit-side reorg handling 의 명시적 절차는 없음. persistence-architecture/07 의 일반 패턴:

  • chain_events 는 append-only — reorg 발생 시 이전 row 를 UPDATE 하지 않고, 새 reversing event 를 INSERT
  • deposit_observations 의 status 를 confirmingfailed 로 전이 (set-once 가 아닌 status 컬럼은 UPDATE 가능)
  • 이미 ledger credit 된 경우 reversal entry (→ 23)