본문으로 건너뛰기

결제 플로우

결제 플로우를 이해하면 더 나은 결제 경험을 구축하고 예외 상황을 처리할 수 있습니다.

결제 플로우 다이어그램

단계별 설명

1. 결제 시작

사용자가 "Pay" 버튼을 클릭하거나 pay()를 호출합니다:

const { pay } = useVolrPay();

pay({
amount: '10.00',
currency: 'USDC',
onSuccess: () => {},
onError: () => {},
});

2. 인증 확인

PaymentModal은 사용자가 인증되었는지 확인합니다:

  • 인증되지 않음: 자동으로 SigninModal 표시
  • 인증됨: 결제 플로우 계속 진행

3. 지갑 설정

사용자가 지갑이 없는 경우:

  • Volr 지갑 생성: 사용자가 패스키를 등록하고 지갑 생성
  • 외부 지갑 연결: 사용자가 MetaMask 또는 기타 지갑 연결

4. 토큰 선택

사용자가 결제에 사용할 토큰을 선택합니다:

  • 사용 가능한 토큰은 Dashboard에서 구성됨
  • 토큰 잔액 표시
  • 사용자가 토큰 전환 가능

5. 잔액 확인

PaymentModal은 사용자가 충분한 잔액을 가지고 있는지 확인합니다:

// Insufficient balance
if (balance < amount) {
// Show deposit option
// Opens DepositModal
}

// Sufficient balance
if (balance >= amount) {
// Continue to payment confirmation
}

6. 결제 확인

사용자가 결제 세부 정보를 검토합니다:

  • 금액
  • 토큰
  • 아이템 세부 정보 (제공된 경우)
  • 가스 수수료 (해당되는 경우)

7. 트랜잭션 처리

결제가 처리됩니다:

  1. 결제 의도 생성: 백엔드가 결제 기록 생성
  2. 트랜잭션 서명: 사용자가 지갑으로 트랜잭션 서명
  3. 트랜잭션 제출: 트랜잭션이 블록체인에 제출됨
  4. 확인 대기: 트랜잭션 확인 대기

8. 결과

결제가 완료됩니다:

  • 성공: 성공 메시지 표시, onSuccess 호출
  • 오류: 오류 메시지 표시, onError 호출

상태 관리

PaymentModal은 내부적으로 다음 상태를 관리합니다:

type PaymentStep = 
| 'info' // Payment info and token selection
| 'wallet' // Wallet choice or setup
| 'processing' // Transaction processing
| 'result'; // Success or error

type WalletStep =
| 'choice' // Choose wallet type
| 'create-account' // Create Volr wallet
| 'external-wallet'; // Connect external wallet

Handling Edge Cases

Insufficient Balance

When user has insufficient balance:

// PaymentModal automatically shows deposit option
// User can:
// 1. Deposit funds via DepositModal
// 2. Cancel payment
// 3. Switch to different token (if available)

User Cancels

Handle user cancellation:

pay({
amount: '10.00',
currency: 'USDC',
onCancel: () => {
console.log('User cancelled payment');
// No action needed, modal closes automatically
},
});

Network Errors

Handle network errors:

pay({
amount: '10.00',
currency: 'USDC',
onError: (error) => {
if (error.message.includes('network')) {
alert('Network error. Please check your connection.');
}
},
});

Transaction Timeout

If transaction takes too long:

// PaymentModal shows processing state
// User can:
// 1. Wait for confirmation
// 2. Check transaction on block explorer (via transaction hash)
// 3. Retry if transaction fails

Best Practices

1. Show Loading States

Always show loading states during payment:

const [isPaying, setIsPaying] = useState(false);

const handlePay = () => {
setIsPaying(true);
pay({
amount: '10.00',
currency: 'USDC',
onSuccess: () => {
setIsPaying(false);
// Handle success
},
onError: () => {
setIsPaying(false);
// Handle error
},
});
};

return (
<button onClick={handlePay} disabled={isPaying}>
{isPaying ? 'Processing...' : 'Pay'}
</button>
);

2. Provide Clear Feedback

Give users clear feedback at each step:

pay({
amount: '10.00',
currency: 'USDC',
onSuccess: () => {
// Show success message
toast.success('Payment successful!');
// Redirect or update UI
},
onError: (error) => {
// Show user-friendly error
toast.error('Payment failed. Please try again.');
},
});

3. Handle Authentication

Ensure user is authenticated before payment:

import { useVolr } from '@volr/react';

function PaymentButton() {
const { isLoggedIn } = useVolr();
const { pay } = useVolrPay();

if (!isLoggedIn) {
return <div>Please sign in to make a payment</div>;
}

return <button onClick={() => pay({...})}>Pay</button>;
}

Next Steps