Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

Commit

Permalink
1206/adjusting exported csv (#1218)
Browse files Browse the repository at this point in the history
* Inverting limit and fill prices on csv export

* Added new csv column with the unit for each price

* Added inverse limit and fill price columns

* Added Sold and Bought unit columns

* Added Fill % conlumn

* Added Total Order Amount column

* Capitalize all columns

* One Unit column per price group

* Price units were inverted...

* Moved helper functions to utils

* Liquidity trades fill% and total order amount have unlimited on csv

Co-authored-by: Leandro Boscariol <leandro.boscariol@gnosis.io>
  • Loading branch information
alfetopito and Leandro Boscariol authored Jul 13, 2020
1 parent 62ba9eb commit dd25a6b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 40 deletions.
31 changes: 3 additions & 28 deletions src/components/TradesWidget/TradeRow.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo } from 'react'
import styled from 'styled-components'
import BigNumber from 'bignumber.js'
import { formatDistanceStrict } from 'date-fns'

import { formatPrice, formatSmart, formatAmountFull, invertPrice, DEFAULT_PRECISION } from '@gnosis.pm/dex-js'
Expand All @@ -10,9 +9,9 @@ import { Trade, TradeType } from 'api/exchange/ExchangeApi'
import { EtherscanLink } from 'components/EtherscanLink'
import { FoldableRowWrapper } from 'components/Layout/Card'

import { isTradeSettled } from 'utils'
import { isTradeSettled, divideBN, formatPercentage } from 'utils'
import { displayTokenSymbolOrLink } from 'utils/display'
import { ONE_HUNDRED_BIG_NUMBER, MEDIA } from 'const'
import { MEDIA } from 'const'

const TradeRowFoldableWrapper = styled(FoldableRowWrapper)`
@media ${MEDIA.mobile} {
Expand Down Expand Up @@ -62,28 +61,6 @@ const TypePill = styled.span<{
text-transform: uppercase;
`

// TODO: move to dex-js
/**
* Formats percentage values with 2 decimals of precision.
* Adds `%` at the end
* Adds `<` at start when smaller than 0.01
* Adds `>` at start when greater than 99.99
*
* @param percentage Raw percentage value. E.g.: 50% == 0.5
*/
function formatPercentage(percentage: BigNumber): string {
const displayPercentage = percentage.times(ONE_HUNDRED_BIG_NUMBER)
let result = ''
if (!displayPercentage.gte('0.01')) {
result = '<0.01'
} else if (displayPercentage.gt('99.99')) {
result = '>99.99'
} else {
result = displayPercentage.decimalPlaces(2, BigNumber.ROUND_FLOOR).toString(10)
}
return result + '%'
}

