Payment Providers
Overview
Wafra implements a composite payment provider system that supports multiple fiat-to-crypto payment processors through a unified abstraction layer. This architecture enables optimal routing, quote comparison, and seamless provider switching while maintaining a consistent user experience.
Current Provider Ecosystem
Active Providers
| Provider | Status | Integration Type | KYC Method | Onramp | Offramp | Global Support |
|---|---|---|---|---|---|---|
| Onramp | ✅ Live | Direct API | Traditional | ✅ Yes | ✅ Yes | ✅ Global |
| DTR | ✅ Live | Whitelabel | SIWE + Sumsub | ✅ Yes | 🔄 Limited | 🔄 Limited |
Provider Selection Logic
Current Implementation:
- Quote-Driven: Best rates determine provider selection
- Capability-Based: Provider features influence routing (onramp vs offramp)
- Regional Availability: Geographic restrictions affect provider choice
- KYC Status: User’s verification status impacts provider selection
Composite Payment Architecture
Service Abstraction
Provider Interface:
abstract class BasePaymentService {
abstract getQuote(params: QuoteParams): Promise<Quote | null>;
abstract createOrder(
user: User,
params: TransactionParams
): Promise<TransactionResult>;
abstract getKycStatus(user: User): Promise<KycResponse>;
abstract getUserLimit(user: User): Promise<UserLimit>;
abstract handleWebhook(payload: any, headers: any): Promise<boolean>;
}
// Current implementations
class OnrampService extends BasePaymentService {
/* ... */
}
class DtrService extends BasePaymentService {
/* ... */
}Composite Service:
export class PaymentService {
private providers: Map<string, BasePaymentService> = new Map();
constructor(providers: BasePaymentService[]) {
providers.forEach((provider) => {
this.providers.set(provider.id, provider);
});
}
async getBestQuote(params: QuoteParams): Promise<Quote[]> {
// Compare quotes from all available providers
const quotes = await Promise.allSettled(
Array.from(this.providers.values()).map((provider) =>
provider.getQuote(params)
)
);
return quotes
.filter((result) => result.status === "fulfilled" && result.value)
.map((result) => result.value)
.sort((a, b) => b.cryptoAmount - a.cryptoAmount); // Best rate first
}
getProvider(providerId: string): BasePaymentService | undefined {
return this.providers.get(providerId);
}
}Quote Comparison System
Multi-Provider Quotes:
interface Quote {
provider: string;
fiatAmount: number;
cryptoAmount: number;
rate: string;
fees: {
provider: number;
network: number;
total: number;
};
estimatedTime: string;
paymentMethods: PaymentMethod[];
quoteId?: string;
}
// Real-time quote comparison
const quotes = await paymentService.getBestQuote({
fiatAmount: 1000,
fiatCurrency: "USD",
cryptoCurrency: "USDC",
countryCode: "US",
paymentMethod: "bank_transfer",
});Onramp Provider Integration
Service Architecture
Onramp Service Structure:
export class OnrampService extends BasePaymentService {
private apiClient: OnrampApiClient;
private paymentMethods: OnrampPaymentMethods;
private orderManager: OnrampOrderManager;
private userManager: OnrampUserManager;
private limitsService: OnrampLimitsService;
private quoteService: OnrampQuoteService;
private webhookService: OnrampWebhookService;
// Service capabilities
supportsOnramp: true;
supportsOfframp: true;
globalSupport: true;
}Onramp Features
Key Capabilities:
- Global Coverage: Supports 100+ countries
- Multiple Payment Methods: Bank transfers, cards, e-wallets
- Bidirectional: Both onramp (fiat→crypto) and offramp (crypto→fiat)
- Traditional KYC: Standard identity verification process
- Widget Integration: Embedded payment interface
Payment Method Support:
interface OnrampPaymentMethod {
type: "instant" | "bank_transfer";
currency: string;
country: string;
minAmount: number;
maxAmount: number;
feePercentage: number; // 1% for instant, 0.5% for bank
estimatedTime: string;
}Onramp Process
-
Step 1: Real-time exchange rates with fees
-
Step 2: Create or retrieve Onramp customer account
-
Step 3: Traditional identity verification
-
Step 4: Check user’s monthly transaction limits
-
Step 5: Submit transaction to Onramp API
-
Step 6: User completes payment via Onramp interface
-
Step 7: USDC delivered to user’s Safe wallet
Offramp Process
-
Step 1: Configure bank account or e-wallet details
-
Step 2: Crypto-to-fiat conversion rates
-
Step 3: Initiate withdrawal from user’s wallet
-
Step 4: Onramp handles fiat settlement
-
Step 5: USD delivered to user’s bank account
DTR Provider Integration
Service Architecture
DTR Service Structure:
export class DtrService extends BasePaymentService {
private apiClient: DtrApiClient;
private userManager: DtrUserManager;
private quoteService: DtrQuoteService;
private authService: DtrAuthService; // SIWE integration
private webhookService: DTRWebhookService;
// Service capabilities
supportsOnramp: true;
supportsOfframp: false; // Limited offramp support
globalSupport: false; // Limited regional support
}SIWE Authentication
Sign-In With Ethereum Integration:
// SIWE challenge generation
async generateSiweChallenge(user: User, userAddress: string): Promise<SiweChallenge> {
const challenge = await this.authService.generateChallenge({
address: userAddress,
domain: 'wafra.app',
statement: 'Sign in to Wafra for secure payment processing',
uri: 'https://wafra.app',
version: '1',
chainId: 8453, // Base network
});
return challenge;
}
// Signature verification and authentication
async verifySiweAndAuthenticate(
user: User,
signatureData: SiweSignatureRequest
): Promise<AuthenticationResult> {
const verification = await this.authService.verifySignature(signatureData);
if (verification.success) {
await this.userManager.createOrUpdateDtrUser(user, verification.address);
return { authenticated: true, dtrUserId: verification.dtrUserId };
}
return { authenticated: false, error: verification.error };
}Enhanced KYC with Sumsub
DTR KYC Process:
-
Step 1: User signs message with wallet
-
Step 2: Account created with verified wallet address
-
Step 3: Enhanced identity verification initiated
-
Step 4: Professional KYC/AML provider handles verification
-
Step 5: ID, selfie, and additional compliance documents
-
Step 6: AML, sanctions, and PEP screening
-
Step 7: Banking services activated upon approval
Sumsub Integration:
async getSumsubToken(user: User): Promise<SumsubTokenResponse> {
const dtrUser = await this.userManager.getDtrUser(user);
const tokenResponse = await this.apiClient.makeAuthenticatedRequest(
'POST',
'/kyc/sumsub/token',
{
userId: dtrUser.dtrUserId,
applicantId: dtrUser.applicantId,
}
);
return {
token: tokenResponse.access_token,
applicantId: tokenResponse.applicant_id,
expiresAt: tokenResponse.expires_at,
};
}Payment Method Management
Dynamic Payment Methods
Payment Method Structure:
interface PaymentMethod {
id: number;
type: "bank_transfer" | "instant" | "card" | "ewallet";
name: string;
currency: string;
country: string;
provider: "onramp" | "dtr";
minAmount: number;
maxAmount: number;
feeFixed: number;
feePercentage: number;
isPayInAllowed: boolean; // Onramp support
isPayOutAllowed: boolean; // Offramp support
isActive: boolean;
details: {
// Provider-specific metadata
fiatType?: number; // Onramp fiat type ID
methodName?: string; // Onramp method identifier
bankCode?: string; // DTR bank code
routingNumber?: string; // DTR routing number
};
}Provider-Specific Methods
Onramp Payment Methods:
- Bank Transfers: ACH, SEPA, domestic transfers
- Instant Transfers: Real-time payment networks
- Cards: Credit and debit card support
- E-Wallets: PayPal, digital wallet integration
DTR Payment Methods:
- Virtual Bank Accounts: Dedicated account numbers
- SWIFT Transfers: International wire transfers
- Domestic Banking: Country-specific banking rails
Transaction Lifecycle Management
Order Management
Order Status Flow:
Order Tracking:
interface Order {
id: string;
userId: string;
provider: "onramp" | "dtr";
amount: number;
usdcAmount: bigint;
currency: string;
status: OrderStatus;
paymentMethod: string;
depositAddress: string;
foreignOrderId?: string; // Provider's transaction ID
transactionType: "onramp" | "offramp";
createdAt: Date;
updatedAt: Date;
}Real-Time Status Updates
Webhook Integration:
// Unified webhook handler
async function handleProviderWebhook(
provider: string,
payload: any,
headers: any
): Promise<WebhookResponse> {
const paymentProvider = paymentService.getProvider(provider);
if (!paymentProvider) {
throw new Error(`Unknown provider: ${provider}`);
}
// Provider handles webhook verification and processing
const result = await paymentProvider.handleWebhook(payload, headers);
if (result.success) {
// Update order status in database
await updateOrderStatus(result.orderId, result.status);
// Notify user via Socket.IO
await notifyUserOrderUpdate(result.userId, result);
}
return result;
}Error Handling & Recovery
Provider Failure Handling
Automatic Fallback:
async function createOrderWithFallback(
user: User,
params: TransactionParams
): Promise<TransactionResult> {
const providers = ["onramp", "dtr"]; // Priority order
for (const providerId of providers) {
try {
const provider = paymentService.getProvider(providerId);
if (!provider) continue;
const result = await provider.createOrder(user, params);
if (result.status !== "error") {
return result;
}
} catch (error) {
logger.warn(`Provider ${providerId} failed, trying next`, { error });
continue;
}
}
throw new Error("All payment providers failed");
}Error Categories
Common Error Types:
enum PaymentError {
INSUFFICIENT_FUNDS = "insufficient_funds",
KYC_REQUIRED = "kyc_required",
LIMIT_EXCEEDED = "limit_exceeded",
UNSUPPORTED_REGION = "unsupported_region",
PROVIDER_UNAVAILABLE = "provider_unavailable",
INVALID_PAYMENT_METHOD = "invalid_payment_method",
RATE_EXPIRED = "rate_expired",
}Monitoring & Analytics
Provider Performance Metrics
Current Tracking:
- Success Rates: Transaction completion by provider
- Processing Times: Average time from creation to completion
- Quote Accuracy: Rate comparison between quote and execution
- User Preference: Provider selection patterns
- Regional Performance: Success rates by geography
Cost Analysis
Fee Comparison:
interface ProviderCostAnalysis {
provider: string;
averageFeePercentage: number;
averageProcessingTime: number;
successRate: number;
userSatisfactionScore: number;
regionalAvailability: string[];
}Future Enhancements
Additional Providers
Planned Integrations:
- MoonPay: Additional global coverage
- Ramp: European market focus
- Banxa: APAC region specialization
- Transak: Comprehensive global solution
Advanced Features
Roadmap Items:
- Smart Routing: AI-driven provider selection
- Dynamic Pricing: Real-time fee optimization
- Batch Processing: Grouped transaction efficiency
- Cross-Border Optimization: Multi-currency support
- Regulatory Adaptation: Jurisdiction-specific compliance
This payment provider architecture ensures reliable, cost-effective fiat-to-crypto conversion while maintaining regulatory compliance and optimal user experience.