概览
On-ramp 将法币(COP, MXN, USD)转换为加密货币(USDC, USDT)。用户使用本地支付方式支付,并在钱包中接收加密货币。完整的 On-Ramp 流程
实现示例
复制
const executeOnRamp = async (userId, walletAddress, amount) => {
try {
// 1. 如果需要,创建钱包账户
let wallet = await findWalletAccount(userId, 'POLYGON', 'USDC');
if (!wallet) {
wallet = await createWalletAccount(userId, walletAddress, 'USDC', 'POLYGON');
}
// 2. 获取报价
const quote = await fetch('/api/v2/quotations', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
fromCurrency: 'COP',
toCurrency: 'USDC',
amount: amount,
amountIsToCurrency: false,
cashInMethod: 'PSE',
cashOutMethod: 'POLYGON'
})
}).then(r => r.json());
console.log(`您将收到: ${quote.toAmount} USDC`);
// 3. 创建 ramp
const ramp = await fetch('/api/v2/ramps', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
quotationId: quote.id,
userId: userId,
accountId: wallet.id,
externalId: `onramp-${Date.now()}`
})
}).then(r => r.json());
// 4. 重定向到支付
return {
rampId: ramp.id,
paymentUrl: ramp.paymentInfo[0].url,
expectedAmount: quote.toAmount
};
} catch (error) {
console.error('On-ramp 失败:', error);
throw error;
}
};
// 使用
const result = await executeOnRamp('user-id', '0x742d35...', 100000);
window.location.href = result.paymentUrl;
支付方式
- PSE(哥伦比亚)
- SPEI(墨西哥)
- TRANSFIYA(哥伦比亚)
用户重定向到 PSE 结账:流程:
复制
// Ramp 响应包含支付 URL
const paymentUrl = ramp.paymentInfo[0].url;
// 重定向用户
window.location.href = paymentUrl;
// 用户在 PSE 上完成支付
// Webhook 在支付确认时通知
- 重定向到 PSE URL
- 用户选择银行
- 用户验证身份
- 用户确认支付
- 收到 Webhook
用户转账到提供的 CLABE:重要: 用户必须在支付参考中包含
复制
const paymentInfo = ramp.paymentInfo[0];
// 显示给用户:
console.log('银行:', paymentInfo.Bank);
console.log('CLABE:', paymentInfo.CLABE);
console.log('收款人:', paymentInfo.Beneficiary);
console.log('参考号:', paymentInfo.concepto);
// 用户使用参考号完成 SPEI 转账
concepto移动钱包或电话转账:用户通过 Transfiya 应用发送到提供的号码。
复制
{
"quotationId": "quote-id",
"userId": "user-id",
"accountId": "wallet-id",
"details": {
"cashIn": {
"transfiyaAccount": "3001234567"
}
}
}
监控进度
复制
const monitorRamp = async (rampId) => {
const pollInterval = setInterval(async () => {
const ramp = await fetch(`/api/v2/ramps/${rampId}`, {
headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());
console.log('状态:', ramp.status);
if (ramp.status === 'COMPLETED') {
console.log('加密货币已交付!');
console.log('交易:', ramp.transferProof);
clearInterval(pollInterval);
} else if (['FAILED', 'CANCELED'].includes(ramp.status)) {
console.error('Ramp 失败:', ramp.details);
clearInterval(pollInterval);
}
}, 10000); // 每 10 秒检查一次
};
使用 webhooks 作为主要通知方式,轮询作为备用。
处理用户流程
构建流畅的用户体验:复制
// 步骤 1:报价页面
const QuotePage = () => {
const [quote, setQuote] = useState(null);
const getQuote = async (amount) => {
const q = await createQuotation(amount, 'COP', 'USDC');
setQuote(q);
};
return (
<div>
<input onChange={(e) => getQuote(e.target.value)} />
{quote && (
<div>
<p>您发送: {quote.fromAmount} COP</p>
<p>您收到: {quote.toAmount} USDC</p>
<p>汇率: {quote.rate}</p>
<button onClick={() => createAndRedirect(quote)}>
继续
</button>
</div>
)}
</div>
);
};
// 步骤 2:重定向到支付
const createAndRedirect = async (quote) => {
const ramp = await createRamp(quote.id, userId, walletId);
// 保存 ramp ID 用于状态检查
localStorage.setItem('currentRampId', ramp.id);
// 重定向到 PSE
window.location.href = ramp.paymentInfo[0].url;
};
// 步骤 3:返回页面 - 检查状态
const ReturnPage = () => {
const rampId = localStorage.getItem('currentRampId');
const [status, setStatus] = useState(null);
useEffect(() => {
const checkStatus = async () => {
const ramp = await getRamp(rampId);
setStatus(ramp.status);
if (ramp.status === 'COMPLETED') {
showSuccess(ramp);
}
};
checkStatus();
const interval = setInterval(checkStatus, 5000);
return () => clearInterval(interval);
}, [rampId]);
return <div>状态: {status}</div>;
};