export const TradeRow: React.FC<TradeRowProps> = params => {
const { trade, networkId } = params
const {
Expand Down Expand Up @@ -114,9 +91,7 @@ export const TradeRow: React.FC<TradeRowProps> = params => {
case 'full':
case 'partial': {
if (orderSellAmount) {
const fillPercentage = formatPercentage(
new BigNumber(sellAmount.toString()).dividedBy(new BigNumber(orderSellAmount.toString())),
)
const fillPercentage = formatPercentage(divideBN(sellAmount, orderSellAmount))
const orderAmount = formatSmart({
amount: orderSellAmount,
precision: sellTokenDecimals,
Expand Down
50 changes: 38 additions & 12 deletions src/components/TradesWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faFileCsv } from '@fortawesome/free-solid-svg-icons'
import styled from 'styled-components'

import { formatPrice, TokenDetails, formatAmount } from '@gnosis.pm/dex-js'
import { formatPrice, formatAmount, invertPrice, formatAmountFull } from '@gnosis.pm/dex-js'

import FilterTools from 'components/FilterTools'
import { CardTable, CardWidgetWrapper } from 'components/Layout/Card'
Expand All @@ -22,7 +22,8 @@ import { Trade } from 'api/exchange/ExchangeApi'
import { toCsv, CsvColumns } from 'utils/csv'
import { filterTradesFn } from 'utils/filter'

import { getNetworkFromId, isTradeSettled, isTradeReverted } from 'utils'
import { getNetworkFromId, isTradeSettled, isTradeReverted, divideBN } from 'utils'
import { symbolOrAddress } from 'utils/display'

const CsvButtonContainer = styled.div`
display: flex;
Expand All @@ -36,10 +37,6 @@ const SplitHeaderTitle = styled.div`
flex-flow: column;
`

function symbolOrAddress(token: TokenDetails): string {
return token.symbol || token.address
}

function csvTransformer(trade: Trade): CsvColumns {
const {
buyToken,
Expand All @@ -48,13 +45,33 @@ function csvTransformer(trade: Trade): CsvColumns {
fillPrice,
sellAmount,
buyAmount,
orderSellAmount,
timestamp,
txHash,
eventIndex,
orderId,
batchId,
} = trade

const limitPriceStr = limitPrice ? formatPrice({ price: invertPrice(limitPrice), decimals: 8 }) : 'N/A'
const inverseLimitPriceStr = limitPrice ? formatPrice({ price: limitPrice, decimals: 8 }) : 'N/A'
const fillPriceStr = formatPrice({ price: invertPrice(fillPrice), decimals: 8 })
const inverseFillPriceStr = formatPrice({ price: fillPrice, decimals: 8 })

let fillPercentage = 'N/A'
let totalOrderAmount = 'N/A'
if (trade.type === 'liquidity') {
fillPercentage = 'unlimited'
totalOrderAmount = 'unlimited'
} else if (orderSellAmount) {
fillPercentage = divideBN(sellAmount, orderSellAmount).toString(10)
totalOrderAmount = formatAmountFull({
amount: orderSellAmount,
precision: sellToken.decimals,
thousandSeparator: false,
})
}

// The order of the keys defines csv column order,
// as well as names and whether to include it or not.
// We can optionally define an interface for that.
Expand All @@ -63,27 +80,36 @@ function csvTransformer(trade: Trade): CsvColumns {
return {
Date: new Date(timestamp).toISOString(),
Market: `${symbolOrAddress(buyToken)}/${symbolOrAddress(sellToken)}`,
'Buy Token symbol': buyToken.symbol || '',
'Buy Token address': buyToken.address,
'Sell Token symbol': sellToken.symbol || '',
'Sell Token address': sellToken.address,
'Limit Price': limitPrice ? formatPrice({ price: limitPrice, decimals: 8 }) : 'N/A',
'Fill Price': formatPrice({ price: fillPrice, decimals: 8 }),
'Buy Token Symbol': buyToken.symbol || '',
'Buy Token Address': buyToken.address,
'Sell Token Symbol': sellToken.symbol || '',
'Sell Token Address': sellToken.address,
'Limit Price': limitPriceStr,
'Fill Price': fillPriceStr,
'Price Unit': symbolOrAddress(sellToken),
'Inverse Limit Price': inverseLimitPriceStr,
'Inverse Fill Price': inverseFillPriceStr,
'Inverse Price Unit': symbolOrAddress(buyToken),
Sold: formatAmount({
amount: sellAmount,
precision: sellToken.decimals as number,
decimals: sellToken.decimals,
thousandSeparator: false,
isLocaleAware: false,
}),
'Sold Unit': symbolOrAddress(sellToken),
Bought: formatAmount({
amount: buyAmount,
precision: buyToken.decimals as number,
decimals: sellToken.decimals,
thousandSeparator: false,
isLocaleAware: false,
}),
'Bought Unit': symbolOrAddress(buyToken),
Type: trade.type || '',
'Fill %': fillPercentage,
'Total Order Amount': totalOrderAmount,
'Total Order Amount Unit': symbolOrAddress(sellToken),
'Transaction Hash': txHash,
'Event Log Index': eventIndex.toString(),
'Order Id': orderId,
Expand Down
4 changes: 4 additions & 0 deletions src/utils/display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export function displayTokenSymbolOrLink(token: TokenDetails): React.ReactNode |
return displayName
}

export function symbolOrAddress(token: TokenDetails): string {
return token.symbol || token.address
}

/**
* computeMarketProp
* @description returns array of potentially accepted market names by:: BUYTOKEN <SEPARATOR> SELLTOKEN
Expand Down
23 changes: 23 additions & 0 deletions src/utils/format.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BigNumber from 'bignumber.js'
import { ONE_HUNDRED_BIG_NUMBER } from 'const'

export {
formatSmart,
Expand Down Expand Up @@ -98,3 +99,25 @@ export const formatTimeToFromBatch = (
returnType: 'TIME' | 'BATCH' = 'TIME',
batchLength = 5,
): number => (returnType === 'TIME' ? Number(value) * batchLength : Number(value) / batchLength)

// TODO: move to dex-js
/**
* Formats percentage values with 2 decimals of precision.
* Adds `%` at the end
* Adds `<` at start when smaller than 0.01
* Adds `>` at start when greater than 99.99
*
* @param percentage Raw percentage value. E.g.: 50% == 0.5
*/
export function formatPercentage(percentage: BigNumber): string {
const displayPercentage = percentage.times(ONE_HUNDRED_BIG_NUMBER)
let result = ''
if (!displayPercentage.gte('0.01')) {
result = '<0.01'
} else if (displayPercentage.gt('99.99')) {
result = '>99.99'
} else {
result = displayPercentage.decimalPlaces(2, BigNumber.ROUND_FLOOR).toString(10)
}
return result + '%'
}
5 changes: 5 additions & 0 deletions src/utils/miscellaneous.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BN from 'bn.js'
import BigNumber from 'bignumber.js'

import { TokenDetails, Unpromise } from 'types'
import { AssertionError } from 'assert'
Expand Down Expand Up @@ -187,3 +188,7 @@ export function flattenMapOfLists<K, T>(map: Map<K, T[]>): T[] {
export function flattenMapOfSets<K, T>(map: Map<K, Set<T>>): T[] {
return Array.from(map.values()).reduce<T[]>((acc, set) => acc.concat(Array.from(set)), [])
}

export function divideBN(numerator: BN, denominator: BN): BigNumber {
return new BigNumber(numerator.toString()).dividedBy(denominator.toString())
}

0 comments on commit dd25a6b

Please sign in to comment.