Skip to content
This repository has been archived by the owner on Feb 2, 2024. It is now read-only.

Commit

Permalink
feat: classify order types (#720)
Browse files Browse the repository at this point in the history
* chore: add utils fn decodeFullAppData

* feat: add getUiOrderType - different than CoW Swap's
  • Loading branch information
alfetopito authored Dec 29, 2023
1 parent 637155e commit 6d3eb8c
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/components/AppData/DecodeAppData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Spinner from 'components/common/Spinner'
import { DEFAULT_IPFS_READ_URI, IPFS_INVALID_APP_IDS } from 'const'
import { appDataHexToCid, fetchDocFromAppDataHex } from 'hooks/useAppData'
import useSafeState from 'hooks/useSafeState'
import { decodeFullAppData } from 'utils/decodeFullAppData'

type Props = {
appData: string
Expand All @@ -22,7 +23,7 @@ async function _getDecodedAppData(
// If the full appData is available, we try to parse it as JSON
if (fullAppData) {
try {
const decodedAppData = JSON.parse(fullAppData)
const decodedAppData = decodeFullAppData(fullAppData, true)
return { decodedAppData, isError: false }
} catch (error) {
console.error('Error parsing fullAppData from the API', { fullAppData }, error)
Expand Down
4 changes: 3 additions & 1 deletion src/components/orders/DetailsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { sendEvent } from 'components/analytics'
import { LinkWithPrefixNetwork } from 'components/common/LinkWithPrefixNetwork'
import DecodeAppData from 'components/AppData/DecodeAppData'
import { TAB_QUERY_PARAM_KEY } from 'apps/explorer/const'
import { getUiOrderType } from 'utils/getUiOrderType'

const Table = styled(SimpleTable)`
> tbody > tr {
Expand Down Expand Up @@ -301,7 +302,8 @@ export function DetailsTable(props: Props): JSX.Element | null {
<HelpTooltip tooltip={tooltip.type} /> Type
</td>
<td>
{capitalize(kind)} {order.class} order {partiallyFillable ? '(Partially fillable)' : '(Fill or Kill)'}
{capitalize(kind)} {getUiOrderType(order).toLowerCase()} order{' '}
{partiallyFillable ? '(Partially fillable)' : '(Fill or Kill)'}
</td>
</tr>
<tr>
Expand Down
28 changes: 28 additions & 0 deletions src/utils/decodeFullAppData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { AnyAppDataDocVersion } from '@cowprotocol/app-data'

/**
* Decode appData from a string to a AnyAppDataDocVersion instance
* Keep in mind it can be a valid JSON but not necessarily a valid AppDataDoc
*
* Returns undefined if the given appData is not a valid JSON
* When `throwOnError` is true, it will throw an error if the given appData is not a valid JSON
*/
export function decodeFullAppData(
appData: string | null | undefined,
throwOnError?: true,
): AnyAppDataDocVersion | undefined {
if (!appData) {
return undefined
}

try {
return JSON.parse(appData)
} catch (e) {
if (throwOnError) {
throw e
}

console.info('[decodeFullAppData] given appData is not a valid JSON', appData)
return undefined
}
}
43 changes: 43 additions & 0 deletions src/utils/getUiOrderType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { latest } from '@cowprotocol/app-data'
import { OrderClass } from '@cowprotocol/cow-sdk'
import { Order } from 'api/operator'
import { decodeFullAppData } from 'utils/decodeFullAppData'

/**
* UiOrderType based on appData, falling back to backend order class.
*
* Similar to CoW Swap, but not exactly like it.
*
* Here, MARKET remains as MARKET, while on CoW Swap it's translated to SWAP.
* Also, we keep the LIQUIDITY order type as it, while there it's translated to LIMIT.
*
* In summary, it matches 1:1 appData.metadata.orderClass.orderClass enum
*/
export enum UiOrderType {
MARKET = 'MARKET',
LIMIT = 'LIMIT',
LIQUIDITY = 'LIQUIDITY',
TWAP = 'TWAP',
}

const API_ORDER_CLASS_TO_UI_ORDER_TYPE_MAP: Record<OrderClass, UiOrderType> = {
[OrderClass.MARKET]: UiOrderType.MARKET,
[OrderClass.LIMIT]: UiOrderType.LIMIT,
[OrderClass.LIQUIDITY]: UiOrderType.LIQUIDITY,
}

export function getUiOrderType({ fullAppData, class: orderClass }: Order): UiOrderType {
const appData = decodeFullAppData(fullAppData)

const appDataOrderClass = appData?.metadata?.orderClass as latest.OrderClass | undefined
const typeFromAppData = UiOrderType[appDataOrderClass?.orderClass.toUpperCase() || '']

// 1. AppData info has priority as it's what's more precise
if (typeFromAppData) {
return typeFromAppData
}

// 3. Fallback to API classification.
// Least precise as it doesn't distinguish twap type and uses backend logic which doesn't match frontend's classification
return API_ORDER_CLASS_TO_UI_ORDER_TYPE_MAP[orderClass]
}

0 comments on commit 6d3eb8c

Please sign in to comment.