Skip to content

Commit

Permalink
feat: executedSurplusFee removal (#5262)
Browse files Browse the repository at this point in the history
* chore: bump cow-sdk to latest RC version

* feat: replace executedSurplusFee with executedSuplus

Also use totalFee where applicable

* feat: do same as previous, but on Explorer

* refactor: moved getFeeToken out and improved logic as suggested

* test: add unit tests
  • Loading branch information
alfetopito authored Jan 6, 2025
1 parent a8efd5c commit 3be8a65
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 34 deletions.
11 changes: 8 additions & 3 deletions apps/cowswap-frontend/src/legacy/state/orders/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ export type OrderInfoApi = Pick<
| 'executedSellAmount'
| 'executedSellAmountBeforeFees'
| 'executedFeeAmount'
| 'executedSurplusFee'
| 'executedFee'
| 'executedFeeToken'
| 'totalFee'
| 'invalidated'
| 'ethflowData'
| 'onchainOrderData'
Expand Down Expand Up @@ -139,6 +141,7 @@ export interface AddPendingOrderParams {
order: SerializedOrder
isSafeWallet: boolean
}

export type ChangeOrderStatusParams = { id: UID; chainId: ChainId }
export type SetOrderCancellationHashParams = ChangeOrderStatusParams & { hash: string }

Expand Down Expand Up @@ -177,11 +180,13 @@ export interface BatchOrdersUpdateParams {
}

export type PresignedOrdersParams = BatchOrdersUpdateParams

export interface UpdatePresignGnosisSafeTxParams {
orderId: UID
chainId: ChainId
safeTransaction: SafeMultisigTransactionResponse
}

export type ExpireOrdersBatchParams = BatchOrdersUpdateParams
export type InvalidateOrdersBatchParams = BatchOrdersUpdateParams
export type CancelOrdersBatchParams = BatchOrdersUpdateParams
Expand All @@ -196,7 +201,7 @@ export const fulfillOrdersBatch = createAction<FulfillOrdersBatchParams>('order/
export const preSignOrders = createAction<PresignedOrdersParams>('order/presignOrders')

export const updatePresignGnosisSafeTx = createAction<UpdatePresignGnosisSafeTxParams>(
'order/updatePresignGnosisSafeTx'
'order/updatePresignGnosisSafeTx',
)

export const expireOrdersBatch = createAction<ExpireOrdersBatchParams>('order/expireOrdersBatch')
Expand All @@ -214,7 +219,7 @@ export const deleteOrders = createAction<DeleteOrdersParams>('order/deleteOrders
export const clearOrders = createAction<{ chainId: ChainId }>('order/clearOrders')

export const updateLastCheckedBlock = createAction<{ chainId: ChainId; lastCheckedBlock: number }>(
'order/updateLastCheckedBlock'
'order/updateLastCheckedBlock',
)

export const clearOrdersStorage = createAction('order/clearOrdersStorage')
Expand Down
17 changes: 9 additions & 8 deletions apps/cowswap-frontend/src/legacy/state/orders/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export function getDefaultNetworkState(chainId: ChainId): OrdersStateNetwork {
// makes sure there's always an object at state[chainId], state[chainId].pending | .fulfilled
function prefillState(
state: Writable<OrdersState>,
{ payload: { chainId } }: PayloadAction<PrefillStateRequired>
{ payload: { chainId } }: PayloadAction<PrefillStateRequired>,
): asserts state is Required<OrdersState> {
const stateAtChainId = state[chainId]

Expand Down Expand Up @@ -174,7 +174,7 @@ function addOrderToState(
id: string,
status: OrderTypeKeys,
order: SerializedOrder,
isSafeWallet: boolean
isSafeWallet: boolean,
): void {
// Attempt to fix `TypeError: Cannot add property <x>, object is not extensible`
// seen on https://user-images.githubusercontent.com/34510341/138450105-bb94a2d1-656e-4e15-ae99-df9fb33c8ca4.png
Expand All @@ -200,7 +200,7 @@ function cancelOrderInState(
state: Required<OrdersState>,
chainId: ChainId,
orderObject: OrderObject,
isSafeWallet: boolean
isSafeWallet: boolean,
) {
const id = orderObject.id

Expand Down Expand Up @@ -368,12 +368,13 @@ export default createReducer(initialState, (builder) =>

orderObject.order.apiAdditionalInfo = {
creationDate: order.creationDate,
availableBalance: order.availableBalance,
executedBuyAmount: order.executedBuyAmount,
executedSellAmount: order.executedSellAmount,
executedSellAmountBeforeFees: order.executedSellAmountBeforeFees,
executedFeeAmount: order.executedFeeAmount,
executedSurplusFee: order.executedSurplusFee,
executedFee: order.executedFee,
executedFeeToken: order.executedFeeToken,
totalFee: order.totalFee,
invalidated: order.invalidated,
ethflowData: order.ethflowData,
onchainOrderData: order.onchainOrderData,
Expand Down Expand Up @@ -458,7 +459,7 @@ export default createReducer(initialState, (builder) =>
const allOrdersMap = flatOrdersStateNetwork(state[chainId])

const children = Object.values(allOrdersMap).filter(
(item) => item?.order.composableCowInfo?.parentId === id
(item) => item?.order.composableCowInfo?.parentId === id,
)

children.forEach((child) => {
Expand Down Expand Up @@ -544,12 +545,12 @@ export default createReducer(initialState, (builder) =>
orderListByChain[status] = ordersCleaned
})
})
})
}),
)

function reClassifyOrder(
newOrder: SerializedOrder,
existingOrder: OrderObject | undefined
existingOrder: OrderObject | undefined,
): { status: OrderStatus; isCancelling: boolean | undefined } {
// Onchain cancellations are considered final
// Still, the order classification at apps/cowswap-frontend/src/legacy/state/orders/utils.ts can't tell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ export const ordersMock: ParsedOrder[] = [
signingScheme: SigningScheme.EIP712,
class: OrderClass.MARKET,
kind: OrderKind.SELL,
apiAdditionalInfo: {
executedFeeAmount: '1',
executedFee: '1',
executedFeeToken: USDC[chainId].address,
totalFee: '1',
creationDate: '2022-11-11T13:15:13.551Z',
executedBuyAmount: '23000000000000',
executedSellAmount: '5000300000000000',
executedSellAmountBeforeFees: '5000300000000000',
invalidated: false,
class: OrderClass.LIMIT,
signingScheme: SigningScheme.EIP712,
},
},
{
id: '5',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import { TokenAmount } from '@cowprotocol/ui'
import { CurrencyAmount } from '@uniswap/sdk-core'

import { getFeeToken } from 'modules/ordersTable/utils/getFeeToken'

import { ParsedOrder } from 'utils/orderUtils/parseOrder'

import * as styledEl from './styled'

export type Props = { order: ParsedOrder }

export function FeeField({ order }: Props): JSX.Element | null {
const { inputToken } = order
const { executedFeeAmount, executedSurplusFee } = order.executionData
const { totalFee } = order.executionData
const feeToken = getFeeToken(order)

if (!inputToken) return <styledEl.Value></styledEl.Value>
if (!feeToken) return <styledEl.Value></styledEl.Value>

// TODO: use the value from SDK
const totalFee = CurrencyAmount.fromRawAmount(inputToken, (executedSurplusFee ?? executedFeeAmount) || 0)
const quoteSymbol = inputToken.symbol
const totalFeeAmount = CurrencyAmount.fromRawAmount(feeToken, totalFee || 0)
const quoteSymbol = feeToken.symbol

return (
<styledEl.Value>
{!quoteSymbol || !totalFee ? (
<span>-</span>
) : (
<span>
<TokenAmount amount={totalFee} tokenSymbol={inputToken} />
<TokenAmount amount={totalFeeAmount} tokenSymbol={feeToken} />
</span>
)}
</styledEl.Value>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { getFeeToken } from './getFeeToken' // Adjust the import path as necessary

import { ordersMock } from '../pure/OrdersTableContainer/orders.mock'

const BASE_ORDER = ordersMock[3]

describe('getFeeToken', () => {
it("should return inputToken when that's the fee token", () => {
const input = BASE_ORDER
const expectedOutput = BASE_ORDER.inputToken

const result = getFeeToken(input)

expect(result).toEqual(expectedOutput)
})

it("should return outputToken when that's the fee token", () => {
const input = {
...BASE_ORDER,
executionData: { ...BASE_ORDER.executionData, executedFeeToken: BASE_ORDER.outputToken.address },
}
const expectedOutput = BASE_ORDER.outputToken

const result = getFeeToken(input)

expect(result).toEqual(expectedOutput)
})

it('should return inputToken when there is no fee token', () => {
const input = { ...BASE_ORDER, executionData: { ...BASE_ORDER.executionData, executedFeeToken: null } }
const expectedOutput = BASE_ORDER.inputToken

const result = getFeeToken(input)

expect(result).toEqual(expectedOutput)
})
})
14 changes: 14 additions & 0 deletions apps/cowswap-frontend/src/modules/ordersTable/utils/getFeeToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ParsedOrder } from 'utils/orderUtils/parseOrder'

export function getFeeToken(order: ParsedOrder) {
const { inputToken, outputToken } = order
const { executedFeeToken } = order.executionData

const feeTokenAddress = executedFeeToken?.toLowerCase()

if (!feeTokenAddress) {
return inputToken
}

return [inputToken, outputToken].find((token) => token?.address.toLowerCase() === feeTokenAddress)
}
12 changes: 9 additions & 3 deletions apps/cowswap-frontend/src/utils/orderUtils/parseOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export interface ParsedOrderExecutionData {
surplusAmount: BigNumber
surplusPercentage: BigNumber
executedFeeAmount: string | undefined
executedSurplusFee: string | null
executedFee: string | null
executedFeeToken: string | null
totalFee: string | null
filledPercentDisplay: string
executedPrice: Price<Currency, Currency> | null
activityId: string | undefined
Expand Down Expand Up @@ -60,7 +62,9 @@ export const parseOrder = (order: Order): ParsedOrder => {
const { executedBuyAmount, executedSellAmount } = getOrderExecutedAmounts(order)
const expirationTime = new Date(Number(order.validTo) * 1000)
const executedFeeAmount = order.apiAdditionalInfo?.executedFeeAmount
const executedSurplusFee = order.apiAdditionalInfo?.executedSurplusFee || null
const executedFee = order.apiAdditionalInfo?.executedFee || null
const executedFeeToken = order.apiAdditionalInfo?.executedFeeToken || null
const totalFee = order.apiAdditionalInfo?.totalFee || null
const creationTime = new Date(order.creationTime)
const fullyFilled = isOrderFilled(order)
const partiallyFilled = isPartiallyFilled(order)
Expand All @@ -80,6 +84,7 @@ export const parseOrder = (order: Order): ParsedOrder => {
const activityTitle = showCreationTxLink ? 'Creation transaction' : 'Order ID'

const executionData: ParsedOrderExecutionData = {
executedFeeToken,
executedBuyAmount,
executedSellAmount,
filledAmount,
Expand All @@ -88,7 +93,8 @@ export const parseOrder = (order: Order): ParsedOrder => {
surplusAmount,
surplusPercentage,
executedFeeAmount,
executedSurplusFee,
executedFee,
totalFee,
executedPrice,
fullyFilled,
partiallyFilled,
Expand Down
14 changes: 11 additions & 3 deletions apps/explorer/src/api/operator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ export type RawOrder = EnrichedOrder
*/
export type Order = Pick<
RawOrder,
'owner' | 'uid' | 'appData' | 'kind' | 'partiallyFillable' | 'signature' | 'class' | 'fullAppData'
| 'owner'
| 'uid'
| 'appData'
| 'kind'
| 'partiallyFillable'
| 'signature'
| 'class'
| 'fullAppData'
| 'executedFeeToken'
> & {
receiver: string
txHash?: string
Expand All @@ -35,7 +43,7 @@ export type Order = Pick<
executedSellAmount: BigNumber
feeAmount: BigNumber
executedFeeAmount: BigNumber
executedSurplusFee: BigNumber | null
executedFee: BigNumber | null
totalFee: BigNumber
cancelled: boolean
status: OrderStatus
Expand All @@ -60,7 +68,7 @@ export type Trade = Pick<RawTrade, 'blockNumber' | 'logIndex' | 'owner' | 'txHas
kind?: OrderKind
buyAmount: BigNumber
sellAmount: BigNumber
executedSurplusFee?: BigNumber
executedFee?: BigNumber
sellAmountBeforeFees: BigNumber
buyToken?: TokenErc20 | null
buyTokenAddress: string
Expand Down
4 changes: 2 additions & 2 deletions apps/explorer/src/test/data/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const RAW_ORDER = {
executedSellAmount: '0',
feeAmount: '0',
executedFeeAmount: '0',
executedSurplusFee: '0',
executedFee: '0',
executedSellAmountBeforeFees: '0',
totalFee: '0',
sellToken: WETH.address,
Expand All @@ -49,7 +49,7 @@ export const RICH_ORDER: Order = {
executedSellAmount: ZERO_BIG_NUMBER,
feeAmount: new BigNumber(RAW_ORDER.feeAmount),
executedFeeAmount: new BigNumber(RAW_ORDER.executedFeeAmount),
executedSurplusFee: ZERO_BIG_NUMBER,
executedFee: ZERO_BIG_NUMBER,
totalFee: ZERO_BIG_NUMBER,
cancelled: RAW_ORDER.invalidated,
status: 'open',
Expand Down
4 changes: 2 additions & 2 deletions apps/explorer/src/utils/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ export function transformOrder(rawOrder: RawOrder): Order {
sellAmount,
feeAmount,
executedFeeAmount,
executedSurplusFee,
executedFee,
totalFee,
invalidated,
...rest
Expand All @@ -397,7 +397,7 @@ export function transformOrder(rawOrder: RawOrder): Order {
executedSellAmount,
feeAmount: new BigNumber(feeAmount),
executedFeeAmount: new BigNumber(executedFeeAmount),
executedSurplusFee: executedSurplusFee ? new BigNumber(executedSurplusFee) : null,
executedFee: executedFee ? new BigNumber(executedFee) : null,
totalFee: new BigNumber(totalFee),
cancelled: invalidated,
status,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"@cowprotocol/cms": "^0.9.0",
"@cowprotocol/contracts": "^1.3.1",
"@cowprotocol/cow-runner-game": "^0.2.9",
"@cowprotocol/cow-sdk": "^5.8.0",
"@cowprotocol/cow-sdk": "^5.10.0-RC.0",
"@cowprotocol/ethflowcontract": "cowprotocol/ethflowcontract.git#main-artifacts",
"@davatar/react": "1.8.1",
"@emotion/react": "^11.11.1",
Expand Down Expand Up @@ -343,4 +343,4 @@
"vite-tsconfig-paths": "~4.3.2",
"vitest": "~0.32.0"
}
}
}
20 changes: 16 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2414,6 +2414,17 @@
json-stringify-deterministic "^1.0.8"
multiformats "^9.6.4"

"@cowprotocol/app-data@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@cowprotocol/app-data/-/app-data-2.4.0.tgz#326e20065161e06308cf0ff429fe9dd2908c1c30"
integrity sha512-aG3CicUdR7jpY5/linxXmpL4axmiUvEwiHlOM0qKO/QdbNSntKNXjSu3r4QtHZ7BUiF1VUkcDVvvFW4D2MA0Rw==
dependencies:
ajv "^8.11.0"
cross-fetch "^3.1.5"
ipfs-only-hash "^4.0.0"
json-stringify-deterministic "^1.0.8"
multiformats "^9.6.4"

"@cowprotocol/cms@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@cowprotocol/cms/-/cms-0.9.0.tgz#f668256f7cc8ebe344cbfef018a82a2b9c8eb9dd"
Expand All @@ -2436,11 +2447,12 @@
resolved "https://registry.yarnpkg.com/@cowprotocol/cow-runner-game/-/cow-runner-game-0.2.9.tgz#3f94b3f370bd114f77db8b1d238cba3ef4e9d644"
integrity sha512-rX7HnoV+HYEEkBaqVUsAkGGo0oBrExi+d6Io+8nQZYwZk+IYLmS9jdcIObsLviM2h4YX8+iin6NuKl35AaiHmg==

"@cowprotocol/cow-sdk@^5.8.0":
version "5.8.0"
resolved "https://registry.yarnpkg.com/@cowprotocol/cow-sdk/-/cow-sdk-5.8.0.tgz#f5a4533a02e8055087a47fae6917819283c021c8"
integrity sha512-rNfkJ9wf1/x9R5L/sfTPWc8i5aAmodVb2whnlrb7JNl0BYviE1V0rtPmT8b2vwB6JWMIF41gFd9dXEWeqlavJA==
"@cowprotocol/cow-sdk@^5.10.0-RC.0":
version "5.10.0-RC.0"
resolved "https://registry.yarnpkg.com/@cowprotocol/cow-sdk/-/cow-sdk-5.10.0-RC.0.tgz#6e33a60cd0e028d9d1236f0822755727712f75dc"
integrity sha512-KneqcG7esS3hqUxHc45IQ95koThIZ6aKzBu/5YvgGq77OSFgmKjMDYayM647eAufByHCJkCt5I3TnFK8sjB9wA==
dependencies:
"@cowprotocol/app-data" "^2.4.0"
"@cowprotocol/contracts" "^1.6.0"
"@ethersproject/abstract-signer" "^5.7.0"
"@openzeppelin/merkle-tree" "^1.0.5"
Expand Down

0 comments on commit 3be8a65

Please sign in to comment.