Skip to content

Commit

Permalink
feat: portals market-data (#7443)
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre authored Aug 1, 2024
1 parent ce9b581 commit df61d99
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 46 deletions.
44 changes: 3 additions & 41 deletions scripts/generateAssetData/utils/portals.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,15 @@
import type { ChainId } from '@shapeshiftoss/caip'
import {
arbitrumChainId,
ASSET_NAMESPACE,
avalancheChainId,
baseChainId,
bscChainId,
ethChainId,
gnosisChainId,
optimismChainId,
polygonChainId,
toAssetId,
} from '@shapeshiftoss/caip'
import { ASSET_NAMESPACE, bscChainId, toAssetId } from '@shapeshiftoss/caip'
import type { Asset } from '@shapeshiftoss/types'
import axios from 'axios'
import qs from 'qs'
import { getAddress, isAddressEqual, zeroAddress } from 'viem'
import { CHAIN_ID_TO_PORTALS_NETWORK } from 'lib/market-service/portals/constants'
import type { GetTokensResponse, TokenInfo } from 'lib/market-service/portals/types'

import { colorMap } from '../colorMap'
import { createThrottle } from '.'

// Non-exhaustive - https://api.portals.fi/docs#/Supported/SupportedController_getSupportedTokensV2 for full docs
type TokenInfo = {
key: string
name: string
decimals: number
symbol: string
address: string
images: string[] | undefined
}

type GetTokensResponse = {
totalItems: number
pageItems: number
more: boolean
page: number
tokens: TokenInfo[]
}

const CHAIN_ID_TO_PORTALS_NETWORK: Partial<Record<ChainId, string>> = {
[avalancheChainId]: 'avalanche',
[ethChainId]: 'ethereum',
[polygonChainId]: 'polygon',
[bscChainId]: 'bsc',
[optimismChainId]: 'optimism',
[arbitrumChainId]: 'arbitrum',
[gnosisChainId]: 'gnosis',
[baseChainId]: 'base',
}

export const fetchPortalsTokens = async (
chainId: ChainId,
page: number = 0,
Expand Down
6 changes: 1 addition & 5 deletions src/components/AssetHeader/AssetMarketData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,7 @@ export const AssetMarketData: React.FC<AssetMarketDataProps> = ({ assetId }) =>
<Text translation='assets.assetDetails.assetHeader.availableSupply' />
</StatLabel>
<StatValue isLoaded={isLoaded}>
<Amount
value={Math.round(Number(marketData?.supply ?? 0))}
abbreviated
omitDecimalTrailingZeros
/>
<Amount value={marketData?.supply} abbreviated omitDecimalTrailingZeros />
</StatValue>
</StatRow>
)}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/market-service/market-service-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { MarketService } from './api'
import { CoinCapMarketService } from './coincap/coincap'
import { CoinGeckoMarketService } from './coingecko/coingecko'
import { FoxyMarketService } from './foxy/foxy'
import { PortalsMarketService } from './portals/portals'
// import { YearnTokenMarketCapService } from './yearn/yearn-tokens'
// import { YearnVaultMarketCapService } from './yearn/yearn-vaults'

Expand Down Expand Up @@ -48,6 +49,7 @@ export class MarketServiceManager {
// More reliable providers should be listed first.
new CoinGeckoMarketService(),
new CoinCapMarketService(),
new PortalsMarketService(),
// Yearn is currently borked upstream
// new YearnVaultMarketCapService({ yearnSdk }),
// new YearnTokenMarketCapService({ yearnSdk }),
Expand Down
22 changes: 22 additions & 0 deletions src/lib/market-service/market-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ vi.mock('./coincap/coincap', () => ({
}),
}))

const mockPortalsFindByAssetId = vi.fn().mockImplementation(() => mockCGFindByAssetIdData)
const mockPortalsFindAll = vi.fn().mockImplementation(() => mockCGFindAllData)
const mockPortalsFindPriceHistoryByAssetId = vi
.fn()
.mockImplementation(() => mockCGPriceHistoryData)

