Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

[USD Price] Add coingecko api and hooks #1356

Merged
merged 16 commits into from
Sep 7, 2021
98 changes: 98 additions & 0 deletions src/custom/api/coingecko/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { SupportedChainId as ChainId } from 'constants/chains'
import { PriceInformation } from 'utils/price'

function getApiUrl(): string {
// it's all the same base url
return 'https://api.coingecko.com/api'
}

// https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses=0x33e18a092a93ff21ad04746c7da12e35d34dc7c4&vs_currencies=usd
// Defaults
const API_NAME = 'Coingecko'
const API_BASE_URL = getApiUrl()
const API_VERSION = 'v3'
const DEFAULT_HEADERS = {
'Content-Type': 'application/json',
}

function _getApiBaseUrl(chainId: ChainId): string {
const baseUrl = API_BASE_URL

if (!baseUrl) {
throw new Error(`Unsupported Network. The ${API_NAME} API is not deployed in the Network ${chainId}`)
} else {
return baseUrl + '/' + API_VERSION
}
}

function _getCoinGeckoAssetPlatform(chainId: ChainId) {
switch (chainId) {
// Use of asset platforms - supports ethereum and xdai
// https://api.coingecko.com/api/v3/asset_platforms
case ChainId.MAINNET:
return 'ethereum'
case ChainId.XDAI:
return 'xdai'
default:
return null
}
}

function _fetch(chainId: ChainId, url: string, method: 'GET' | 'POST' | 'DELETE', data?: any): Promise<Response> {
const baseUrl = _getApiBaseUrl(chainId)
return fetch(baseUrl + url, {
headers: DEFAULT_HEADERS,
method,
body: data !== undefined ? JSON.stringify(data) : data,
})
}

// TODO: consider making these _get/_delete/_post etc reusable across apis
function _get(chainId: ChainId, url: string): Promise<Response> {
return _fetch(chainId, url, 'GET')
}

export interface CoinGeckoUsdPriceParams {
chainId: ChainId
tokenAddress: string
}

interface CoinGeckoUsdQuote {
[address: string]: {
usd: number
}
}

export async function getUSDPriceQuote(params: CoinGeckoUsdPriceParams): Promise<CoinGeckoUsdQuote | null> {
const { chainId, tokenAddress } = params
// ethereum/xdai (chains)
const assetPlatform = _getCoinGeckoAssetPlatform(chainId)
if (assetPlatform == null) {
// Unsupported
return null
}

console.log(`[api:${API_NAME}] Get USD price from ${API_NAME}`, params)

const response = await _get(
chainId,
`/simple/token_price/${assetPlatform}?contract_addresses=${tokenAddress}&vs_currencies=usd`
).catch((error) => {
console.error(`Error getting ${API_NAME} USD price quote:`, error)
throw new Error(error)
})

return response.json()
}

export function toPriceInformation(priceRaw: CoinGeckoUsdQuote | null): PriceInformation | null {
// We only receive/want the first key/value pair in the return object
const token = priceRaw ? Object.keys(priceRaw)[0] : null

if (!token || !priceRaw?.[token].usd) {
return null
}

const { usd } = priceRaw[token]
return { amount: usd.toString(), token }
}
16 changes: 13 additions & 3 deletions src/custom/components/swap/FeeInformationTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import React, { useMemo } from 'react'
import TradeGp from 'state/swap/TradeGp'
import QuestionHelper from 'components/QuestionHelper'
import styled from 'styled-components'
import { useUSDCValue } from 'hooks/useUSDCPrice'
import { formatSmart } from 'utils/format'
import useTheme from 'hooks/useTheme'
import { FIAT_PRECISION } from 'constants/index'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'

