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

Adding Competition Solver tab to settlements page #590

Closed
Closed
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b67c3b1
create the SolverCompetition screen
vicebas Aug 7, 2023
c0c8fdf
update Design
vicebas Aug 8, 2023
27605de
update Design
vicebas Aug 8, 2023
b083b62
update Design
vicebas Aug 8, 2023
439a82b
update Design
vicebas Aug 8, 2023
1b938a4
update Design
vicebas Aug 8, 2023
1dad41b
update Design
vicebas Aug 8, 2023
857783f
Create Clearing Prices
vicebas Aug 9, 2023
63c6676
Create Clearing Prices
vicebas Aug 9, 2023
56f76c6
Fixes on the description screen
vicebas Aug 9, 2023
d655359
add cache to Erc20
vicebas Aug 10, 2023
616ebae
add mobile capacities
vicebas Aug 11, 2023
84eae43
fix solutions prices and executed orders
vicebas Aug 14, 2023
a9d0509
fix small issues
vicebas Aug 16, 2023
e450c8a
fix formatting issues
vicebas Aug 16, 2023
5d6362a
avatar boring colors
vicebas Aug 16, 2023
08bb57e
fix prices issues
vicebas Aug 17, 2023
a5efe4a
Update webpack.config.js
0xaaiden Aug 17, 2023
9647448
Merge branch 'cowprotocol:develop' into feature/transactionScreens
0xaaiden Aug 17, 2023
20685c5
fix prices issues with decimals
vicebas Aug 17, 2023
3a26f19
Changes in display + tooltip info
Aug 18, 2023
4640729
Changes in display + tooltip info
Aug 18, 2023
4ff36d0
Change staging API back to barn
Aug 18, 2023
4b87d3c
fix native token per network
vicebas Aug 23, 2023
3782e0b
fix native token per network
vicebas Aug 23, 2023
8b22c10
add blockchain check before loading solvers
vicebas Aug 24, 2023
0a2da0b
add blockchain check before loading solvers
vicebas Aug 24, 2023
5f05d1b
Update webpack.config.js to redirect staging api to use prod endpoint…
0xaaiden Aug 24, 2023
ef5ceca
add blockchain check before loading solvers
vicebas Aug 24, 2023
9594f68
add blockchain check before loading solvers
vicebas Aug 24, 2023
657e099
change api being used to get currentBlock
vicebas Aug 25, 2023
7a3a8bb
change api being used to get currentBlock
vicebas Aug 25, 2023
2a761b6
Update webpack.config.js
0xaaiden Aug 25, 2023
6d9e2e2
undo webpack changes
vicebas Aug 25, 2023
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
29 changes: 28 additions & 1 deletion src/api/operator/operatorApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ import { Network } from 'types'
import { buildSearchString } from 'utils/url'
import { isProd, isStaging } from 'utils/env'

import { GetOrderParams, GetOrdersParams, RawOrder, RawTrade, GetTxOrdersParams, WithNetworkId } from './types'
import {
GetOrderParams,
GetOrdersParams,
RawOrder,
RawTrade,
GetTxOrdersParams,
WithNetworkId,
GetTxSolverCompetitionParams,
RawSolverCompetition,
} from './types'
import { fetchQuery } from 'api/baseApi'
import { orderBookSDK } from 'cowSdk'
import { Address, UID } from '@cowprotocol/cow-sdk'
Expand Down Expand Up @@ -150,6 +159,24 @@ export async function getTrades(
return [...trades[0], ...trades[1]]
}

