/** * Fee Calculator * * Provides local fee calculation for gas-free transfers. * Calculates service fees based on transfer amounts using a simple percentage-based model. * * @module features/gas-free/utils/FeeCalculator */ /** * Fee calculator for gas-free transfers * * Uses a simple percentage-based pricing model with floor and cap. */ export class FeeCalculator { private readonly assetToUsdRate: number = 1; // 1 asset unit (no precision) = 1 USD (to be dynamically set based on asset) private readonly assetPrecision: number = 6; // Default precision // Fee calculation parameters private readonly FEE_RATE = 0.001; // 0.1% private readonly MIN_FEE = 0.50; // $0.50 minimum (floor) private readonly MAX_FEE = 10.00; // $10.00 maximum (cap) /** * Create a fee estimator with default parameters */ constructor() { // No configuration needed - fixed parameters } /** * Calculate service fee in USD based on transfer amount * * Uses a simple percentage-based model with floor and cap: * - 0.1% of transfer amount * - Minimum: $0.50 (applies for amounts < $500) * - Maximum: $10.00 (applies for amounts > $10,000) * * @param amountUsd - Transfer amount in USD * @returns Fee in USD * @throws Error if amount is invalid * * @example * ```typescript * const calculator = new FeeCalculator(); * console.log(calculator.calculateFee(100)); // $0.50 (minimum) * console.log(calculator.calculateFee(500)); // $0.50 (0.1% × $500) * console.log(calculator.calculateFee(1000)); // $1.00 (0.1% × $1000) * console.log(calculator.calculateFee(50000)); // $10.00 (maximum cap) * ``` */ public calculateFee(amountUsd: number): number { if (amountUsd < 0) { throw new Error('Amount cannot be negative'); } if (!Number.isFinite(amountUsd)) { throw new Error('Amount must be a valid number'); } // Calculate percentage-based fee const percentageFee = amountUsd * this.FEE_RATE; // Apply floor (minimum) and cap (maximum) const feeUsd = Math.max(this.MIN_FEE, Math.min(this.MAX_FEE, percentageFee)); return feeUsd; } /** * Estimate service fee in RGB asset base units * * This method uses hardcoded parameters (1:1 USD rate, precision 6) to estimate fees. * * Steps: * 1. Converts transfer amount from base units to asset units * 2. Converts asset units to USD (1:1 rate) * 3. Calculates fee in USD (0.1% with $0.50 min, $10 max) * 4. Converts fee back to asset base units * * @param transferAmount - Amount being transferred in base units (e.g., 100250000 for 100.25 TUSDT with precision 6) * @param assetToUsdRate - Conversion rate from asset to USD (optional, defaults to 1) * @param assetPrecision - Asset precision exponent (optional, defaults to 6) * @returns Object with fee in asset base units, USD, and effective percentage * @throws Error if inputs are invalid * * @example * ```typescript * const calculator = new FeeCalculator(); * * // Transfer 100 TUSDT (100000000 base units with precision 6) * const result1 = calculator.estimateFeeInAsset(100000000, 1, 6); * console.log(`Fee: ${result1.feeInAsset} base units`); // 500000 ($0.50 minimum) * console.log(`Fee: $${result1.feeUsd}`); // $0.50 * * // Transfer 1,000 TUSDT (1000000000 base units) * const result2 = calculator.estimateFeeInAsset(1000000000, 1, 6); * console.log(`Fee: ${result2.feeInAsset} base units`); // 1000000 ($1.00) * console.log(`Fee: $${result2.feeUsd}`); // $1.00 * console.log(`Rate: ${result2.effectivePercentage}%`); // 0.1% * ``` */ public estimateFeeInAsset( transferAmount: number, assetToUsdRate?: number, assetPrecision?: number ): { feeInAsset: number; feeUsd: number; effectivePercentage: number } { // Use provided values or defaults const rate = assetToUsdRate ?? this.assetToUsdRate; const precision = assetPrecision ?? this.assetPrecision; // Validate inputs if (transferAmount < 0) { throw new Error('Transfer amount cannot be negative'); } if (!Number.isFinite(transferAmount)) { throw new Error('Transfer amount must be a valid number'); } if (rate <= 0) { throw new Error('Asset to USD rate must be positive'); } if (!Number.isFinite(rate)) { throw new Error('Asset to USD rate must be a valid number'); } if (precision <= 0 || !Number.isInteger(precision)) { throw new Error('Asset precision must be a positive integer'); } // Step 1: Convert transfer amount from base units to asset units const transferAmountInAssetUnits = transferAmount / Math.pow(10, precision); // Step 2: Convert to USD const transferAmountUsd = transferAmountInAssetUnits * rate; // Step 3: Calculate fee in USD using amount-based formula const feeUsd = this.calculateFee(transferAmountUsd); // Step 4: Convert USD fee to asset base units // USD → asset units → base units (with precision) const feeInAssetUnits = feeUsd / rate; const feeInAsset = Math.round(feeInAssetUnits * Math.pow(10, precision)); // Calculate effective percentage for tracking const effectivePercentage = (feeUsd / transferAmountUsd) * 100; return { feeInAsset, feeUsd, effectivePercentage, }; } /** * Get the current asset to USD exchange rate */ public getAssetToUsdRate(): number { return this.assetToUsdRate; } /** * Get the current asset precision */ public getAssetPrecision(): number { return this.assetPrecision; } /** * Get the fee rate (0.1%) */ public getFeeRate(): number { return this.FEE_RATE; } /** * Get the minimum fee ($0.50) */ public getMinFee(): number { return this.MIN_FEE; } /** * Get the maximum fee ($10.00) */ public getMaxFee(): number { return this.MAX_FEE; } } /** * Create a default fee calculator instance * * @returns FeeCalculator instance * * @example * ```typescript * import { createFeeCalculator } from './FeeCalculator'; * * const calculator = createFeeCalculator(); * const fee = calculator.estimateFeeInAsset(100000000); // 100 TUSDT * console.log(`Fee: $${fee.feeUsd}`); // $0.50 (minimum applies) * ``` */ export function createFeeCalculator(): FeeCalculator { return new FeeCalculator(); }