@@ -27,6 +27,7 @@ import {
2727 CreateOrderPayloadSchema ,
2828 DepositPayloadSchema ,
2929 FetchDepositAddressesPayloadSchema ,
30+ FetchFeesPayloadSchema ,
3031 GetOrderDetailsPayloadSchema ,
3132 WithdrawPayloadSchema ,
3233} from "./schemas/action-payloads" ;
@@ -338,21 +339,160 @@ export function getServer(
338339 null ,
339340 ) ;
340341 }
342+ const parsedPayload = parsePayload (
343+ FetchFeesPayloadSchema ,
344+ call . request . payload ,
345+ ) ;
346+ if ( ! parsedPayload . success ) {
347+ return wrappedCallback (
348+ {
349+ code : grpc . status . INVALID_ARGUMENT ,
350+ message : parsedPayload . message ,
351+ } ,
352+ null ,
353+ ) ;
354+ }
355+ const includeAllFees =
356+ parsedPayload . data . includeAllFees ||
357+ parsedPayload . data . includeFundingFees === true ;
341358 try {
342359 await broker . loadMarkets ( ) ;
343- const market = await broker . market ( symbol ) ;
360+ const fetchFundingFees = async ( currencyCodes : string [ ] ) => {
361+ let fundingFeeSource :
362+ | "fetchDepositWithdrawFees"
363+ | "currencies"
364+ | "unavailable" = "unavailable" ;
365+ const fundingFeesByCurrency : Record < string , unknown > = { } ;
366+
367+ if ( broker . has . fetchDepositWithdrawFees ) {
368+ try {
369+ const feeMap = ( await broker . fetchDepositWithdrawFees (
370+ currencyCodes ,
371+ ) ) as unknown as Record <
372+ string ,
373+ {
374+ deposit ?: unknown ;
375+ withdraw ?: unknown ;
376+ networks ?: unknown ;
377+ fee ?: number ;
378+ percentage ?: boolean ;
379+ }
380+ > ;
381+ for ( const code of currencyCodes ) {
382+ const feeInfo = feeMap [ code ] ;
383+ if ( ! feeInfo ) {
384+ continue ;
385+ }
386+ const fallbackFee =
387+ feeInfo . fee !== undefined ||
388+ feeInfo . percentage !== undefined
389+ ? {
390+ fee : feeInfo . fee ?? null ,
391+ percentage : feeInfo . percentage ?? null ,
392+ }
393+ : null ;
394+ fundingFeesByCurrency [ code ] = {
395+ deposit : feeInfo . deposit ?? fallbackFee ,
396+ withdraw : feeInfo . withdraw ?? fallbackFee ,
397+ networks : feeInfo . networks ?? { } ,
398+ } ;
399+ }
400+ if ( Object . keys ( fundingFeesByCurrency ) . length > 0 ) {
401+ fundingFeeSource = "fetchDepositWithdrawFees" ;
402+ }
403+ } catch ( error ) {
404+ safeLogError (
405+ `Error fetching deposit/withdraw fee map for ${ symbol } from ${ cex } ` ,
406+ error ,
407+ ) ;
408+ }
409+ }
344410
345- // Address CodeRabbit's concern: explicit handling for missing fees
346- const generalFee = broker . fees ?? null ;
347- const feeStatus = broker . fees ? "available" : "unknown" ;
411+ if ( fundingFeeSource === "unavailable" ) {
412+ try {
413+ const currencies = await broker . fetchCurrencies ( ) ;
414+ for ( const code of currencyCodes ) {
415+ const currency = currencies [ code ] ;
416+ if ( ! currency ) {
417+ continue ;
418+ }
419+ fundingFeesByCurrency [ code ] = {
420+ deposit : {
421+ enabled : currency . deposit ?? null ,
422+ } ,
423+ withdraw : {
424+ enabled : currency . withdraw ?? null ,
425+ fee : currency . fee ?? null ,
426+ limits : currency . limits ?. withdraw ?? null ,
427+ } ,
428+ networks : currency . networks ?? { } ,
429+ } ;
430+ }
431+ if ( Object . keys ( fundingFeesByCurrency ) . length > 0 ) {
432+ fundingFeeSource = "currencies" ;
433+ }
434+ } catch ( error ) {
435+ safeLogError (
436+ `Error fetching currency metadata for fees for ${ symbol } from ${ cex } ` ,
437+ error ,
438+ ) ;
439+ }
440+ }
441+
442+ return { fundingFeeSource, fundingFeesByCurrency } ;
443+ } ;
444+
445+ const isMarketSymbol = symbol . includes ( "/" ) ;
446+ if ( isMarketSymbol ) {
447+ const market = await broker . market ( symbol ) ;
448+ const generalFee = broker . fees ?? null ;
449+ const feeStatus = broker . fees ? "available" : "unknown" ;
450+
451+ if ( ! broker . fees ) {
452+ log . warn ( `Fee metadata unavailable for ${ cex } ` , { symbol } ) ;
453+ }
454+
455+ if ( ! includeAllFees ) {
456+ return wrappedCallback ( null , {
457+ proof : verityProof ,
458+ result : JSON . stringify ( {
459+ feeScope : "market" ,
460+ generalFee,
461+ feeStatus,
462+ market,
463+ } ) ,
464+ } ) ;
465+ }
348466
349- if ( ! broker . fees ) {
350- log . warn ( `Fee metadata unavailable for ${ cex } ` , { symbol } ) ;
467+ const currencyCodes = Array . from (
468+ new Set ( [ market . base , market . quote ] ) ,
469+ ) ;
470+ const { fundingFeeSource, fundingFeesByCurrency } =
471+ await fetchFundingFees ( currencyCodes ) ;
472+ return wrappedCallback ( null , {
473+ proof : verityProof ,
474+ result : JSON . stringify ( {
475+ feeScope : "market+funding" ,
476+ generalFee,
477+ feeStatus,
478+ market,
479+ fundingFeeSource,
480+ fundingFeesByCurrency,
481+ } ) ,
482+ } ) ;
351483 }
352484
485+ const tokenCode = symbol . toUpperCase ( ) ;
486+ const { fundingFeeSource, fundingFeesByCurrency } =
487+ await fetchFundingFees ( [ tokenCode ] ) ;
353488 return wrappedCallback ( null , {
354489 proof : verityProof ,
355- result : JSON . stringify ( { generalFee, feeStatus, market } ) ,
490+ result : JSON . stringify ( {
491+ feeScope : "token" ,
492+ symbol : tokenCode ,
493+ fundingFeeSource,
494+ fundingFeesByCurrency,
495+ } ) ,
356496 } ) ;
357497 } catch ( error ) {
358498 safeLogError (
0 commit comments