/**
* Gets information about solver competition By Transaction Hash
* Required params:
* - txHash: string
*
*/
export async function getSolverCompetitionByTx(params: GetTxSolverCompetitionParams): Promise<RawSolverCompetition> {
const { networkId, txHash } = params

console.log(
`[getSolverCompetitionByTx] Fetching Solver Competition on network ${networkId} with filters: tx_hash=${txHash}`,
)

const queryString = '/solver_competition/by_tx_hash/' + txHash
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just noticed, this endpoint is available from orderBookSDK since version https://github.com/cowprotocol/cow-sdk/releases/tag/v2.3.0

Update to the latest and you can use it directly.

You will still HAVE TO query both barn and prod envs, like it's done here: https://github.com/cowprotocol/explorer/blob/develop/src/api/operator/operatorApi.ts#L104-L119


return _fetchQuery(networkId, queryString)
}
Comment on lines +168 to +178
Copy link
Collaborator

Choose a reason for hiding this comment

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

This unfortunately doesn't work with prod batches in this PR, as it only queries the env corresponding to the page's env.

See for example this goerli batch

It returns a 404 for barn while it has the proper response on prod

But I think you'd be aware of that as it for sure happened while developing/testing.

Long story short, there are 2 databases, and we usually query the one corresponding to the loaded environment.
In some cases though, we need to query both.
Check for reference the implementation of getTxOrders:

https://github.com/cowprotocol/explorer/blob/develop/src/api/operator/operatorApi.ts#L104-L119

Also, this endpoint should be moved to the https://github.com/cowprotocol/cow-sdk/. I'll raise this internally and see that we include it in the next release. No action from your part on this regard, just mentioning it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Upon further investigation, it seems that even batches which were made against barn still don't return anything in the solver endpoint for the same env, such as the one I intentionally created https://explorer-dev-git-fork-0xaaiden-feature-transacti-ee2e16-cowswap.vercel.app/gc/tx/0x540537ad6d2d7948a232f39ec7e91c66f2c0a476d5ca84617a2fec2d3eb5ce54?tab=solver

Looks like it's something on the backend side.

A quick fix would be to always query prod, although I don't think querying both requires much effort.

I'll reach out internally about this as well.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Got an answer that clarifies why it suddenly became available.

Searching by hash takes 65 blocks to propagate (we wait for the block to be final). If you know the auction id you can search immediately using that identifier

I suggest you to watch for the current block and compare with the tx block.
While the different is < 65, don't bother querying the backend, and show some indication in the UI saying the data is not yet available.


function _fetchQuery<T>(networkId: Network, queryString: string): Promise<T>
function _fetchQuery<T>(networkId: Network, queryString: string, nullOn404: true): Promise<T | null>
function _fetchQuery<T>(networkId: Network, queryString: string, nullOn404?: boolean): Promise<T | null> {
Expand Down
12 changes: 11 additions & 1 deletion src/api/operator/operatorMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
GetTradesParams,
RawOrder,
RawTrade,
GetTxSolverCompetitionParams,
RawSolverCompetition,
} from './types'

import { RAW_ORDER, RAW_TRADE } from '../../../test/data'
import { RAW_ORDER, RAW_SOLVER_COMPETITION, RAW_TRADE } from '../../../test/data'
import { GetAccountOrdersResponse } from './accountOrderUtils'

export async function getOrder(params: GetOrderParams): Promise<RawOrder> {
Expand Down Expand Up @@ -57,3 +59,11 @@ export async function getTrades(params: GetTradesParams): Promise<RawTrade[]> {

return [trade]
}

export async function getSolverCompetitionByTx(params: GetTxSolverCompetitionParams): Promise<RawSolverCompetition[]> {
const { txHash } = params
const solverCompetition = { ...RAW_SOLVER_COMPETITION }
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick:

return [{
    ...RAW_SOLVER_COMPETITION,
    transactionHash: txHash || solverCompetition.transactionHash
}]

solverCompetition.transactionHash = txHash || solverCompetition.transactionHash

return [solverCompetition]
}
24 changes: 23 additions & 1 deletion src/api/operator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import BigNumber from 'bignumber.js'

import { TokenErc20 } from '@gnosis.pm/dex-js'
import { Network } from 'types'
import { EnrichedOrder, OrderKind, Trade as TradeMetaData } from '@cowprotocol/cow-sdk'
import { EnrichedOrder, OrderKind, Trade as TradeMetaData, SolverCompetitionResponse } from '@cowprotocol/cow-sdk'
import { SolverSettlement } from '@cowprotocol/cow-sdk/dist/order-book/generated/models/SolverSettlement'

export type TxHash = string

Expand Down Expand Up @@ -71,6 +72,23 @@ export type Trade = Pick<RawTrade, 'blockNumber' | 'logIndex' | 'owner' | 'txHas
surplusPercentage?: BigNumber
}

