CCTP와 브릿지 신뢰 모델
도입
크로스체인 결제에서 "다른 체인으로 보낸다"는 말은 너무 넓다. 실제로는 원본 자산을 잠그고 래핑 토큰을 발행할 수도 있고, liquidity provider가 먼저 지급한 뒤 나중에 정산할 수도 있으며, CCTP처럼 source chain에서 native USDC를 burn하고 destination chain에서 native USDC를 mint할 수도 있다. 사용자가 보는 UX는 비슷해도 신뢰 주체와 장애 지점은 완전히 다르다.
이 강의에서는 cross-chain을 수수료 절감 기능이 아니라 결제 시스템의 신뢰 모델로 읽는다. 목표는 "어떤 bridge가 좋다"를 고르는 것이 아니라, 어떤 자산을 사용자에게 어떻게 표시하고, 어디서 finality를 기다리고, 실패했을 때 어떤 상태로 복구할지 설계하는 것이다.
이 강의는 CCTP와 bridge의 책임 경계 비교에 집중한다. USDC checkout 상태 설계는 CCTP와 USDC 크로스체인 결제, 작은 구현 검증은 CCTP 시뮬레이터 랩에서 다룬다.
학습 목표
- lock-and-mint bridge, liquidity bridge, CCTP burn-and-mint의 asset model을 구분한다.
- source chain, attestation/proof, destination chain, relayer, issuer의 책임을 분리한다.
- CCTP V2의 finality threshold, fee, hook, migration 항목을 checkout release gate로 바꾼다.
- 사용자에게
Processing,Delayed,Completed,Manual review상태를 일관되게 보여준다.
개념 설명
핵심 개념
- native burn/mint와 lock/mint 브릿지 모델을 비교한다.
- 신뢰 주체와 failure domain을 결제 설계에 반영한다.
검증 지점
- finality와 attestation 조건이 명확한가
- route별 trust assumption이 분리되는가
- 두 모델의 신뢰 경계를 설명했다.
실습 산출물
- CCTP와 bridge risk matrix 작성
- CCTP checkout 상태머신 설계
- timeout/refund가 설계되는가
1. 세 가지 자산 이동 모델
| 모델 | Source chain에서 일어나는 일 | Destination chain에서 받는 것 | 주요 신뢰 주체 | 결제 설계상 위험 |
|---|---|---|---|---|
| Lock-and-mint bridge | 원본 토큰을 bridge contract나 custodian에 lock | wrapped token | bridge contract, validator, custodian | wrapped token redeemability, bridge exploit, liquidity fragmentation |
| Liquidity bridge | LP 또는 solver가 destination에서 먼저 지급 | native 또는 wrapped token | liquidity provider, solver, route engine | 선지급 실패, 가격/수수료 변동, solver censorship |
| CCTP burn-and-mint | native USDC를 burn하고 message를 생성 | native USDC mint | Circle attestation service, CCTP contracts | attestation 지연, supported domain 제한, finality/fee 선택 오류 |
일반 bridge는 "목적지에 토큰이 생겼다"는 사실만으로 충분하지 않다. 그 토큰이 issuer-native인지, wrapped인지, 누가 redemption을 보장하는지까지 봐야 한다. 스테이블코인 checkout에서는 이 차이가 회계, 환불, treasury rebalancing, 사용자 고지에 직접 영향을 준다.
2. CCTP는 wrapped USDC 문제를 줄이지만 중간 상태를 없애지는 않는다
Circle 문서 기준 CCTP는 source domain에서 USDC를 burn하고, Circle의 off-chain attestation service인 Iris가 message를 서명한 뒤, destination domain에서 message를 제출해 USDC를 mint하는 흐름이다. 이 모델은 wrapped asset을 줄이는 장점이 있지만, source burn과 destination mint 사이의 상태를 제품이 책임져야 한다.
학습자는 이 흐름을 "bridge보다 안전하다"로 끝내면 안 된다. CCTP에서도 attestation service, supported chain/domain, finality threshold, destination address encoding, relayer, fee, API rate limit 같은 운영 의존성이 남는다.
3. CCTP V2에서 확인해야 할 필드
CCTP V2는 Fast Transfer, Standard Transfer, hook, fee 관련 항목을 더 명확히 다룬다. checkout integration에서는 아래 필드를 release checklist에 넣어야 한다.
| 항목 | 확인 질문 | 실패하면 |
|---|---|---|
sourceDomain / destinationDomain | 지원되는 domain ID를 쓰는가 | 잘못된 destination으로 message를 보낸다 |
nonce | 같은 message가 한 번만 사용되는가 | 중복 처리 또는 replay 의심 상태가 생긴다 |
mintRecipient | EVM/non-EVM 주소를 올바른 bytes 형식으로 변환했는가 | destination mint가 엉뚱한 주소로 간다 |
minFinalityThreshold | Fast와 Standard 중 어떤 risk/latency를 선택했는가 | 너무 이른 attestation 또는 불필요한 지연이 생긴다 |
maxFee / executed fee | 사용자가 허용한 fee 범위 안인가 | 사용자에게 표시한 수령액과 실제 수령액이 달라진다 |
expirationBlock | 만료 전 receiveMessage가 가능한가 | burn은 되었지만 destination 처리에 재서명이 필요할 수 있다 |
hookData | hook 실행 실패를 core mint 실패와 분리했는가 | destination action 실패가 결제 완료 판단을 흐린다 |
finality threshold는 제품 정책이다. 빠른 결제를 원하면 confirmed 수준의 Fast Transfer를 검토할 수 있지만, 재정산이나 고액 treasury 이동에는 finalized 수준의 Standard Transfer가 더 적합할 수 있다. 이 선택은 문서에 남겨야 한다.
4. 사용자 상태는 내부 상태보다 적어야 한다
내부 상태를 그대로 노출하면 사용자는 무엇을 기다리는지 알 수 없다. 반대로 "전송 중" 하나로 뭉개면 support와 reconciliation이 불가능해진다.
| 내부 상태 | 사용자 표시 | 운영자가 보는 증거 |
|---|---|---|
SourceBurnPending | source chain에서 결제를 확인 중입니다 | source tx hash, confirmations |
AttestationPending | cross-chain 확인을 기다리는 중입니다 | CCTP message, /v2/messages status |
DestinationMintPending | destination chain 수령을 처리 중입니다 | receiveMessage tx, gas/nonce, relayer status |
Completed | destination chain에서 USDC 수령이 완료되었습니다 | mint event, ledger row, merchant settlement |
Delayed | 네트워크 지연으로 확인이 필요합니다 | SLA 초과, provider status, retry count |
ManualReview | 운영팀이 수동 확인 중입니다 | mismatch reason, assigned owner |
결제 시스템에서는 사용자가 돈을 잃지 않았는지, merchant가 상품을 제공해도 되는지, refund가 가능한지를 상태별로 판단해야 한다. 그래서 CCTP 상태머신은 단순 progress bar가 아니라 정산 정책이다.
코드로 확인하기
위 신뢰 모델을 코드와 운영 규칙으로 확인한다. 메시지 상태, 최종성, 재시도, 관측 지점이 어디서 분리되는지 보는 것이 목적이다.
컨트랙트CCTP TokenMessenger 인터페이스 — native burn/mint 진입점
일반 wrapped bridge와 달리 CCTP는 source에서 native USDC를 소각하고, destination에서 native USDC를 새로 발행한다. 사용자 측에서 직접 호출하는 함수는
depositForBurn하나다.
interface ITokenMessengerV2 { function depositForBurn( uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, // 32바이트 패딩된 EVM 주소 또는 SVM pubkey address burnToken, bytes32 destinationCaller, uint256 maxFee, // V2 fast transfer 가 사용 uint32 minFinalityThreshold // standard=2000, fast=1000 ) external returns (uint64 nonce);}interface IMessageTransmitterV2 { function receiveMessage(bytes calldata message, bytes calldata attestation) external returns (bool);}백엔드Bridge 분류 가드 — UI 토큰 표기를 자동으로 분리
사용자에게 "USDC"만 보여주면 wrapped USDC.e 가 native 처럼 인식될 수 있다. 토큰 주소를 source 모델 분류와 함께 저장하고, UI는 그 모델을 그대로 노출한다.
type BridgeModel = "native-burn-mint" | "lock-mint" | "liquidity-network" | "atomic-swap";type TokenSourceTag = { chainId: number; tokenAddress: `0x${string}`; displaySymbol: string; // "USDC" — 사용자에게 보일 문자열 underlyingSymbol: string; // "USDC" sourceBridgeModel: BridgeModel; issuer: "circle" | "wormhole" | "stargate" | "across" | "other"; warningCopy?: string;};export const TOKEN_SOURCES: TokenSourceTag[] = [ { chainId: 8453, tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", displaySymbol: "USDC", underlyingSymbol: "USDC", sourceBridgeModel: "native-burn-mint", issuer: "circle" }, { chainId: 8453, tokenAddress: "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA", displaySymbol: "USDbC (bridged)", // ← native가 아니라는 점이 UI에 박힌다 underlyingSymbol: "USDC", sourceBridgeModel: "lock-mint", issuer: "other", warningCopy: "bridged USDC — redemption 경로가 native와 다릅니다" }];운영CCTP V2 transfer state — Delayed/ManualReview 라우팅
CCTP attestation API 응답을 직접 transfer 상태로 매핑하지 말고, SLA 초과 여부 + 재시도 횟수와 함께 internal status 로 변환한다.
type AttestationApiStatus = "pending_confirmations" | "complete" | "failed";type CctpTransferStatus = | "SourceBurnPending" | "AttestationPending" | "DestinationMintPending" | "Completed" | "Delayed" | "ManualReview" | "Failed";const SLA_MINUTES_BY_THRESHOLD: Record<"fast" | "standard", number> = { fast: 3, standard: 30};export function mapToInternalStatus(args: { apiStatus: AttestationApiStatus; burnedAt: Date; destinationMinted: boolean; finality: "fast" | "standard"; retryCount: number;}): CctpTransferStatus { if (args.destinationMinted) return "Completed"; if (args.apiStatus === "failed") return "Failed"; if (args.apiStatus === "complete") return "DestinationMintPending"; const minutes = (Date.now() - args.burnedAt.getTime()) / 60_000; const sla = SLA_MINUTES_BY_THRESHOLD[args.finality]; if (minutes > sla * 4) return "ManualReview"; if (minutes > sla) return "Delayed"; return "AttestationPending";}강의 포인트
| 관점 | 수업 중 확인할 질문 | 산출물 |
|---|---|---|
| 자산 | destination token이 native인지 wrapped인지 어떻게 표시하는가 | token display policy |
| 신뢰 | issuer, bridge, solver, attestation service 중 누구를 믿는가 | trust actor map |
| finality | Fast와 Standard transfer 중 어떤 기준을 쓰는가 | finality/fee decision table |
| 복구 | burn 후 mint 전 지연이 발생하면 누가 무엇을 확인하는가 | delayed transfer runbook |
| migration | V1 legacy integration이 남아 있는가 | CCTP V2 release gate |
실무 예시
백엔드[OPS] checkout에서 CCTP와 bridge를 비교하기
| 설계 질문 | CCTP burn-and-mint | Lock-and-mint bridge | Liquidity bridge |
|---|---|---|---|
| 사용자가 받는 자산 | native USDC | wrapped USDC 가능 | route에 따라 native 또는 wrapped |
| "완료" 판단 | destination mint + ledger settlement | wrapped mint + redeemability 확인 | solver 지급 + route settlement |
| 주요 장애 | attestation 지연, destination receive 실패 | bridge exploit, lock contract pause | solver 미지급, liquidity 부족 |
| 사용자 표기 | USDC with CCTP transfer status | bridged USDC 또는 wrapped 표기 필요 | route provider와 수수료 표시 필요 |
| 환불 | destination mint 전후 정책 분리 | bridge redemption 경로 필요 | solver/LP settlement 상태 확인 |
이 표를 실제 제품 요구사항으로 바꾸면 "USDC 지원"이라는 문구가 세분화된다. 예를 들어 Native USDC via CCTP, Bridged USDC, USDC via liquidity route를 같은 checkout option으로 표시하면 안 된다.
CCTP V2 migration checklist
Circle의 migration 문서는 CCTP V1이 legacy로 전환되고 V2의 contract, ABI, API, fee, finality 항목이 바뀌었다고 설명한다. 2026년 5월 14일 확인 기준으로 V1 phase-out은 2026년 7월부터 10개월에 걸쳐 진행될 예정이라고 안내되어 있다. release gate에는 다음 항목이 필요하다.
| 항목 | 확인 내용 |
|---|---|
| contract address | TokenMessengerV2, MessageTransmitterV2, TokenMinterV2 주소를 환경별로 갱신 |
| ABI/function | depositForBurn 추가 파라미터와 hook 사용 여부 확인 |
| API | legacy attestation polling 대신 /v2/messages/{sourceDomainId} 흐름 사용 |
| finality | Fast는 1000, Standard는 2000 기준으로 정책화 |
| fee | maxFee, fee quote, 사용자 표시 금액 검증 |
| domain support | source/destination chain이 V2에서 지원되는지 확인 |
| monitoring | allowance, fee, stuck attestation, expired burn alert 추가 |
흔한 오해와 실패 시나리오
| 오해 | 실제 기준 |
|---|---|
| CCTP를 쓰면 bridge risk가 사라진다 | wrapped asset risk는 줄지만 attestation, finality, supported domain, relayer risk는 남는다 |
| USDC면 모두 같은 회계 처리를 해도 된다 | native, bridged, liquidity-routed 자산을 분리해 표시하고 정산해야 한다 |
| source burn이 성공하면 결제가 완료된다 | destination mint와 merchant settlement까지 닫혀야 완료다 |
| Fast Transfer는 항상 더 좋다 | 금액, chain, finality 요구, fee, allowance에 따라 Standard가 맞을 수 있다 |
| hook이 있으면 destination action까지 protocol이 책임진다 | CCTP core는 message와 mint 경계를 제공하고 hook 실행 책임은 integrator에게 남는다 |
실습 과제
- 운영CCTP와 bridge risk matrix 작성: lock-and-mint bridge, liquidity bridge, CCTP burn-and-mint를 asset model, trust actor, finality, fee, recovery, user display 기준으로 비교한다.
- 백엔드CCTP checkout 상태머신 설계: source burn, attestation, destination receiveMessage, mint, delayed/manual review를 포함한 checkout 상태머신과 사용자 표시 문구를 작성한다.
- 운영CCTP V2 migration release gate 만들기: V1 legacy integration을 V2로 전환한다고 가정하고 contract address, ABI,
/v2/messages, finalityThreshold, maxFee, supported domain 확인 항목을 release checklist로 만든다.
완료 기준
- CCTP, lock-and-mint bridge, liquidity bridge의 trust actor와 failure domain을 구분했다.
- native USDC, bridged USDC, liquidity-routed USDC의 사용자 표기 정책을 정했다.
- source burn부터 destination mint까지의 상태머신과 지연 상태 UX를 작성했다.
- CCTP V2 migration에 필요한 contract/API/finality/fee/support 확인 항목을 release gate에 넣었다.
근거 자료
- 크로스체인 L2 학습맵: 03-크로스체인-L2/00-크로스체인-L2-학습맵.md
- CCTP vs 브릿지: 03-크로스체인-L2/01-CCTP-vs-브릿지.md
- Circle CCTP Documentation: https://developers.circle.com/cctp
- Circle CCTP Technical Guide: https://developers.circle.com/cctp/references/technical-guide
- Circle CCTP V1 to V2 Migration Guide: https://developers.circle.com/cctp/migration-from-v1-to-v2
- Circle CCTP Product Page: https://www.circle.com/cross-chain-transfer-protocol