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

[Release 1.8] Use real price strategy endpoint #2016

Merged
merged 6 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion src/custom/api/gnosisProtocol/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SupportedChainId as ChainId } from 'constants/chains'
import { SupportedChainId as ChainId, SupportedChainId } from 'constants/chains'
import { OrderKind, QuoteQuery } from '@gnosis.pm/gp-v2-contracts'
import { stringify } from 'qs'
import { getSigningSchemeApiValue, OrderCreation, OrderCancellation, SigningSchemeValue } from 'utils/signatures'
Expand All @@ -24,6 +24,7 @@ import { GAS_FEE_ENDPOINTS } from 'constants/index'
import * as Sentry from '@sentry/browser'
import { ZERO_ADDRESS } from 'constants/misc'
import { getAppDataHash } from 'constants/appDataHash'
import { GpPriceStrategy } from '@src/custom/hooks/useGetGpPriceStrategy'

function getGnosisProtocolUrl(): Partial<Record<ChainId, string>> {
if (isLocal || isDev || isPr || isBarn) {
Expand Down Expand Up @@ -58,9 +59,18 @@ function getProfileUrl(): Partial<Record<ChainId, string>> {
process.env.REACT_APP_PROFILE_API_URL_STAGING_MAINNET || 'https://protocol-affiliate.gnosis.io/api',
}
}
const STRATEGY_URL_BASE = 'https://raw.githubusercontent.com/gnosis/cowswap/configuration/config/strategies'
function getPriceStrategyUrl(): Record<SupportedChainId, string> {
return {
[SupportedChainId.MAINNET]: STRATEGY_URL_BASE + '/strategy-1.json',
[SupportedChainId.RINKEBY]: STRATEGY_URL_BASE + '/strategy-4.json',
[SupportedChainId.XDAI]: STRATEGY_URL_BASE + '/strategy-100.json',
}
}

const API_BASE_URL = getGnosisProtocolUrl()
const PROFILE_API_BASE_URL = getProfileUrl()
const STRATEGY_API_URL = getPriceStrategyUrl()

const DEFAULT_HEADERS = {
'Content-Type': 'application/json',
Expand Down Expand Up @@ -145,6 +155,20 @@ function _getProfileApiBaseUrl(chainId: ChainId): string {
}
}

function _getPriceStrategyApiBaseUrl(chainId: ChainId): string {
const baseUrl = STRATEGY_API_URL[chainId]

if (!baseUrl) {
new Error(
`Unsupported Network. The ${API_NAME} strategy API is not deployed in the Network ` +
chainId +
'. Defaulting to using Mainnet strategy.'
)
}

return baseUrl
}

export function getOrderLink(chainId: ChainId, orderId: OrderID): string {
const baseUrl = _getApiBaseUrl(chainId)

Expand Down Expand Up @@ -174,6 +198,11 @@ function _fetchProfile(
})
}

function _fetchPriceStrategy(chainId: ChainId): Promise<Response> {
const baseUrl = _getPriceStrategyApiBaseUrl(chainId)
return fetch(baseUrl)
}

function _post(chainId: ChainId, url: string, data: any): Promise<Response> {
return _fetch(chainId, url, 'POST', data)
}
Expand Down Expand Up @@ -427,6 +456,25 @@ export async function getProfileData(chainId: ChainId, address: string): Promise
}
}

export type PriceStrategy = {
primary: GpPriceStrategy
secondary: GpPriceStrategy
}

export async function getPriceStrategy(chainId: ChainId): Promise<PriceStrategy> {
console.log(`[api:${API_NAME}] Get GP price strategy for`, chainId)

const response = await _fetchPriceStrategy(chainId)

if (!response.ok) {
const errorResponse = await response.json()
console.log(errorResponse)
throw new Error(errorResponse?.description)
} else {
return response.json()
}
}

export interface GasFeeEndpointResponse {
lastUpdate: string
lowest: string
Expand Down
2 changes: 1 addition & 1 deletion src/custom/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,4 @@ export const STORAGE_KEY_LAST_PROVIDER = 'lastProvider'
// Default price strategy to use for getting app prices
// COWSWAP = new quote endpoint
// LEGACY = price racing logic (checking 0x, gp, paraswap, etc)
export const DEFAULT_GP_PRICE_STRATEGY = 'LEGACY'
export const DEFAULT_GP_PRICE_STRATEGY = 'COWSWAP'
33 changes: 15 additions & 18 deletions src/custom/hooks/useGetGpPriceStrategy.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import ms from 'ms.macro'
import { useState, useEffect } from 'react'
import { useState, useEffect, useCallback } from 'react'
import { DEFAULT_GP_PRICE_STRATEGY } from 'constants/index'
import { registerOnWindow } from '../utils/misc'
import { getPriceStrategy, PriceStrategy } from 'api/gnosisProtocol/api'
import { useActiveWeb3React } from 'hooks'
import { supportedChainId } from 'utils/supportedChainId'
import { SupportedChainId } from 'constants/chains'

export type GpPriceStrategy = 'COWSWAP' | 'LEGACY'
// TODO: use actual API call
// https://github.com/gnosis/gp-v2-contracts/issues/904
export async function checkGpPriceStrategy(): Promise<GpPriceStrategy> {
return new Promise((accept) => setTimeout(() => accept(DEFAULT_GP_PRICE_STRATEGY), 500))
}

// arbitrary, could be more/less
const GP_PRICE_STRATEGY_INTERVAL_TIME = ms`30 minutes`

export default function useGetGpPriceStrategy(): GpPriceStrategy {
const [gpPriceStrategy, setGpPriceStrategy] = useState<GpPriceStrategy>(DEFAULT_GP_PRICE_STRATEGY)
const { chainId: preChainId } = useActiveWeb3React()

const _handleSetStrategy = useCallback((response: PriceStrategy) => setGpPriceStrategy(response.primary), [])

useEffect(() => {
const chainId = supportedChainId(preChainId)
console.debug('[useGetGpPriceStrategy::GP Price Strategy]::', gpPriceStrategy)

const getStrategy = () => {
checkGpPriceStrategy()
.then(setGpPriceStrategy)
// default to MAINNET if not connected, or incorrect network
getPriceStrategy(chainId || SupportedChainId.MAINNET)
.then(_handleSetStrategy)
.catch((err: Error) => {
console.error('[useGetGpPriceStrategy::useEffect] Error getting GP price strategy::', err)
// Fallback to DEFAULT
Expand All @@ -36,14 +40,7 @@ export default function useGetGpPriceStrategy(): GpPriceStrategy {
}, GP_PRICE_STRATEGY_INTERVAL_TIME)

return () => clearInterval(intervalId)
}, [gpPriceStrategy])
}, [_handleSetStrategy, gpPriceStrategy, preChainId])

// TODO: REMOVE
return process.env.NODE_ENV !== 'production' ? (window as any).GP_STRATEGY : gpPriceStrategy
return gpPriceStrategy
}

/* TESTING ONLY! */
;(window as any).GP_STRATEGY = DEFAULT_GP_PRICE_STRATEGY
registerOnWindow({
setStrategy: (strat: GpPriceStrategy) => ((window as any).GP_STRATEGY = strat),
})