import { CoinDenom , coinDenomToName , IFiatPrice , NetworkDefinition , } from "@anthem/utils" ; import { ChartData } from "./chart-utils" ; import { getFiatPriceHistoryMap , isGraphQLResponseDataEmpty , } from "./client-utils" ; import { getChartTotalGraph , PortfolioHistoryChartData , } from "./cosmos-chart-utils" ; import { add , multiply , subtract } from "./math-utils" ; /** ===========================================================================
 * CSV Utils
 * ============================================================================
 */ export const chartExportBuilder = ( { address , network , fiatPriceHistory , fiatCurrencySymbol , portfolioChartHistory , supportsFiatPrices , selectedDenom , } ) : string => { const { availableChartData , rewardsChartData , delegationsChartData , unbondingChartData , validatorRewardsChartData , validatorDailySummary , } = portfolioChartHistory ; const chartTotal = getChartTotalGraph ( portfolioChartHistory ) ; const INCLUDE_VALIDATOR_COMMISSIONS = ! isGraphQLResponseDataEmpty ( validatorRewardsChartData . data ) ; const fiatPriceMap = getFiatPriceHistoryMap ( fiatPriceHistory , "MMM DD, YYYY" ) ; const setFiatValue = ( value ) => { if ( supportsFiatPrices ) { return String ( value ) ; } else { return "n/a" ; } } ; const balanceMapByTime = availableChartData . data ; const { denom } = selectedDenom ; const coin = coinDenomToName ( denom ) ; let CSV_HEADERS = [ "Timestamp" , `Exchange Rate (${ coin }:${ fiatCurrencySymbol })` , `Total Balance (${ coin })` , `Available Balance (${ coin })` , `Staked Balance (${ coin })` , `Unbonded Balance (${ coin })` , `Daily Rewards (${ coin })` , `Daily Rewards (${ fiatCurrencySymbol })` , `Accumulated Rewards (${ coin })` , `Reward Withdrawals (${ coin })` , `Reward Pool (${ coin })` , ] ; if ( INCLUDE_VALIDATOR_COMMISSIONS ) { CSV_HEADERS = CSV_HEADERS . concat ( [ `Daily Commissions (${ coin })` , `Daily Commissions (${ fiatCurrencySymbol })` , `Accumulated Commissions (${ coin })` , `Commission Withdrawals (${ coin })` , `Commissions Pool (${ coin })` , ] ) ; } const ADDRESS_INFO = `Account history data for ${ network . name } address ${ address }.\n` ; const DENOM_INFO = `Displaying account history for ${ coin } denomination.\n` ; const FIAT_PRICE_INFO = ! supportsFiatPrices ? "Fiat exchange rate history is not supported for this denomination.\n" : "" ; const INFO = `${ ADDRESS_INFO }${ DENOM_INFO }${ FIAT_PRICE_INFO }\n` ; const DISCLAIMER = `[DISCLAIMER]: This CSV account history is a best approximation of the account balances and rewards data over time. It is not a perfect history and uses a 3rd party price feed for exchange price data.\n\n` ; let CSV = `${ INFO }${ DISCLAIMER }${ CSV_HEADERS . join ( "," ) }\n` ; let accumulatedWithdrawals = 0 ; let rewardsPool = 0 ; let lastRewards = 0 ; const validatorFieldsMap = getValidatorRewardsCSVFields ( validatorRewardsChartData ) ; Object . entries ( rewardsChartData . data ) . forEach ( ( [ timestamp , atomRewards ] ) => { const time = timestamp ; const fiatPrice = fiatPriceMap [ timestamp ] ; let withdrawalsATOM = "" ; if ( rewardsChartData . withdrawalsMap && timestamp in rewardsChartData . withdrawalsMap ) { withdrawalsATOM = rewardsChartData . withdrawalsMap [ timestamp ] ; accumulatedWithdrawals = add ( accumulatedWithdrawals , withdrawalsATOM , Number ) ; } const accumulatedRewards = rewardsChartData . data [ timestamp ] ; const currentRewards = subtract ( accumulatedRewards , lastRewards , Number ) ; lastRewards = accumulatedRewards ; const fiatRewards = multiply ( currentRewards , fiatPrice ) ; rewardsPool = subtract ( atomRewards , accumulatedWithdrawals , Number ) ; let balanceValue = 0 ; if ( time in balanceMapByTime ) { balanceValue = balanceMapByTime [ time ] || 0 ; } const withdrawals = Boolean ( withdrawalsATOM ) ? withdrawalsATOM : "" ; let delegationsValue = 0 ; if ( time in delegationsChartData . data ) { delegationsValue = delegationsChartData . data [ time ] ; } let unbondingsValue = 0 ; if ( time in unbondingChartData . data ) { unbondingsValue = unbondingChartData . data [ time ] ; } let validatorFields = null ; let validatorCommissions = 0 ; if ( INCLUDE_VALIDATOR_COMMISSIONS && timestamp in validatorFieldsMap ) { validatorFields = validatorFieldsMap [ timestamp ] ; validatorCommissions = validatorDailySummary . data [ timestamp ] ; } const totalValue = chartTotal . data [ timestamp ] ; let CSV_DATA = [ timestamp . replace ( "," , "" ) , setFiatValue ( fiatPrice ) , totalValue , balanceValue , delegationsValue , unbondingsValue , currentRewards , setFiatValue ( fiatRewards ) , accumulatedRewards , withdrawals , rewardsPool , ] . map ( String ) ; if ( validatorFields ) { validatorCommissions = Number ( validatorFields . atomRewards ) ; const validatorCommissionsFiat = multiply ( validatorCommissions , fiatPrice ) ; CSV_DATA = CSV_DATA . concat ( [ String ( validatorCommissions ) , setFiatValue ( validatorCommissionsFiat ) , validatorFields . accumulatedRewards , validatorFields . withdrawals , validatorFields . commissionsPool , ] ) ; } CSV += `${ CSV_DATA . join ( "," ) }\n` ; } ) ; return CSV ; } ; const getValidatorRewardsCSVFields = ( validatorRewardsATOM ) : { [ key ] : { accumulatedRewards : string ; atomRewards : string ; withdrawals : string ; commissionsPool : string ; } ; } => { let result = { } ; let commissionsPool = 0 ; let accumulatedWithdrawals = 0 ; let currentCommissions = 0 ; let lastCommissions = 0 ; Object . entries ( validatorRewardsATOM . data ) . forEach ( ( [ timestamp , atomCommissions ] ) => { currentCommissions = subtract ( atomCommissions , lastCommissions , Number ) ; lastCommissions = atomCommissions ; let withdrawalsATOM = "" ; if ( validatorRewardsATOM . withdrawalsMap && timestamp in validatorRewardsATOM . withdrawalsMap ) { withdrawalsATOM = validatorRewardsATOM . withdrawalsMap [ timestamp ] ; accumulatedWithdrawals = add ( accumulatedWithdrawals , withdrawalsATOM , Number ) ; } commissionsPool = subtract ( atomCommissions , accumulatedWithdrawals , Number ) ; const withdrawals = Boolean ( withdrawalsATOM ) ? withdrawalsATOM : "" ; const validatorFields = { accumulatedRewards : String ( atomCommissions ) , atomRewards : String ( currentCommissions ) , withdrawals : String ( withdrawals ) , commissionsPool : String ( commissionsPool ) , } ; result = { ... result , [ timestamp ] : validatorFields , } ; } ) ; return result ; } ;