vi.mock('./portals/portals', () => ({
PortalsMarketService: vi.fn().mockImplementation(() => {
return {
findAll: mockPortalsFindAll,
findByAssetId: mockPortalsFindByAssetId,
findPriceHistoryByAssetId: mockPortalsFindPriceHistoryByAssetId,
}
}),
}))

const mockYearnVaultFindAll = vi.fn().mockImplementation(() => mockYearnServiceFindAllData)
const mockYearnVaultFindByAssetId = vi.fn().mockImplementation(() => mockYearnFindByAssetIdData)
const mockYearnVaultFindPriceHistoryByAssetId = vi
Expand Down Expand Up @@ -133,6 +149,7 @@ describe('market service', () => {
const marketServiceManager = new MarketServiceManager(marketServiceManagerArgs)
mockCoingeckoFindAll.mockRejectedValueOnce({ error: 'error' })
mockCoincapFindAll.mockRejectedValueOnce({ error: 'error' })
mockPortalsFindAll.mockRejectedValueOnce({ error: 'error' })
mockYearnVaultFindAll.mockRejectedValueOnce({ error: 'error' })
mockYearnTokenFindAll.mockRejectedValueOnce({ error: 'error' })
mockFoxyFindAll.mockRejectedValueOnce({ error: 'error' })
Expand All @@ -150,6 +167,7 @@ describe('market service', () => {
it('returns next market service data if previous data does not exist', async () => {
mockCoingeckoFindAll.mockRejectedValueOnce({ error: 'error' })
mockCoincapFindAll.mockRejectedValueOnce({ error: 'error' })
mockPortalsFindAll.mockRejectedValueOnce({ error: 'error' })
const marketServiceManager = new MarketServiceManager(marketServiceManagerArgs)
const result = await marketServiceManager.findAll({ count: Number() })
expect(result).toEqual(mockFoxyMarketData)
Expand All @@ -169,6 +187,7 @@ describe('market service', () => {
it('can return from next market service if first is not found', async () => {
mockCoingeckoFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockCoincapFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockPortalsFindByAssetId.mockRejectedValueOnce({ error: 'error' })
const marketServiceManager = new MarketServiceManager(marketServiceManagerArgs)
const result = await marketServiceManager.findByAssetId(ethArgs)
expect(result).toEqual(mockFoxyMarketData)
Expand All @@ -177,6 +196,7 @@ describe('market service', () => {
it('can return null if no data found', async () => {
mockCoingeckoFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockCoincapFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockPortalsFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockYearnVaultFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockYearnTokenFindByAssetId.mockRejectedValueOnce({ error: 'error' })
mockFoxyFindByAssetId.mockRejectedValueOnce({ error: 'error' })
Expand All @@ -203,6 +223,7 @@ describe('market service', () => {
it('can return from the next market service if the first is not found', async () => {
mockCoingeckoFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockCoincapFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockPortalsFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
const marketServiceManager = new MarketServiceManager(marketServiceManagerArgs)
const result = await marketServiceManager.findPriceHistoryByAssetId(
findPriceHistoryByAssetIdArgs,
Expand All @@ -213,6 +234,7 @@ describe('market service', () => {
it('can return null if no data found', async () => {
mockCoingeckoFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockCoincapFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockPortalsFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockYearnVaultFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockYearnTokenFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
mockFoxyFindPriceHistoryByAssetId.mockRejectedValueOnce({ error: 'error' })
Expand Down
22 changes: 22 additions & 0 deletions src/lib/market-service/portals/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { ChainId } from '@shapeshiftoss/caip'
import {
arbitrumChainId,
avalancheChainId,
baseChainId,
bscChainId,
ethChainId,
gnosisChainId,
optimismChainId,
polygonChainId,
} from '@shapeshiftoss/caip'

export const CHAIN_ID_TO_PORTALS_NETWORK: Partial<Record<ChainId, string>> = {
[avalancheChainId]: 'avalanche',
[ethChainId]: 'ethereum',
[polygonChainId]: 'polygon',
[bscChainId]: 'bsc',
[optimismChainId]: 'optimism',
[arbitrumChainId]: 'arbitrum',
[gnosisChainId]: 'gnosis',
[baseChainId]: 'base',
}
Loading

0 comments on commit df61d99

Please sign in to comment.