From 75fec885fa5ef33a0d961c333be2980ede7d51c6 Mon Sep 17 00:00:00 2001 From: vstudio79 Date: Thu, 28 May 2026 19:27:24 +0100 Subject: [PATCH] Add calculateAnchorFee function - Create FeeQuote, FeeBreakdown, and TransactionType interfaces - Support asset-specific fee schedules (flat + percentage) - Return detailed fee breakdown with effective rate - Generate unique quote IDs with 60-second expiry --- packages/anchor-service/src/anchor.service.ts | 64 +++++++++++++++++++ packages/anchor-service/src/index.ts | 1 + .../src/interfaces/fee.interface.ts | 19 ++++++ 3 files changed, 84 insertions(+) create mode 100644 packages/anchor-service/src/interfaces/fee.interface.ts diff --git a/packages/anchor-service/src/anchor.service.ts b/packages/anchor-service/src/anchor.service.ts index 6e9de31..88273ea 100644 --- a/packages/anchor-service/src/anchor.service.ts +++ b/packages/anchor-service/src/anchor.service.ts @@ -14,6 +14,7 @@ import type { CustomerStatus, IdentityDocument, } from './interfaces/customer.interface'; +import type { FeeQuote, TransactionType } from './interfaces/fee.interface'; interface CustomerRecord { customerId: string; @@ -303,6 +304,69 @@ export class AnchorService { return Array.from(this.customers.values()); } + // --------------------------------------------------------------------------- + // Fee Calculation + // --------------------------------------------------------------------------- + + private readonly feeSchedule: Record = { + USDC: { flat: '1.00', percentage: '0' }, + USDT: { flat: '1.00', percentage: '0' }, + BTC: { flat: '0.0001', percentage: '0.5' }, + ETH: { flat: '0.001', percentage: '0.3' }, + XLM: { flat: '0.01', percentage: '0' }, + }; + + async calculateAnchorFee( + amount: string, + asset: string, + type: TransactionType, + ): Promise { + const schedule = this.feeSchedule[asset] ?? { flat: '0', percentage: '1' }; + const parsedAmount = parseFloat(amount); + + if (isNaN(parsedAmount) || parsedAmount <= 0) { + throw new Error(`Invalid amount: ${amount}`); + } + + const breakdown: FeeQuote['feeBreakdown'] = []; + + let totalFee = 0; + + if (schedule.flat !== '0') { + const flatFee = parseFloat(schedule.flat); + totalFee += flatFee; + breakdown.push({ + type: 'flat', + description: `Flat fee for ${asset}`, + amount: schedule.flat, + }); + } + + if (schedule.percentage !== '0') { + const percentageFee = parsedAmount * (parseFloat(schedule.percentage) / 100); + totalFee += percentageFee; + breakdown.push({ + type: 'percentage', + description: `${schedule.percentage}% fee on ${asset}`, + amount: percentageFee.toFixed(7), + }); + } + + const effectiveRate = parsedAmount > 0 ? ((totalFee / parsedAmount) * 100).toFixed(4) : '0'; + + return { + totalFee: totalFee.toFixed(7), + asset, + type, + amount, + feeBreakdown: breakdown, + effectiveRate: `${effectiveRate}%`, + quoteId: `fee_${crypto.randomUUID().split('-').join('').slice(0, 16)}`, + expiresAt: new Date(Date.now() + 60_000).toISOString(), + createdAt: new Date().toISOString(), + }; + } + private validateRequiredFields(data: CustomerData, isUpdate: boolean): string[] { const missing: string[] = []; diff --git a/packages/anchor-service/src/index.ts b/packages/anchor-service/src/index.ts index 7f700c4..28d622c 100644 --- a/packages/anchor-service/src/index.ts +++ b/packages/anchor-service/src/index.ts @@ -17,3 +17,4 @@ export type { IdentityDocument, FileContent, } from './interfaces/customer.interface'; +export type { FeeQuote, FeeBreakdown, TransactionType } from './interfaces/fee.interface'; diff --git a/packages/anchor-service/src/interfaces/fee.interface.ts b/packages/anchor-service/src/interfaces/fee.interface.ts new file mode 100644 index 0000000..2bde8a89 --- /dev/null +++ b/packages/anchor-service/src/interfaces/fee.interface.ts @@ -0,0 +1,19 @@ +export type TransactionType = 'deposit' | 'withdrawal' | 'send'; + +export interface FeeBreakdown { + type: 'flat' | 'percentage'; + description: string; + amount: string; +} + +export interface FeeQuote { + totalFee: string; + asset: string; + type: TransactionType; + amount: string; + feeBreakdown: FeeBreakdown[]; + effectiveRate: string; + quoteId: string; + expiresAt: string; + createdAt: string; +}