UNPKG

@moneygraph/sdk

Version:

AI-native SDK for global payouts powered by StratosPay

217 lines (216 loc) 6.45 kB
"use strict"; /** * MoneyGraph SDK - Liquidity Module * * FX quotes with Quote & Confirm pattern: * 1. getQuote() - Get a rate quote (valid for 2 minutes) * 2. confirmQuote() - Lock in the rate before executing payout */ Object.defineProperty(exports, "__esModule", { value: true }); exports.LiquidityModule = void 0; const client_1 = require("../api/client"); // Mock FX rates for sandbox (USD as base) const MOCK_RATES = { // Major currencies USD_EUR: 0.92, USD_GBP: 0.79, USD_CAD: 1.36, USD_AUD: 1.53, USD_JPY: 149.50, USD_CHF: 0.88, USD_CNY: 7.24, USD_INR: 83.12, USD_SGD: 1.34, USD_HKD: 7.82, USD_KRW: 1320.00, USD_MXN: 17.15, USD_BRL: 4.97, // African currencies USD_NGN: 1550.00, USD_KES: 153.50, USD_ZAR: 18.50, USD_GHS: 12.50, USD_UGX: 3750.00, USD_TZS: 2510.00, USD_XOF: 605.00, USD_XAF: 605.00, USD_EGP: 30.90, USD_MAD: 10.05, // Europe USD_PLN: 4.02, USD_CZK: 22.50, USD_HUF: 355.00, USD_RON: 4.58, USD_NOK: 10.70, USD_SEK: 10.55, USD_DKK: 6.88, // Middle East USD_AED: 3.67, USD_SAR: 3.75, USD_ILS: 3.70, // Asia USD_PHP: 55.80, USD_THB: 35.20, USD_VND: 24500.00, USD_IDR: 15650.00, USD_MYR: 4.70, USD_PKR: 278.00, USD_BDT: 110.00, // Crypto (relative to USD) USD_USDC: 1.00, USD_USDT: 1.00, USD_ETH: 0.00030, USD_BTC: 0.000015, }; // Sandbox quote storage const sandboxQuotes = new Map(); function generateQuoteId() { return `quote_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`; } function getRate(from, to) { // Direct rate const directKey = `${from}_${to}`; if (MOCK_RATES[directKey]) { return MOCK_RATES[directKey]; } // Reverse rate const reverseKey = `${to}_${from}`; if (MOCK_RATES[reverseKey]) { return 1 / MOCK_RATES[reverseKey]; } // Cross rate via USD const fromUsdKey = `USD_${from}`; const toUsdKey = `USD_${to}`; if (from === 'USD' && MOCK_RATES[toUsdKey]) { return MOCK_RATES[toUsdKey]; } if (to === 'USD' && MOCK_RATES[fromUsdKey]) { return 1 / MOCK_RATES[fromUsdKey]; } // Cross via USD const fromToUsd = MOCK_RATES[fromUsdKey] ? 1 / MOCK_RATES[fromUsdKey] : null; const usdToTo = MOCK_RATES[toUsdKey] || null; if (fromToUsd !== null && usdToTo !== null) { return fromToUsd * usdToTo; } // Default fallback return 1.0; } function calculateFee(amount) { // 1% fee with $2 minimum return Math.max(amount * 0.01, 2); } class LiquidityModule { constructor(client) { this.client = client; } /** * Get an FX quote * Quote is valid for 2 minutes */ async getQuote(params) { if (this.client.isSandbox) { const rate = getRate(params.from, params.to); const fee = calculateFee(params.amount); const toAmount = (params.amount - fee) * rate; const quote = { id: generateQuoteId(), from_currency: params.from, to_currency: params.to, from_amount: params.amount, to_amount: Math.round(toAmount * 100) / 100, rate, fee, expires_at: new Date(Date.now() + 2 * 60 * 1000).toISOString(), created_at: new Date().toISOString(), }; sandboxQuotes.set(quote.id, { ...quote, confirmed: false }); return quote; } return this.client.post('/liquidity/quote', params); } /** * Confirm a quote (lock in the rate) * Must be called before the quote expires */ async confirmQuote(quoteId) { if (this.client.isSandbox) { const quote = sandboxQuotes.get(quoteId); if (!quote) { throw new client_1.MoneyGraphError('Quote not found', 'QUOTE_NOT_FOUND', 404); } if (new Date(quote.expires_at) < new Date()) { throw new client_1.MoneyGraphError('Quote has expired', 'QUOTE_EXPIRED', 400); } if (quote.confirmed) { throw new client_1.MoneyGraphError('Quote already confirmed', 'VALIDATION_ERROR', 400); } quote.confirmed = true; sandboxQuotes.set(quoteId, quote); return { id: crypto.randomUUID(), quote_id: quoteId, locked_rate: quote.rate, transaction_id: `txn_${Date.now()}`, status: 'confirmed', confirmed_at: new Date().toISOString(), }; } return this.client.post(`/liquidity/quote/${quoteId}/confirm`); } /** * Check if a quote is still valid */ isQuoteValid(quote) { return new Date(quote.expires_at) > new Date(); } /** * Get remaining time in seconds until quote expires */ getQuoteTimeRemaining(quote) { const remaining = new Date(quote.expires_at).getTime() - Date.now(); return Math.max(0, Math.floor(remaining / 1000)); } /** * Get available exchange rates for a currency pair */ async getRates(fromCurrency, toCurrency) { if (this.client.isSandbox) { const rate = getRate(fromCurrency, toCurrency); return { rate, inverse_rate: 1 / rate, fee_percent: 1, min_amount: 10, max_amount: 100000, }; } // In live mode, get quote for $100 to determine rate const quote = await this.getQuote({ from: fromCurrency, to: toCurrency, amount: 100, }); return { rate: quote.rate, inverse_rate: 1 / quote.rate, fee_percent: (quote.fee / quote.from_amount) * 100, min_amount: 10, max_amount: 100000, }; } /** * Clean up expired quotes (sandbox only) */ cleanupExpiredQuotes() { if (!this.client.isSandbox) return; const now = Date.now(); for (const [id, quote] of sandboxQuotes.entries()) { if (new Date(quote.expires_at).getTime() < now) { sandboxQuotes.delete(id); } } } } exports.LiquidityModule = LiquidityModule;