interface FeeInformationTooltipProps {
trade?: TradeGp
Expand All @@ -15,6 +15,7 @@ interface FeeInformationTooltipProps {
amountAfterFees?: string
feeAmount?: string
type: 'From' | 'To'
fiatValue: CurrencyAmount<Token> | null
showFiat?: boolean
}

Expand Down Expand Up @@ -73,10 +74,19 @@ const FeeInnerWrapper = styled.div`
`

export default function FeeInformationTooltip(props: FeeInformationTooltipProps) {
const { trade, label, amountBeforeFees, amountAfterFees, feeAmount, type, showHelper, showFiat = false } = props
const {
trade,
label,
amountBeforeFees,
amountAfterFees,
feeAmount,
type,
showHelper,
fiatValue,
showFiat = false,
} = props

const theme = useTheme()
const fiatValue = useUSDCValue(type === 'From' ? trade?.inputAmount : trade?.outputAmount)

const [symbol, fullFeeAmount] = useMemo(() => {
const amount = trade?.[type === 'From' ? 'inputAmount' : 'outputAmount']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, { useState, useContext, useMemo } from 'react'
import { ArrowDown, AlertTriangle } from 'react-feather'
import { Text } from 'rebass'
import styled, { ThemeContext } from 'styled-components'
import { useUSDCValue } from 'hooks/useUSDCPrice'
import { useHigherUSDValue /* , useUSDCValue */ } from 'hooks/useUSDCPrice'
import { TYPE } from 'theme'
import { ButtonPrimary } from 'components/Button'
import { isAddress, shortenAddress } from 'utils'
Expand Down Expand Up @@ -89,8 +89,10 @@ SwapModalHeaderProps) {
const [showInverted, setShowInverted] = useState<boolean>(false)

// show fiatValue for unadjusted trade amounts!
const fiatValueInput = useUSDCValue(trade.inputAmountWithoutFee)
const fiatValueOutput = useUSDCValue(trade.outputAmountWithoutFee)
// const fiatValueInput = useUSDCValue(trade.inputAmountWithoutFee)
// const fiatValueOutput = useUSDCValue(trade.outputAmountWithoutFee)
const fiatValueInput = useHigherUSDValue(trade.inputAmountWithoutFee)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

higher or highest?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well technically "highest" would mean just that, the "highest" whereas "higher" implies of the choices given, which is "highest"

but yes it's very nitpicky here. happy to change it to whatever we like best @alfetopito @Anxo @nenadV91

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whatever

const fiatValueOutput = useHigherUSDValue(trade.outputAmountWithoutFee)

const [slippageIn, slippageOut] = useMemo(
() => [slippageAdjustedAmounts[Field.INPUT], slippageAdjustedAmounts[Field.OUTPUT]],
Expand Down Expand Up @@ -148,6 +150,7 @@ SwapModalHeaderProps) {
showHelper
trade={trade}
type="From"
fiatValue={fiatValueInput}
/>
</AuxInformationContainer>
)}
Expand Down Expand Up @@ -200,6 +203,7 @@ SwapModalHeaderProps) {
showHelper
trade={trade}
type="To"
fiatValue={fiatValueOutput}
/>
</AuxInformationContainer>
)}
Expand Down
5 changes: 3 additions & 2 deletions src/custom/components/swap/TradePrice/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react'
import TradePriceMod, { TradePriceProps } from './TradePriceMod'
import { useUSDCValue } from 'hooks/useUSDCPrice'
import { useHigherUSDValue /* useUSDCValue */ } from 'hooks/useUSDCPrice'
import { formatSmart } from 'utils/format'
import { tryParseAmount } from 'state/swap/hooks'
import { FIAT_PRECISION } from 'constants/index'
Expand All @@ -17,7 +17,8 @@ export default function TradePrice(props: Omit<TradePriceProps, 'fiatValue'>) {
: tryParseAmount(price.toFixed(price.quoteCurrency.decimals), price.quoteCurrency),
[price, showInverted]
)
const amount = useUSDCValue(priceSide)
// const amount = useUSDCValue(priceSide)
const amount = useHigherUSDValue(priceSide)
const fiatValueFormatted = formatSmart(amount, FIAT_PRECISION)

return <TradePriceMod {...props} fiatValue={fiatValueFormatted} />
Expand Down
8 changes: 3 additions & 5 deletions src/custom/components/swap/TradeSummary/RowFee.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useContext } from 'react'
import { CurrencyAmount, Currency, TradeType } from '@uniswap/sdk-core'
import { CurrencyAmount, Currency, TradeType, Token } from '@uniswap/sdk-core'
import { ThemeContext } from 'styled-components'
import { TYPE } from 'theme'

Expand All @@ -10,7 +10,6 @@ import { RowBetween, RowFixed } from 'components/Row'
import { MouseoverTooltipContent } from 'components/Tooltip'
import { AMOUNT_PRECISION, FIAT_PRECISION } from 'constants/index'
import { LightGreyText } from 'pages/Swap'
import { useUSDCValue } from 'hooks/useUSDCPrice'

export const GASLESS_FEE_TOOLTIP_MSG =
'On CowSwap you sign your order (hence no gas costs!). The fees are covering your gas costs already.'
Expand Down Expand Up @@ -39,7 +38,7 @@ export interface RowFeeProps {
// Even for invalid trades, we want to display the fee, this is why there's another "fee" parameter
trade?: TradeGp
fee?: CurrencyAmount<Currency>

feeFiatValue: CurrencyAmount<Token> | null
showHelpers: boolean
allowsOffchainSigning: boolean
fontWeight?: number
Expand All @@ -50,6 +49,7 @@ export interface RowFeeProps {
export function RowFee({
trade,
fee,
feeFiatValue,
allowsOffchainSigning,
showHelpers,
fontSize = 14,
Expand All @@ -60,8 +60,6 @@ export function RowFee({
const { realizedFee } = React.useMemo(() => computeTradePriceBreakdown(trade), [trade])
// trades are null when there is a fee quote error e.g
// so we can take both
const feeAmount = trade?.fee.feeAsCurrency || fee
const feeFiatValue = useUSDCValue(feeAmount)
const feeFiatDisplay = `(≈$${formatSmart(feeFiatValue, FIAT_PRECISION)})`

const displayFee = realizedFee || fee
Expand Down
3 changes: 3 additions & 0 deletions src/custom/components/swap/TradeSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { RowFixed } from 'components/Row'
import { RowFee } from './RowFee'
import { RowSlippage } from './RowSlippage'
import { RowReceivedAfterSlippage } from './RowReceivedAfterSlippage'
import { useHigherUSDValue } from 'hooks/useUSDCPrice'

const Wrapper = styled.div`
${RowFixed} {
Expand All @@ -22,6 +23,7 @@ export type TradeSummaryProps = Required<AdvancedSwapDetailsProps>

export default function TradeSummary({ trade, allowedSlippage, showHelpers, showFee }: TradeSummaryProps) {
const allowsOffchainSigning = true // TODO: Next PR will handle this
const feeFiatValue = useHigherUSDValue(trade.fee.feeAsCurrency)

return (
<Wrapper>
Expand All @@ -30,6 +32,7 @@ export default function TradeSummary({ trade, allowedSlippage, showHelpers, show
{showFee && (
<RowFee
trade={trade}
feeFiatValue={feeFiatValue}
allowsOffchainSigning={allowsOffchainSigning}
showHelpers={showHelpers}
fontSize={12}
Expand Down
Loading