결제 동작 원리 및 핵심 아키텍처
SoloPay의 전체 결제 파이프라인과 가스리스 아키텍처를 설명합니다.
2.1 전체 결제 파이프라인
모든 SoloPay 결제는 아래 5단계로 처리됩니다.
[1] SoloPay 위젯
POST /payments 호출 → paymentId, 컨트랙트 주소 수신
↓
[2] 사용자 지갑 (MetaMask)
EIP-712 서명 생성 (트랜잭션 없음, 가스비 없음)
↓
[3] SoloPay 릴레이어
서명 수신 → 서명 검증 → 온체인 TX 전송
↓
[4] 블록체인 (PaymentGateway 컨트랙트)
pay() 실행 → 토큰 이동 & 이벤트 발생
↓
[5] SoloPay → 가맹점 서버
PAID / INVALID Webhook 이벤트 전송결제가 PAID로 확인되면 자금이 가맹점 지갑으로 직접 이체된 것입니다. 별도의 확정(finalize)이나 취소(cancel) 단계가 필요하지 않습니다.
단계별 설명
| 단계 | 주체 | 작업 |
|---|---|---|
| 1. 결제 요청 | SoloPay 위젯 | POST /payments → paymentId, 컨트랙트 주소 수신 |
| 2. 서명 | 사용자 지갑 | EIP-712 서명만 (TX 없음, 가스 없음) |
| 3. 릴레이어 | SoloPay 서버 | 서명 검증 → 온체인 TX 전송 |
| 4. 컨트랙트 | 블록체인 | pay() → 토큰이 가맹점으로 이체 |
| 5. Webhook | SoloPay 서버 | 가맹점 Webhook URL로 이벤트 전송 (아래 5a–5b 참고) |
5a. PAID | SoloPay 서버 | 결제 온체인 확인 완료. 주문 완료 처리 |
5b. INVALID | SoloPay 서버 | 온체인 결제 감지되었으나 검증 실패 |
다음에 일어나는 일:
- 성공:
PAID수신 → 주문 완료 (자금이 가맹점 지갑으로 이체됨). - 환불 (출시 예정):
PAID이후 POST /payments/refunds로 환불 요청 →REFUND_SUBMITTED→ 확인 후REFUNDED.
2.2 가스리스(Gasless) 및 릴레이어(Relayer) 시스템
일반 결제 vs 가스리스 결제
일반 결제 (Direct Pay) 가스리스 결제 (Gasless Pay)
──────────────────── ────────────────────────────
사용자 사용자
│ │
│ ① 트랜잭션 직접 전송 │ ① 서명(Signature) 데이터만 생성
│ (가스비: 사용자 부담) │ (트랜잭션 없음, 가스비 없음)
▼ ▼
PaymentGateway 컨트랙트 SoloPay 위젯 → SoloPay 릴레이어
│
│ ② 서명 검증 후 TX 전송
│ (가스비: 릴레이어 부담)
▼
PaymentGateway 컨트랙트릴레이어의 역할
릴레이어(Relayer)는 SoloPay가 운영하는 서버입니다. 가스리스 결제의 핵심 중계자 역할을 합니다.
- 서명 수신: SoloPay 위젯으로부터 사용자의 EIP-712 서명 데이터를 받습니다.
- 서명 검증: EIP-712 서명이 올바른 포맷인지, 사용자 주소와 일치하는지 검증합니다.
- 가스비 대납: 릴레이어 지갑에서 가스비를 지불하고
ERC2771Forwarder컨트랙트를 통해PaymentGateway에 트랜잭션을 전송합니다. - 상태 모니터링: 트랜잭션의 온체인 상태를 추적합니다 (
QUEUED→SUBMITTED→CONFIRMED/FAILED).
ERC-2771 메타트랜잭션
SoloPay는 OpenZeppelin의 ERC2771Forwarder 표준을 사용합니다. 이를 통해 릴레이어가 트랜잭션을 대신 전송하더라도, 컨트랙트 측에서는 원래 사용자(서명자)를 정확히 식별할 수 있습니다.
2.3 토큰별 가스리스 동작 방식 (Permit 지원 여부)
토큰의 Permit(EIP-2612) 지원 여부에 따라 가스리스 수준이 달라집니다.
A. 완벽한 가스리스 — Permit 지원 토큰 (예: USDC)
EIP-2612 Permit을 지원하는 토큰은 최초 결제 시에도 Approve 트랜잭션 없이 서명(Signature) 하나만으로 모든 과정이 처리됩니다.
최초 결제 포함 모든 결제:
사용자
│
│ ① EIP-2612 Permit 서명 (가스비 없음)
│ ② EIP-712 ForwardRequest 서명 (가스비 없음)
▼
릴레이어 → 컨트랙트 실행 (가스비: 릴레이어 부담)
→ 사용자 가스비 지출: 0원SoloPay 결제 위젯을 사용하면 Permit 지원 여부를 자동 감지하여 처리합니다.
B. 부분 가스리스 — Permit 미지원 토큰 (일반 ERC-20)
일반 ERC-20 토큰(Permit 미지원)은 allowance 방식의 사전 승인이 필요합니다.
최초 1회 (사용자 가스비 발생)
사용자
│
│ ① approve(gatewayAddress, 무한 승인) 트랜잭션 전송
│ (가스비: 사용자 부담 — 1회만 발생)
▼
PaymentGateway 컨트랙트에 allowance 등록이후 모든 결제 (완전 가스리스)
사용자
│
│ ① EIP-712 ForwardRequest 서명 (가스비 없음)
▼
릴레이어 → 컨트랙트 실행 (가스비: 릴레이어 부담)
→ 두 번째 결제부터는 가스비 없음무한 승인 (Infinite Approve) 권장
최초 1회 Approve 시 최대값(BigInt(2**256 - 1))으로 승인해두면, 이후 수백 번의 결제도 추가 Approve 없이 진행됩니다.
Permit 지원 여부 비교표
| 항목 | Permit 지원 토큰 (USDC 등) | 일반 ERC-20 |
|---|---|---|
| 최초 결제 가스비 | 없음 ✅ | 있음 (1회) ⚠️ |
| 이후 결제 가스비 | 없음 ✅ | 없음 ✅ |
| 구현 복잡도 | 낮음 | 낮음 (Approve 1회 추가) |
2.4 트랜잭션 상태 사이클
결제(Payment) 상태
CREATED ──► PAID
PAID ──► REFUND_SUBMITTED ──► REFUNDED (출시 예정)
CREATED ──► INVALID
CREATED ──► EXPIRED
CREATED ──► FAILED| 상태 | 설명 |
|---|---|
CREATED | 결제 생성됨, 온체인 트랜잭션 대기 |
PAID | 결제 온체인 확인 완료, 자금이 가맹점으로 이체됨 (최종 성공) |
REFUND_SUBMITTED | 환불 트랜잭션 제출됨 (출시 예정) |
REFUNDED | 환불 완료 (출시 예정) |
INVALID | 온체인 결제 감지되었으나 검증 실패 |
EXPIRED | 결제 만료 |
FAILED | 트랜잭션 실패 |
Relay 상태 (가스리스 전용)
QUEUED ──────▶ SUBMITTED ──────▶ CONFIRMED
│
▼
FAILED| 상태 | 설명 |
|---|---|
QUEUED | 릴레이어가 서명 데이터 수신, TX 전송 준비 중 |
SUBMITTED | 릴레이어가 블록체인에 TX 전송 완료 |
CONFIRMED | TX가 블록에 포함되어 확정 |
FAILED | TX 실패 (가스 부족, 컨트랙트 revert 등) |
결제 상태 vs Relay 상태
- 결제 상태는 온체인 상태(PAID, INVALID, EXPIRED 등)를 반영합니다.
- Relay 상태는 릴레이어의 TX 제출 과정(QUEUED → SUBMITTED → CONFIRMED/FAILED)을 반영합니다.
- 결제 TX가 확정되면 결제 상태가 PAID가 되며, 자금이 가맹점 지갑으로 직접 이체됩니다.
다음 단계
- 환불 — 완료된 결제에 대한 환불 요청
- 스마트 컨트랙트 정보 — 컨트랙트 주소 및 ABI
- 클라이언트 사이드 연동 — 단계별 구현 가이드