💰 Payment Processing Example
What You'll Learn
Complete payment processing implementation using BRDZ SDK's MCP (AI Commerce) module, traditional payments, cross-chain transactions, and order management systems.
Prerequisites
- API Key configured
- Authentication setup
- User authenticated with valid JWT token
- Basic understanding of e-commerce flows
Overview
BRDZ SDK provides multiple payment processing approaches:
- MCP (AI Commerce): AI-powered shopping and payments
- Traditional Payments: Direct wallet-to-wallet transfers
- Cross-chain Payments: Multi-blockchain transactions
- Order Management: Complete e-commerce integration
MCP (AI Commerce) Payment Flow
Basic AI-Powered Shopping
import brdzSDK from 'anantla_sdk';
class MCPPaymentProcessor {
constructor(userId) {
this.userId = userId;
this.mcp = brdzSDK.mcp;
this.currentOrder = null;
}
// Step 1: AI Intent Detection
async detectPurchaseIntent(userPrompt) {
try {
console.log('🤖 Analyzing purchase intent...');
const result = await this.mcp.step1_detectIntent({
prompt: userPrompt
});
return {
success: true,
intent_detected: result.intent_detected,
detected_url: result.detected_url,
confidence: result.confidence,
extracted_info: result.extracted_info
};
} catch (error) {
throw new Error(`Intent detection failed: ${error.message}`);
}
}
// Step 2: Product Information Extraction
async extractProductInfo(productUrl) {
try {
console.log('📦 Extracting product information...');
const result = await this.mcp.step2_parseProduct({
url: productUrl
});
return {
success: true,
product: result.product,
images: result.product?.images,
specifications: result.product?.specifications,
availability: result.product?.availability
};
} catch (error) {
throw new Error(`Product extraction failed: ${error.message}`);
}
}
// Step 3: Price Confirmation and Currency Conversion
async confirmProductPricing(productData) {
try {
console.log('💱 Converting price to USDC...');
const result = await this.mcp.step3a_productConfirmation({
product: productData
});
return {
success: true,
product: result.product,
pricing: result.pricing,
usdc_price: result.pricing?.usdc_amount,
exchange_rate: result.pricing?.exchange_rate,
fees: result.pricing?.fees
};
} catch (error) {
throw new Error(`Price confirmation failed: ${error.message}`);
}
}
// Step 4: Create Order
async createOrder(productData, pricingData, recipientInfo) {
try {
console.log('📋 Creating order...');
const orderData = {
product: productData,
pricing: pricingData,
recipient: {
name: recipientInfo.name,
phone: recipientInfo.phone,
address: recipientInfo.address,
notes: recipientInfo.notes || "Standard delivery"
}
};
const result = await this.mcp.createOrder(orderData);
this.currentOrder = result;
return {
success: true,
order_id: result.order_id,
total_amount: result.total_amount_usdc,
ready_for_payment: result.ready_for_payment,
balance_sufficient: result.balance_sufficient,
estimated_delivery: result.estimated_delivery
};
} catch (error) {
throw new Error(`Order creation failed: ${error.message}`);
}
}
// Step 5: Execute Payment
async executePayment(orderId, confirmation = "confirmed") {
try {
console.log('💳 Processing payment...');
const result = await this.mcp.executeOrder({
order_id: orderId,
confirmation: confirmation
});
return {
success: true,
transaction_hash: result.transaction_hash,
payment_status: result.payment_status,
order_status: result.order_status,
tracking_info: result.tracking_info,
receipt_email_sent: result.receipt_email_sent
};
} catch (error) {
throw new Error(`Payment execution failed: ${error.message}`);
}
}
// Complete Shopping Flow
async completeShoppingFlow(userPrompt, recipientInfo) {
try {
console.log('🛒 Starting complete shopping flow...');
// Step 1: Detect intent
const intentResult = await this.detectPurchaseIntent(userPrompt);
if (!intentResult.intent_detected) {
throw new Error('No purchase intent detected in your message');
}
// Step 2: Extract product info
const productResult = await this.extractProductInfo(intentResult.detected_url);
// Step 3: Confirm pricing
const pricingResult = await this.confirmProductPricing(productResult.product);
// Step 4: Create order
const orderResult = await this.createOrder(
pricingResult.product,
pricingResult.pricing,
recipientInfo
);
if (!orderResult.balance_sufficient) {
throw new Error(`Insufficient USDC balance. Required: ${orderResult.total_amount} USDC`);
}
// Step 5: Execute payment
const paymentResult = await this.executePayment(orderResult.order_id);
return {
success: true,
order_id: orderResult.order_id,
transaction_hash: paymentResult.transaction_hash,
product_name: pricingResult.product.name,
total_paid: orderResult.total_amount,
delivery_info: paymentResult.tracking_info,
steps_completed: {
intent_detection: true,
product_extraction: true,
price_confirmation: true,
order_creation: true,
payment_execution: true
}
};
} catch (error) {
throw new Error(`Shopping flow failed: ${error.message}`);
}
}
}
// Usage Example
const mcpProcessor = new MCPPaymentProcessor(123);
// Complete shopping example
const shoppingResult = await mcpProcessor.completeShoppingFlow(
"I want to buy wireless headphones from https://tokopedia.com/product/headphones-sony-wh1000xm4",
{
name: "John Doe",
phone: "+628123456789",
address: "Jl. Sudirman No. 123, Jakarta Selatan 12190, Indonesia",
notes: "Please call before delivery"
}
);
console.log('Shopping completed:', shoppingResult);
Multi-Chain MCP Payment Support
class MultiChainMCPProcessor extends MCPPaymentProcessor {
constructor(userId) {
super(userId);
}
// V2: Multi-Chain Support
async getChainOptions(productData, pricingData, recipientInfo) {
try {
console.log('⛓️ Getting available blockchain options...');
const result = await this.mcp.chainSelector({
product: productData,
pricing: pricingData,
recipient: recipientInfo
});
return {
available_chains: result.available_chains,
recommended_chain: result.recommended_chain,
gas_estimates: result.gas_estimates,
contract_addresses: result.contract_addresses
};
} catch (error) {
throw new Error(`Chain selection failed: ${error.message}`);
}
}
async createOrderV2(productData, pricingData, recipientInfo, selectedChain, walletAddress) {
try {
console.log(`📋 Creating V2 order on ${selectedChain}...`);
const result = await this.mcp.createOrderV2({
product: productData,
pricing: pricingData,
recipient: recipientInfo,
selected_chain: selectedChain,
wallet_address: walletAddress
});
return {
success: true,
order_id: result.order_id,
selected_chain: result.selected_chain,
contract_address: result.contract_address,
gas_estimate: result.gas_estimate,
total_with_gas: result.total_with_gas,
ready_for_payment: result.ready_for_payment
};
} catch (error) {
throw new Error(`V2 order creation failed: ${error.message}`);
}
}
async executeOrderV2(orderId, walletAddress) {
try {
console.log('💳 Processing V2 payment...');
const result = await this.mcp.executeOrderV2({
order_id: orderId,
confirmation: "confirmed",
wallet_address: walletAddress
});
return {
success: true,
transaction_hash: result.transaction_hash,
chain: result.chain,
gas_used: result.gas_used,
total_cost: result.total_cost,
order_status: result.order_status
};
} catch (error) {
throw new Error(`V2 payment execution failed: ${error.message}`);
}
}
// Complete Multi-Chain Shopping Flow
async completeMultiChainShopping(userPrompt, recipientInfo, preferredChain = null) {
try {
// Steps 1-3: Same as basic flow
const intentResult = await this.detectPurchaseIntent(userPrompt);
const productResult = await this.extractProductInfo(intentResult.detected_url);
const pricingResult = await this.confirmProductPricing(productResult.product);
// Step 4: Get chain options
const chainOptions = await this.getChainOptions(
pricingResult.product,
pricingResult.pricing,
recipientInfo
);
// Step 5: Select optimal chain
const selectedChain = preferredChain || chainOptions.recommended_chain;
console.log(`⛓️ Selected chain: ${selectedChain}`);
// Get user's wallet address for selected chain
const walletAddress = await this.getUserWalletForChain(selectedChain);
// Step 6: Create V2 order
const orderResult = await this.createOrderV2(
pricingResult.product,
pricingResult.pricing,
recipientInfo,
selectedChain,
walletAddress
);
// Step 7: Execute V2 payment
const paymentResult = await this.executeOrderV2(
orderResult.order_id,
walletAddress
);
return {
success: true,
order_id: orderResult.order_id,
transaction_hash: paymentResult.transaction_hash,
chain_used: paymentResult.chain,
gas_used: paymentResult.gas_used,
total_cost: paymentResult.total_cost,
product_name: pricingResult.product.name,
chain_options: chainOptions
};
} catch (error) {
throw new Error(`Multi-chain shopping failed: ${error.message}`);
}
}
async getUserWalletForChain(chainId) {
try {
const cryptoWallet = brdzSDK.cryptoWallet;
const wallets = await cryptoWallet.getUserWallets(this.userId);
// Find wallet with the required chain
for (const wallet of wallets) {
const addresses = await cryptoWallet.getWalletAddresses(wallet.bw_id);
const chainAddress = addresses.find(addr => addr.chain_id === chainId);
if (chainAddress) {
return chainAddress.address;
}
}
throw new Error(`No wallet found for chain: ${chainId}`);
} catch (error) {
throw new Error(`Wallet lookup failed: ${error.message}`);
}
}
}
React Payment Components
MCP Shopping Component
import React, { useState, useEffect } from 'react';
import { useSDK } from '../contexts/SDKContext';
interface ShoppingStep {
step: number;
title: string;
status: 'pending' | 'processing' | 'completed' | 'error';
data?: any;
error?: string;
}
interface RecipientInfo {
name: string;
phone: string;
address: string;
notes?: string;
}
const MCPShopping: React.FC = () => {
const { currentUser } = useSDK();
const [prompt, setPrompt] = useState('');
const [recipientInfo, setRecipientInfo] = useState<RecipientInfo>({
name: '',
phone: '',
address: '',
notes: ''
});
const [steps, setSteps] = useState<ShoppingStep[]>([
{ step: 1, title: 'Detect Purchase Intent', status: 'pending' },
{ step: 2, title: 'Extract Product Information', status: 'pending' },
{ step: 3, title: 'Confirm Pricing & Convert to USDC', status: 'pending' },
{ step: 4, title: 'Create Order', status: 'pending' },
{ step: 5, title: 'Execute Payment', status: 'pending' }
]);
const [currentStep, setCurrentStep] = useState(0);
const [processing, setProcessing] = useState(false);
const [completed, setCompleted] = useState(false);
const [finalResult, setFinalResult] = useState<any>(null);
const updateStep = (stepIndex: number, status: ShoppingStep['status'], data?: any, error?: string) => {
setSteps(prev => prev.map((step, index) =>
index === stepIndex
? { ...step, status, data, error }
: step
));
};
const startShopping = async () => {
if (!prompt.trim() || !recipientInfo.name || !recipientInfo.phone || !recipientInfo.address) {
alert('Please fill in all required fields');
return;
}
setProcessing(true);
setCurrentStep(0);
setCompleted(false);
try {
// Import MCP module
const brdzSDK = await import('anantla_sdk').then(sdk => sdk.default);
const mcp = brdzSDK.mcp;
// Step 1: Detect Intent
setCurrentStep(0);
updateStep(0, 'processing');
const intentResult = await mcp.step1_detectIntent({ prompt });
if (!intentResult.intent_detected) {
updateStep(0, 'error', null, 'No purchase intent detected');
return;
}
updateStep(0, 'completed', intentResult);
// Step 2: Extract Product
setCurrentStep(1);
updateStep(1, 'processing');
const productResult = await mcp.step2_parseProduct({
url: intentResult.detected_url
});
updateStep(1, 'completed', productResult);
// Step 3: Confirm Pricing
setCurrentStep(2);
updateStep(2, 'processing');
const pricingResult = await mcp.step3a_productConfirmation({
product: productResult.product
});
updateStep(2, 'completed', pricingResult);
// Step 4: Create Order
setCurrentStep(3);
updateStep(3, 'processing');
const orderResult = await mcp.createOrder({
product: pricingResult.product,
pricing: pricingResult.pricing,
recipient: recipientInfo
});
if (!orderResult.balance_sufficient) {
updateStep(3, 'error', orderResult, `Insufficient balance. Required: ${orderResult.total_amount_usdc} USDC`);
return;
}
updateStep(3, 'completed', orderResult);
// Step 5: Execute Payment
setCurrentStep(4);
updateStep(4, 'processing');
const paymentResult = await mcp.executeOrder({
order_id: orderResult.order_id,
confirmation: "confirmed"
});
updateStep(4, 'completed', paymentResult);
setFinalResult({
order_id: orderResult.order_id,
transaction_hash: paymentResult.transaction_hash,
product_name: pricingResult.product.name,
total_paid: orderResult.total_amount_usdc,
status: paymentResult.payment_status
});
setCompleted(true);
} catch (error) {
updateStep(currentStep, 'error', null, error instanceof Error ? error.message : 'Unknown error');
} finally {
setProcessing(false);
}
};
const resetShopping = () => {
setSteps(steps.map(step => ({ ...step, status: 'pending', data: undefined, error: undefined })));
setCurrentStep(0);
setProcessing(false);
setCompleted(false);
setFinalResult(null);
};
return (
<div className="mcp-shopping">
<div className="shopping-header">
<h2>🛒 AI-Powered Shopping & Payment</h2>
<p>Tell AI what you want to buy and let it handle the complete purchase flow</p>
</div>
{!completed && (
<div className="shopping-form">
<div className="form-section">
<h3>🤖 What do you want to buy?</h3>
<textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Example: I want to buy wireless headphones from https://tokopedia.com/product/sony-headphones"
rows={3}
disabled={processing}
/>
</div>
<div className="form-section">
<h3>📦 Delivery Information</h3>
<div className="form-grid">
<input
type="text"
placeholder="Full Name *"
value={recipientInfo.name}
onChange={(e) => setRecipientInfo(prev => ({ ...prev, name: e.target.value }))}
disabled={processing}
required
/>
<input
type="tel"
placeholder="Phone Number *"
value={recipientInfo.phone}
onChange={(e) => setRecipientInfo(prev => ({ ...prev, phone: e.target.value }))}
disabled={processing}
required
/>
</div>
<textarea
placeholder="Complete Address *"
value={recipientInfo.address}
onChange={(e) => setRecipientInfo(prev => ({ ...prev, address: e.target.value }))}
rows={2}
disabled={processing}
required
/>
<input
type="text"
placeholder="Delivery Notes (optional)"
value={recipientInfo.notes}
onChange={(e) => setRecipientInfo(prev => ({ ...prev, notes: e.target.value }))}
disabled={processing}
/>
</div>
<div className="form-actions">
<button
onClick={startShopping}
disabled={processing || !prompt.trim() || !recipientInfo.name || !recipientInfo.phone || !recipientInfo.address}
className="start-shopping-btn"
>
{processing ? '⏳ Processing...' : '🚀 Start AI Shopping'}
</button>
{processing && (
<button onClick={resetShopping} className="reset-btn">
❌ Cancel
</button>
)}
</div>
</div>
)}
{/* Shopping Steps Progress */}
<div className="shopping-steps">
<h3>📊 Shopping Progress</h3>
{steps.map((step, index) => (
<div
key={step.step}
className={`step ${step.status} ${index === currentStep ? 'active' : ''}`}
>
<div className="step-header">
<div className="step-number">
{step.status === 'completed' && '✅'}
{step.status === 'processing' && '⏳'}
{step.status === 'error' && '❌'}
{step.status === 'pending' && step.step}
</div>
<div className="step-title">{step.title}</div>
<div className="step-status">{step.status}</div>
</div>
{step.error && (
<div className="step-error">
❌ {step.error}
</div>
)}
{step.data && step.status === 'completed' && (
<div className="step-data">
{step.step === 1 && step.data.detected_url && (
<p>🔗 Detected URL: {step.data.detected_url}</p>
)}
{step.step === 2 && step.data.product && (
<div>
<p>📦 Product: {step.data.product.name}</p>
<p>💰 Price: {step.data.product.price} {step.data.product.currency}</p>
</div>
)}
{step.step === 3 && step.data.pricing && (
<div>
<p>💱 USDC Price: {step.data.pricing.usdc_amount} USDC</p>
<p>📈 Exchange Rate: {step.data.pricing.exchange_rate}</p>
</div>
)}
{step.step === 4 && step.data.order_id && (
<div>
<p>📋 Order ID: {step.data.order_id}</p>
<p>💰 Total: {step.data.total_amount_usdc} USDC</p>
<p>✅ Balance Check: {step.data.balance_sufficient ? 'Sufficient' : 'Insufficient'}</p>
</div>
)}
{step.step === 5 && step.data.transaction_hash && (
<div>
<p>🔗 TX Hash: {step.data.transaction_hash}</p>
<p>✅ Status: {step.data.payment_status}</p>
</div>
)}
</div>
)}
</div>
))}
</div>
{/* Final Result */}
{completed && finalResult && (
<div className="shopping-result">
<div className="success-banner">
<h3>🎉 Shopping Completed Successfully!</h3>
</div>
<div className="result-details">
<div className="result-item">
<strong>📦 Product:</strong> {finalResult.product_name}
</div>
<div className="result-item">
<strong>📋 Order ID:</strong> {finalResult.order_id}
</div>
<div className="result-item">
<strong>💰 Total Paid:</strong> {finalResult.total_paid} USDC
</div>
<div className="result-item">
<strong>🔗 Transaction:</strong>
<code className="tx-hash">{finalResult.transaction_hash}</code>
</div>
<div className="result-item">
<strong>✅ Status:</strong> {finalResult.status}
</div>
</div>
<div className="result-actions">
<button onClick={resetShopping} className="new-order-btn">
🛒 Start New Order
</button>
<button
onClick={() => navigator.clipboard.writeText(finalResult.transaction_hash)}
className="copy-tx-btn"
>
📋 Copy Transaction Hash
</button>
</div>
</div>
)}
</div>
);
};
export default MCPShopping;
Order Management Dashboard
import React, { useState, useEffect } from 'react';
import { useSDK } from '../contexts/SDKContext';
interface Order {
order_id: string;
product_name: string;
total_amount: number;
status: string;
created_at: string;
transaction_hash?: string;
}
interface OrderStats {
total_orders: number;
completed_orders: number;
processing_orders: number;
total_spent_usdc: number;
completion_rate: number;
}
const OrderManagement: React.FC = () => {
const { currentUser } = useSDK();
const [orders, setOrders] = useState<Order[]>([]);
const [stats, setStats] = useState<OrderStats | null>(null);
const [loading, setLoading] = useState(false);
const [selectedOrder, setSelectedOrder] = useState<Order | null>(null);
useEffect(() => {
loadOrderData();
}, []);
const loadOrderData = async () => {
setLoading(true);
try {
const brdzSDK = await import('anantla_sdk').then(sdk => sdk.default);
const mcp = brdzSDK.mcp;
// Load dashboard data (stats + recent orders)
const dashboardData = await mcp.getDashboardData(10);
setStats(dashboardData.stats);
setOrders(dashboardData.recentOrders);
} catch (error) {
console.error('Failed to load order data:', error);
} finally {
setLoading(false);
}
};
const loadAllOrders = async () => {
setLoading(true);
try {
const brdzSDK = await import('anantla_sdk').then(sdk => sdk.default);
const mcp = brdzSDK.mcp;
const allOrders = await mcp.getAllOrders({ limit: 50 });
setOrders(allOrders.data);
} catch (error) {
console.error('Failed to load all orders:', error);
} finally {
setLoading(false);
}
};
const getOrderDetails = async (orderId: string) => {
try {
const brdzSDK = await import('anantla_sdk').then(sdk => sdk.default);
const mcp = brdzSDK.mcp;
const orderDetails = await mcp.getOrder(orderId);
setSelectedOrder(orderDetails);
} catch (error) {
console.error('Failed to get order details:', error);
}
};
const getStatusColor = (status: string) => {
switch (status.toLowerCase()) {
case 'completed': return '#28a745';
case 'processing': return '#ffc107';
case 'pending': return '#17a2b8';
case 'failed': return '#dc3545';
default: return '#6c757d';
}
};
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
};
return (
<div className="order-management">
<div className="dashboard-header">
<h2>📊 Payment & Order Dashboard</h2>
<div className="header-actions">
<button onClick={loadOrderData} disabled={loading}>
{loading ? '⏳ Loading...' : '🔄 Refresh'}
</button>
<button onClick={loadAllOrders}>
📋 Load All Orders
</button>
</div>
</div>
{/* Statistics Overview */}
{stats && (
<div className="stats-overview">
<div className="stat-card">
<div className="stat-value">{stats.total_orders}</div>
<div className="stat-label">Total Orders</div>
</div>
<div className="stat-card">
<div className="stat-value">{stats.completed_orders}</div>
<div className="stat-label">Completed</div>
</div>
<div className="stat-card">
<div className="stat-value">{stats.processing_orders}</div>
<div className="stat-label">Processing</div>
</div>
<div className="stat-card">
<div className="stat-value">{stats.total_spent_usdc.toFixed(2)} USDC</div>
<div className="stat-label">Total Spent</div>
</div>
<div className="stat-card">
<div className="stat-value">{stats.completion_rate.toFixed(1)}%</div>
<div className="stat-label">Success Rate</div>
</div>
</div>
)}
{/* Orders List */}
<div className="orders-section">
<h3>📦 Recent Orders ({orders.length})</h3>
{loading ? (
<div className="loading-state">
<div className="spinner">⏳</div>
<p>Loading orders...</p>
</div>
) : orders.length === 0 ? (
<div className="empty-state">
<h4>🛒 No Orders Found</h4>
<p>Start shopping with AI to see your orders here!</p>
</div>
) : (
<div className="orders-table">
<div className="table-header">
<div className="col-order-id">Order ID</div>
<div className="col-product">Product</div>
<div className="col-amount">Amount</div>
<div className="col-status">Status</div>
<div className="col-date">Date</div>
<div className="col-actions">Actions</div>
</div>
{orders.map((order) => (
<div key={order.order_id} className="table-row">
<div className="col-order-id">
<code>{order.order_id.substring(0, 8)}...</code>
</div>
<div className="col-product">
<strong>{order.product_name || 'Unknown Product'}</strong>
</div>
<div className="col-amount">
{order.total_amount} USDC
</div>
<div className="col-status">
<span
className="status-badge"
style={{ backgroundColor: getStatusColor(order.status) }}
>
{order.status}
</span>
</div>
<div className="col-date">
{formatDate(order.created_at)}
</div>
<div className="col-actions">
<button
onClick={() => getOrderDetails(order.order_id)}
className="details-btn"
>
👁️ Details
</button>
{order.transaction_hash && (
<button
onClick={() => navigator.clipboard.writeText(order.transaction_hash!)}
className="copy-btn"
>
📋 Copy TX
</button>
)}
</div>
</div>
))}
</div>
)}
</div>
{/* Order Details Modal */}
{selectedOrder && (
<div className="modal-overlay" onClick={() => setSelectedOrder(null)}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<div className="modal-header">
<h3>📦 Order Details</h3>
<button onClick={() => setSelectedOrder(null)}>✖</button>
</div>
<div className="modal-body">
<div className="detail-row">
<strong>Order ID:</strong>
<code>{selectedOrder.order_id}</code>
</div>
<div className="detail-row">
<strong>Product:</strong>
{selectedOrder.product_name}
</div>
<div className="detail-row">
<strong>Amount:</strong>
{selectedOrder.total_amount} USDC
</div>
<div className="detail-row">
<strong>Status:</strong>
<span
className="status-badge"
style={{ backgroundColor: getStatusColor(selectedOrder.status) }}
>
{selectedOrder.status}
</span>
</div>
<div className="detail-row">
<strong>Created:</strong>
{formatDate(selectedOrder.created_at)}
</div>
{selectedOrder.transaction_hash && (
<div className="detail-row">
<strong>Transaction Hash:</strong>
<code className="tx-hash">{selectedOrder.transaction_hash}</code>
</div>
)}
</div>
<div className="modal-actions">
{selectedOrder.transaction_hash && (
<button
onClick={() => navigator.clipboard.writeText(selectedOrder.transaction_hash!)}
className="copy-tx-btn"
>
📋 Copy Transaction Hash
</button>
)}
<button onClick={() => setSelectedOrder(null)} className="close-btn">
Close
</button>
</div>
</div>
</div>
)}
</div>
);
};
export default OrderManagement;
Traditional Payment Processing
Direct Wallet Transfers
class TraditionalPaymentProcessor {
constructor(userId) {
this.userId = userId;
this.onchain = brdzSDK.onchain;
this.cryptoWallet = brdzSDK.cryptoWallet;
}
async sendPayment(fromWalletId, toAddress, amount, tokenSymbol, chainId) {
try {
console.log('💸 Sending direct payment...');
// Get platform fee settings
const feeSettings = await this.onchain.getFeeSettings();
// Calculate platform fee
const platformFee = this.onchain.utils.calculatePlatformFee(
amount,
feeSettings.platform_fee_percentage,
feeSettings.minimum_platform_fee_usd
);
// Execute transaction via backend
const result = await this.onchain.executeTransaction({
wallet_id: fromWalletId,
chain_id: chainId,
token_symbol: tokenSymbol,
token_contract: tokenSymbol === 'USDC' ? 'contract_address' : 'native',
to_address: toAddress,
amount: amount,
decimals: tokenSymbol === 'USDC' ? 6 : 18
});
return {
success: true,
transaction_hash: result.transaction_hash,
gas_fee: result.gas_fee,
platform_fee: platformFee,
total_cost: result.total_cost,
chain: chainId
};
} catch (error) {
throw new Error(`Payment failed: ${error.message}`);
}
}
async getTransactionHistory(limit = 10) {
try {
const history = await this.onchain.getTransactionHistory(this.userId, {
limit: limit,
offset: 0
});
return history.data.map(tx => ({
tx_hash: tx.tx_hash,
amount: tx.amount,
token_symbol: tx.token_symbol,
chain_id: tx.chain_id,
to_address: tx.to_address,
tx_flow: tx.tx_flow, // 'IN' or 'OUT'
gas_fee: tx.gas_fee,
platform_fee: tx.platform_fee,
status: tx.status,
created_at: tx.created_at
}));
} catch (error) {
throw new Error(`Failed to get transaction history: ${error.message}`);
}
}
async getTransactionDetails(txHash) {
try {
const details = await this.onchain.getTransactionDetails(txHash);
return {
transaction_hash: details.tx_hash,
amount: details.amount,
token_symbol: details.token_symbol,
chain_id: details.chain_id,
from_address: details.from_address,
to_address: details.to_address,
gas_fee: details.gas_fee,
platform_fee: details.platform_fee,
block_number: details.block_number,
confirmations: details.confirmations,
status: details.status,
explorer_url: this.onchain.utils.getExplorerUrl(details.chain_id, details.tx_hash)
};
} catch (error) {
throw new Error(`Failed to get transaction details: ${error.message}`);
}
}
// Bulk payment processing
async processBulkPayments(payments) {
const results = [];
for (const payment of payments) {
try {
const result = await this.sendPayment(
payment.from_wallet_id,
payment.to_address,
payment.amount,
payment.token_symbol,
payment.chain_id
);
results.push({
...payment,
success: true,
transaction_hash: result.transaction_hash,
total_cost: result.total_cost
});
// Wait between payments to avoid rate limits
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (error) {
results.push({
...payment,
success: false,
error: error.message
});
}
}
return results;
}
}
// Usage Examples
const paymentProcessor = new TraditionalPaymentProcessor(123);
// Single payment
const paymentResult = await paymentProcessor.sendPayment(
1, // wallet ID
'0x742d35Cc6635C0532925a3b8D400d93458f8DA83', // recipient
'10.5', // amount
'USDC', // token
'sepolia' // chain
);
// Bulk payments
const bulkPayments = [
{
from_wallet_id: 1,
to_address: '0x742d35Cc6635C0532925a3b8D400d93458f8DA83',
amount: '5.0',
token_symbol: 'USDC',
chain_id: 'sepolia'
},
{
from_wallet_id: 1,
to_address: '0x8ba1f109551bD432803012645Hac136c5C63c2C7',
amount: '3.2',
token_symbol: 'USDC',
chain_id: 'amoy'
}
];
const bulkResults = await paymentProcessor.processBulkPayments(bulkPayments);
Advanced Payment Features
Cross-Chain Payment Router
class CrossChainPaymentRouter {
constructor(userId) {
this.userId = userId;
this.crosschain = brdzSDK.crosschain;
this.cryptoWallet = brdzSDK.cryptoWallet;
}
async initiateCrossChainPayment(fromChain, toChain, amount, recipientAddress) {
try {
console.log(`🌉 Initiating cross-chain payment: ${fromChain} → ${toChain}`);
// Step 1: Get user wallet for source chain
const sourceWallet = await this.getUserWalletForChain(fromChain);
// Step 2: Check balance
const balance = await this.crosschain.getUSDCBalance(fromChain, sourceWallet);
if (parseFloat(balance.balance) < parseFloat(amount)) {
throw new Error(`Insufficient balance. Available: ${balance.balance} USDC`);
}
// Step 3: Initiate cross-chain transfer
const transfer = await this.crosschain.initiateTransfer({
user_id: this.userId,
amount: amount,
from_chain: fromChain,
to_chain: toChain,
token: 'USDC',
recipient_address: recipientAddress,
return_address: sourceWallet
});
return {
log_id: transfer.log_id,
nonce: transfer.nonce,
status: 'initiated',
from_chain: fromChain,
to_chain: toChain,
amount: amount,
recipient: recipientAddress
};
} catch (error) {
throw new Error(`Cross-chain initiation failed: ${error.message}`);
}
}
async completeCrossChainPayment(logId, txHash) {
try {
// Confirm the burn transaction
const confirmation = await this.crosschain.confirmTransfer({
log_id: logId,
tx_hash: txHash,
status: 'confirmed'
});
// Execute mint on destination chain
const mintResult = await this.crosschain.mintToken(confirmation.nonce);
return {
success: true,
mint_tx_hash: mintResult.transaction_hash,
destination_chain: mintResult.chain,
amount: mintResult.amount,
status: 'completed'
};
} catch (error) {
throw new Error(`Cross-chain completion failed: ${error.message}`);
}
}
async getCrossChainHistory() {
try {
const history = await this.crosschain.getCTransactionHistory(this.userId, {
limit: 20,
offset: 0
});
return history.data.map(tx => ({
log_id: tx.log_id,
from_chain: tx.from_chain,
to_chain: tx.to_chain,
amount: tx.amount,
status: tx.status,
burn_tx_hash: tx.burn_tx_hash,
mint_tx_hash: tx.mint_tx_hash,
created_at: tx.created_at,
completed_at: tx.completed_at
}));
} catch (error) {
throw new Error(`Failed to get cross-chain history: ${error.message}`);
}
}
async getUserWalletForChain(chainId) {
const wallets = await this.cryptoWallet.getUserWallets(this.userId);
for (const wallet of wallets) {
const addresses = await this.cryptoWallet.getWalletAddresses(wallet.bw_id);
const chainAddress = addresses.find(addr => addr.chain_id === chainId);
if (chainAddress) {
return chainAddress.address;
}
}
throw new Error(`No wallet found for chain: ${chainId}`);
}
}
Styling for Payment Components
/* MCP Shopping Styles */
.mcp-shopping {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.shopping-header {
text-align: center;
margin-bottom: 30px;
}
.shopping-form {
background: #f8f9fa;
padding: 25px;
border-radius: 8px;
margin-bottom: 30px;
}
.form-section {
margin-bottom: 25px;
}
.form-section h3 {
margin-bottom: 15px;
color: #495057;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-bottom: 15px;
}
.form-section input,
.form-section textarea {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.form-actions {
display: flex;
gap: 15px;
justify-content: center;
}
.start-shopping-btn {
padding: 12px 24px;
background: linear-gradient(135deg, #28a745, #20c997);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
}
.start-shopping-btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.reset-btn {
padding: 12px 24px;
background: #dc3545;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
}
/* Shopping Steps */
.shopping-steps {
margin-bottom: 30px;
}
.step {
margin-bottom: 15px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 6px;
background: #fff;
}
.step.active {
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}
.step.completed {
background: #d4edda;
border-color: #28a745;
}
.step.error {
background: #f8d7da;
border-color: #dc3545;
}
.step.processing {
background: #fff3cd;
border-color: #ffc107;
}
.step-header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 10px;
}
.step-number {
width: 30px;
height: 30px;
border-radius: 50%;
background: #6c757d;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.step-title {
flex: 1;
font-weight: bold;
}
.step-status {
font-size: 12px;
text-transform: uppercase;
color: #666;
}
.step-error {
color: #dc3545;
background: rgba(220, 53, 69, 0.1);
padding: 8px;
border-radius: 4px;
margin-top: 10px;
}
.step-data {
margin-top: 10px;
padding: 10px;
background: rgba(0, 123, 255, 0.1);
border-radius: 4px;
font-size: 14px;
}
/* Shopping Result */
.shopping-result {
background: #d4edda;
border: 1px solid #28a745;
border-radius: 8px;
padding: 25px;
text-align: center;
}
.success-banner {
margin-bottom: 20px;
}
.result-details {
display: grid;
gap: 10px;
margin-bottom: 20px;
text-align: left;
}
.result-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid rgba(40, 167, 69, 0.2);
}
.tx-hash {
background: #f8f9fa;
padding: 4px 8px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 12px;
}
.result-actions {
display: flex;
gap: 15px;
justify-content: center;
}
.new-order-btn,
.copy-tx-btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
.new-order-btn {
background: #007bff;
color: white;
}
.copy-tx-btn {
background: #6c757d;
color: white;
}
/* Order Management Styles */
.order-management {
padding: 20px;
}
.dashboard-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
}
.header-actions {
display: flex;
gap: 10px;
}
.header-actions button {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Statistics */
.stats-overview {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 8px;
border: 1px solid #ddd;
text-align: center;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #007bff;
margin-bottom: 5px;
}
.stat-label {
font-size: 12px;
color: #666;
text-transform: uppercase;
}
/* Orders Table */
.orders-table {
background: white;
border-radius: 8px;
overflow: hidden;
border: 1px solid #ddd;
}
.table-header,
.table-row {
display: grid;
grid-template-columns: 120px 1fr 100px 100px 140px 120px;
gap: 15px;
align-items: center;
}
.table-header {
background: #f8f9fa;
padding: 15px;
font-weight: bold;
border-bottom: 1px solid #ddd;
}
.table-row {
padding: 15px;
border-bottom: 1px solid #eee;
}
.table-row:hover {
background: #f8f9fa;
}
.status-badge {
padding: 4px 8px;
border-radius: 12px;
color: white;
font-size: 11px;
text-transform: uppercase;
font-weight: bold;
}
.details-btn,
.copy-btn {
padding: 4px 8px;
font-size: 11px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 5px;
}
.details-btn {
background: #17a2b8;
color: white;
}
.copy-btn {
background: #6c757d;
color: white;
}
/* Modal */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 30px;
border-radius: 8px;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-header button {
background: none;
border: none;
font-size: 20px;
cursor: pointer;
}
.detail-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.modal-actions {
display: flex;
gap: 10px;
justify-content: center;
margin-top: 20px;
}
.copy-tx-btn,
.close-btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.copy-tx-btn {
background: #007bff;
color: white;
}
.close-btn {
background: #6c757d;
color: white;
}
/* Responsive Design */
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
}
.stats-overview {
grid-template-columns: repeat(2, 1fr);
}
.table-header,
.table-row {
grid-template-columns: 1fr;
gap: 5px;
}
.modal-content {
margin: 20px;
width: calc(100% - 40px);
}
}
Next Steps
You've mastered comprehensive payment processing with BRDZ SDK:
✅ AI-Powered Shopping - Complete MCP commerce flows with natural language
✅ Order Management - Dashboard with statistics and transaction tracking
✅ Traditional Payments - Direct wallet-to-wallet transfers
✅ Multi-Chain Support - Cross-chain payment routing
✅ React Integration - Production-ready payment components
Continue Learning
- Cross-Chain Operations - Advanced multi-blockchain workflows
- SDK Reference - Complete MCP documentation
- SDK Reference - Traditional payment APIs
Need Help?
If you encounter issues:
- Email: contact@anantla.com
- Contact: BRDZ Contact Form