export type Solution = SolverSettlement & {
ranking: number
}

/**
* Raw API SolverCompetition response type
*/
export type RawSolverCompetition = SolverCompetitionResponse & {
solutions: Solution[]
auctionStartBlock: number
}

/**
* Enriched SolverCompetition type
*/
export type SolverCompetition = RawSolverCompetition

export type WithNetworkId = { networkId: Network }

export type GetOrderParams = WithNetworkId & {
Expand All @@ -94,6 +112,10 @@ export type GetTxOrdersParams = WithNetworkId & {
txHash: TxHash
}

export type GetTxSolverCompetitionParams = WithNetworkId & {
txHash: TxHash
}

export type GetTradesParams = WithNetworkId & {
owner?: string
orderId?: string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react'
import { faListUl, faProjectDiagram } from '@fortawesome/free-solid-svg-icons'
import { faListUl, faProjectDiagram, faHandshakeAngle } from '@fortawesome/free-solid-svg-icons'
Copy link
Contributor

Choose a reason for hiding this comment

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

@fairlighteth any suggestion for the tab icon?


import { useQuery, useUpdateQueryString } from 'hooks/useQuery'
import { BlockchainNetwork, TransactionsTableContext } from './context/TransactionsTableContext'
Expand All @@ -17,6 +17,7 @@ import { Notification } from 'components/Notification'
import { TransactionBatchGraph } from 'apps/explorer/components/TransanctionBatchGraph'
import CowLoading from 'components/common/CowLoading'
import { TAB_QUERY_PARAM_KEY } from 'apps/explorer/const'
import { SolverCompetition } from 'components/transaction/SolverCompetition'

interface Props {
txHash: string
Expand All @@ -27,6 +28,7 @@ interface Props {
enum TabView {
ORDERS = 1,
GRAPH,
SOLVER = 3,
}

const DEFAULT_TAB = TabView[1]
Expand All @@ -48,6 +50,11 @@ const tabItems = (orders: Order[] | undefined, networkId: BlockchainNetwork, txH
tab: <TabIcon title="Graph" iconFontName={faProjectDiagram} />,
content: <TransactionBatchGraph orders={orders} networkId={networkId} txHash={txHash} />,
},
{
id: TabView.SOLVER,
tab: <TabIcon title="Solver Competition" iconFontName={faHandshakeAngle} />,
content: <SolverCompetition orders={orders} networkId={networkId} txHash={txHash} />,
},
]
}

Expand Down
13 changes: 13 additions & 0 deletions src/components/common/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { useState } from 'react'
import { Avatar } from '@material-ui/core'

type BoringAvatarProps = {
alt?: string
}
const BoringAvatar: React.FC<BoringAvatarProps> = ({ alt }) => {
const [colors] = useState<string[]>(
Array.from({ length: 6 }, () => Math.floor(Math.random() * 16777215).toString(16)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this random logic?

also, nit, since you are creating a component call BoringAvatar, should you call the file with the same name?

Copy link

Choose a reason for hiding this comment

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

Was getting a lot of close colors avatars without it.

)
return <Avatar alt={alt} src={`https://source.boringavatars.com/pixel/120/${alt}?colors=${colors.join(',')}`} />
}
export default BoringAvatar
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I would avoid default export. With named one is enough

Copy link

Choose a reason for hiding this comment

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

Ok

83 changes: 83 additions & 0 deletions src/components/transaction/SolverCompetition/ClearingPrices.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useState } from 'react'
import { useNetworkId } from 'state/network'
import { EmptyItemWrapper } from 'components/common/StyledUserDetailsTable'
import { PricesCard } from 'components/transaction/SolverCompetition/styled'
import { formatSmart, safeTokenName, TokenErc20 } from '@gnosis.pm/dex-js'
import { Network } from 'types'
import TokenImg from 'components/common/TokenImg'
import { HIGH_PRECISION_SMALL_LIMIT, NO_ADJUSTMENT_NEEDED_PRECISION } from 'apps/explorer/const'
import { getImageAddress } from 'utils'
import { invertPrice } from '@gnosis.pm/dex-js/build-esm/utils/price'
import Icon from 'components/Icon'
import { faExchangeAlt } from '@fortawesome/free-solid-svg-icons'
import BigNumber from 'bignumber.js'
import { NATIVE_TOKEN_PER_NETWORK, TEN_BIG_NUMBER } from 'const'
import { Order } from 'api/operator'
import { AuctionPrices } from '@cowprotocol/cow-sdk'

type Props = {
orders: Order[]
prices: AuctionPrices
}

type ItemProps = {
token: TokenErc20
amount: BigNumber
network: Network
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const Item: React.FC<ItemProps> = (props) => {
const { token, network, amount } = props

const [invertedPrice, setInvertedPrice] = useState<boolean>(false)
console.log(token, amount.toNumber())
Copy link
Contributor

Choose a reason for hiding this comment

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

console.log should be removed

const calculatedPrice = amount.div(TEN_BIG_NUMBER.exponentiatedBy(36 - token.decimals.valueOf()))
Copy link
Contributor

Choose a reason for hiding this comment

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

What is 36? Would be great to move it to a const with an appropriate name + comment

const displayPrice = (invertedPrice ? invertPrice(calculatedPrice) : calculatedPrice).toString(10)
const formattedPrice = formatSmart({
amount: displayPrice,
precision: NO_ADJUSTMENT_NEEDED_PRECISION,
smallLimit: HIGH_PRECISION_SMALL_LIMIT,
decimals: 6,
isLocaleAware: false,
})

const tokenImage = getImageAddress(token?.address ?? '', network)
const tokenSymbol = token && safeTokenName(token)

const tokenNames = !invertedPrice
? [tokenSymbol, NATIVE_TOKEN_PER_NETWORK[network].symbol]
: [NATIVE_TOKEN_PER_NETWORK[network].symbol, tokenSymbol]
return (
<div key={token?.address}>
<TokenImg address={tokenImage} />
{`1 ${tokenNames[0]}`} = {formattedPrice} {`${tokenNames[1]}`}
{<Icon icon={faExchangeAlt} onClick={(): void => setInvertedPrice(!invertedPrice)} />}
</div>
)
}

const ClearingPrices: React.FC<Props> = (props) => {
const { orders, prices } = props
const networkId = useNetworkId() ?? undefined
const tokens: { [p: string]: TokenErc20 | null | undefined } = Object.assign(
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be meoized?

{},
...orders.map((o): { [p: string]: TokenErc20 | null | undefined } => ({
[o.buyTokenAddress]: o.buyToken,
[o.sellTokenAddress]: o.sellToken,
})),
)
console.log(tokens)
Copy link
Contributor

Choose a reason for hiding this comment

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

delete console logs

if (!networkId) {
return <EmptyItemWrapper>{'Can&apos;t load details'}</EmptyItemWrapper>
}
return (
<PricesCard>
{Object.values(tokens).map((token, key) => {
return (
<>{token && <Item key={key} token={token} amount={BigNumber(prices[token.address])} network={networkId} />}</>
)
})}
</PricesCard>
)
}
export default ClearingPrices
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, use named exports instead of default

Loading