Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release/1.48.0' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
alfetopito committed Oct 12, 2023
2 parents 4481465 + 5de0df4 commit 11d7e7c
Show file tree
Hide file tree
Showing 27 changed files with 470 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Order, OrderStatus } from 'legacy/state/orders/actions'
import { useAddOrUpdateOrders, useClearOrdersStorage } from 'legacy/state/orders/hooks'
import { classifyOrder, OrderTransitionStatus } from 'legacy/state/orders/utils'

import { useTokensForOrdersList, getTokensListFromOrders } from 'modules/orders'
import { getTokensListFromOrders, useTokensForOrdersList } from 'modules/orders'
import { apiOrdersAtom } from 'modules/orders/state/apiOrdersAtom'

import { useGpOrders } from 'api/gnosisProtocol/hooks'
Expand Down Expand Up @@ -80,6 +80,7 @@ function _transformGpOrderToStoreOrder(
summary: '',
status,
receiver: receiver || '',
fullAppData: order.fullAppData,
apiAdditionalInfo: order,
isCancelling: apiStatus === 'pending' && order.invalidated, // already cancelled in the API, not yet in the UI
// EthFlow related
Expand Down
4 changes: 4 additions & 0 deletions apps/cowswap-frontend/src/legacy/state/orders/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export interface BaseOrder extends Omit<OrderCreation, 'signingScheme'> {

// Additional information from the order available in the API
apiAdditionalInfo?: OrderInfoApi
// De-normalizing it as this is known at order placement time as `appData`,
// but when returned from the api is replaced with the `appDataHash`
// See this order response for example https://barn.api.cow.fi/goerli/api/v1/orders/0xc170856a42f38ba07a7af3ea8f299ea724ec0aa22445eb741cbad7f9dd4fcda05b0abe214ab7875562adee331deff0fe1912fe4265269bb1
fullAppData?: EnrichedOrder['fullAppData']

// Wallet specific
presignGnosisSafeTxHash?: string // Gnosis Safe tx
Expand Down
6 changes: 4 additions & 2 deletions apps/cowswap-frontend/src/legacy/utils/trade.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RADIX_DECIMAL, NATIVE_CURRENCY_BUY_ADDRESS } from '@cowprotocol/common-const'
import { isAddress, shortenAddress, formatTokenAmount, formatSymbol } from '@cowprotocol/common-utils'
import { NATIVE_CURRENCY_BUY_ADDRESS, RADIX_DECIMAL } from '@cowprotocol/common-const'
import { formatSymbol, formatTokenAmount, isAddress, shortenAddress } from '@cowprotocol/common-utils'
import {
EcdsaSigningScheme,
OrderClass,
Expand Down Expand Up @@ -156,6 +156,7 @@ export function mapUnsignedOrderToOrder({ unsignedOrder, additionalParams }: Map
sellAmountBeforeFee,
orderCreationHash,
quoteId,
appData: { fullAppData },
} = additionalParams
const status = _getOrderStatus(allowsOffchainSigning, isOnChain)

Expand All @@ -170,6 +171,7 @@ export function mapUnsignedOrderToOrder({ unsignedOrder, additionalParams }: Map
outputToken: buyToken,
quoteId,
class: additionalParams.class,
fullAppData,

// Status
status,
Expand Down
1 change: 1 addition & 0 deletions apps/cowswap-frontend/src/modules/appData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export * from './updater/AppDataUpdater'
export { useAppData, useUploadAppData } from './hooks'
export { updateHooksOnAppData, buildAppData } from './utils/buildAppData'
export { buildAppDataHooks } from './utils/buildAppDataHooks'
export * from './utils/getAppDataHooks'
export type { AppDataInfo, UploadAppDataParams } from './types'
24 changes: 24 additions & 0 deletions apps/cowswap-frontend/src/modules/appData/utils/decodeAppData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { AnyAppDataDocVersion } from '@cowprotocol/app-data'

import { Nullish } from 'types'

/**
* 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
*/
export function decodeAppData(appData: Nullish<string>): AnyAppDataDocVersion | undefined {
if (!appData) {
return undefined
}

try {
// TODO: returned value can be a valid JSON but not necessarily a valid AppDataDoc
return JSON.parse(appData)
} catch (e) {
console.info(`[decodeAppData] given appData is not a valid JSON`, appData)

return undefined
}
}
21 changes: 21 additions & 0 deletions apps/cowswap-frontend/src/modules/appData/utils/getAppDataHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AnyAppDataDocVersion } from '@cowprotocol/app-data'

import { Nullish } from 'types'

import { decodeAppData } from './decodeAppData'

import { AppDataHooks } from '../types'

/**
* Get hooks from fullAppData, which can be JSON stringified or the instance
*
* Returns undefined if the fullAppData is falsy or if there are no hooks
*/
export function getAppDataHooks(fullAppData: Nullish<AnyAppDataDocVersion | string>): AppDataHooks | undefined {
const decodedAppData = typeof fullAppData === 'string' ? decodeAppData(fullAppData) : fullAppData

if (!decodedAppData || !('hooks' in decodedAppData.metadata)) return undefined

// TODO: this requires app-data v0.9.0. Might not work for newer versions...
return decodedAppData.metadata.hooks as AppDataHooks
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useMemo } from 'react'

import { SupportedChainId } from '@cowprotocol/cow-sdk'

import { BalancesAndAllowances } from 'modules/tokens'

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

import { OrdersTableList } from './useOrdersTableList'

import { getOrderParams } from '../../../pure/OrdersTableContainer/utils/getOrderParams'
import { isParsedOrder } from '../../../utils/orderTableGroupUtils'

export function useGetOrdersToCheckPendingPermit(
ordersList: OrdersTableList,
chainId: SupportedChainId,
balancesAndAllowances: BalancesAndAllowances
) {
return useMemo(() => {
// Pick only the pending orders
return ordersList.pending.reduce((acc: ParsedOrder[], item) => {
// Only do it for regular orders (not TWAP)
if (isParsedOrder(item)) {
const { hasEnoughAllowance } = getOrderParams(chainId, balancesAndAllowances, item)

// Only if the order has not enough allowance
if (hasEnoughAllowance === false) {
acc.push(item)
}
}
return acc
}, [])
}, [balancesAndAllowances, chainId, ordersList.pending])
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import { useMemo } from 'react'
import { Order, PENDING_STATES } from 'legacy/state/orders/actions'

import { groupOrdersTable } from '../../../utils/groupOrdersTable'
import { getParsedOrderFromItem, isParsedOrder, OrderTableItem } from '../../../utils/orderTableGroupUtils'
import { getParsedOrderFromTableItem, isParsedOrder, OrderTableItem } from '../../../utils/orderTableGroupUtils'

export interface OrdersTableList {
pending: OrderTableItem[]
history: OrderTableItem[]
}

const ordersSorter = (a: OrderTableItem, b: OrderTableItem) => {
const aCreationTime = getParsedOrderFromItem(a).creationTime
const bCreationTime = getParsedOrderFromItem(b).creationTime
const aCreationTime = getParsedOrderFromTableItem(a).creationTime
const bCreationTime = getParsedOrderFromTableItem(b).creationTime

return bCreationTime.getTime() - aCreationTime.getTime()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,22 @@ import { OrdersReceiptModal } from 'modules/ordersTable/containers/OrdersReceipt
import { useSelectReceiptOrder } from 'modules/ordersTable/containers/OrdersReceiptModal/hooks'
import { OrderActions } from 'modules/ordersTable/pure/OrdersTableContainer/types'
import { buildOrdersTableUrl, parseOrdersTableUrl } from 'modules/ordersTable/utils/buildOrdersTableUrl'
import { PendingPermitUpdater, useGetOrdersPermitStatus } from 'modules/permit'
import { useBalancesAndAllowances } from 'modules/tokens'

import { useCancelOrder } from 'common/hooks/useCancelOrder'
import { useCategorizeRecentActivity } from 'common/hooks/useCategorizeRecentActivity'
import { ordersToCancelAtom, updateOrdersToCancelAtom } from 'common/hooks/useMultipleOrdersCancellation/state'
import { CancellableOrder } from 'common/utils/isOrderCancellable'
import { ParsedOrder } from 'utils/orderUtils/parseOrder'

import { useGetOrdersToCheckPendingPermit } from './hooks/useGetOrdersToCheckPendingPermit'
import { OrdersTableList, useOrdersTableList } from './hooks/useOrdersTableList'
import { useOrdersTableTokenApprove } from './hooks/useOrdersTableTokenApprove'
import { useValidatePageUrlParams } from './hooks/useValidatePageUrlParams'

import { useCategorizeRecentActivity } from '../../../../common/hooks/useCategorizeRecentActivity'
import { OrdersTableContainer, TabOrderTypes } from '../../pure/OrdersTableContainer'
import { getParsedOrderFromItem, OrderTableItem, tableItemsToOrders } from '../../utils/orderTableGroupUtils'
import { getParsedOrderFromTableItem, OrderTableItem, tableItemsToOrders } from '../../utils/orderTableGroupUtils'

function getOrdersListByIndex(ordersList: OrdersTableList, id: string): OrderTableItem[] {
return id === OPEN_TAB.id ? ordersList.pending : ordersList.history
Expand Down Expand Up @@ -73,6 +75,7 @@ export function OrdersTableWidget({
const getSpotPrice = useGetSpotPrice()
const selectReceiptOrder = useSelectReceiptOrder()
const isSafeViaWc = useIsSafeViaWc()
const ordersPermitStatus = useGetOrdersPermitStatus()

const spender = useMemo(() => (chainId ? GP_VAULT_RELAYER[chainId] : undefined), [chainId])

Expand Down Expand Up @@ -101,7 +104,7 @@ export function OrdersTableWidget({
const tokens = useMemo(() => {
const pendingOrders = isOpenOrdersTab ? ordersList.pending : []

return pendingOrders.map((item) => getParsedOrderFromItem(item).inputToken)
return pendingOrders.map((item) => getParsedOrderFromTableItem(item).inputToken)
}, [isOpenOrdersTab, ordersList.pending])

// Get effective balance
Expand Down Expand Up @@ -148,8 +151,11 @@ export function OrdersTableWidget({

useValidatePageUrlParams(orders.length, currentTabId, currentPageNumber)

const ordersToCheckPendingPermit = useGetOrdersToCheckPendingPermit(ordersList, chainId, balancesAndAllowances)

return (
<>
<PendingPermitUpdater orders={ordersToCheckPendingPermit} />
<ContentWrapper>
<OrdersTableContainer
chainId={chainId}
Expand All @@ -168,6 +174,7 @@ export function OrdersTableWidget({
allowsOffchainSigning={allowsOffchainSigning}
orderType={orderType}
pendingActivities={pendingActivity}
ordersPermitStatus={ordersPermitStatus}
>
{isOpenOrdersTab && orders.length && <MultipleCancellationMenu pendingOrders={tableItemsToOrders(orders)} />}
</OrdersTableContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export interface OrderRowProps {
orderParams: OrderParams
onClick: () => void
orderActions: OrderActions
hasValidPendingPermit?: boolean | undefined
children?: JSX.Element
}

Expand All @@ -164,6 +165,7 @@ export function OrderRow({
prices,
spotPrice,
children,
hasValidPendingPermit,
}: OrderRowProps) {
const { buyAmount, rateInfoParams, hasEnoughAllowance, hasEnoughBalance, chainId } = orderParams
const { creationTime, expirationTime, status } = order
Expand All @@ -174,7 +176,7 @@ export function OrderRow({
const showCancellationModal = orderActions.getShowCancellationModal(order)

const withWarning =
(hasEnoughBalance === false || hasEnoughAllowance === false) &&
(hasEnoughBalance === false || (hasEnoughAllowance === false && hasValidPendingPermit === false)) &&
// show the warning only for pending and scheduled orders
(status === OrderStatus.PENDING || status === OrderStatus.SCHEDULED)
const theme = useContext(ThemeContext)
Expand Down Expand Up @@ -357,7 +359,7 @@ export function OrderRow({
{hasEnoughBalance === false && (
<BalanceWarning symbol={inputTokenSymbol} isScheduled={isOrderScheduled} />
)}
{hasEnoughAllowance === false && (
{hasEnoughAllowance === false && hasValidPendingPermit === false && (
<AllowanceWarning
approve={() => orderActions.approveOrderToken(order.inputToken)}
symbol={inputTokenSymbol}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useState, useEffect, useMemo, useRef } from 'react'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import iconOrderExecution from '@cowprotocol/assets/cow-swap/orderExecution.svg'
import { SupportedChainId } from '@cowprotocol/cow-sdk'
Expand All @@ -11,19 +11,19 @@ import SVG from 'react-inlinesvg'
import { useLocation } from 'react-router-dom'
import styled from 'styled-components/macro'

import { QuestionWrapper } from 'legacy/components/QuestionHelper'
import QuestionHelper from 'legacy/components/QuestionHelper'
import QuestionHelper, { QuestionWrapper } from 'legacy/components/QuestionHelper'

import { PendingOrdersPrices } from 'modules/orders/state/pendingOrdersPricesAtom'
import { SpotPricesKeyParams } from 'modules/orders/state/spotPricesAtom'
import { ORDERS_TABLE_PAGE_SIZE } from 'modules/ordersTable/const/tabs'
import {
CheckboxCheckmark,
TableHeader,
TableRowCheckbox,
TableRowCheckboxWrapper,
CheckboxCheckmark,
} from 'modules/ordersTable/pure/OrdersTableContainer/styled'
import { OrderActions } from 'modules/ordersTable/pure/OrdersTableContainer/types'
import { OrdersPermitStatus } from 'modules/permit'
import { BalancesAndAllowances } from 'modules/tokens'

import { ordersTableFeatures } from 'common/constants/featureFlags'
Expand All @@ -40,7 +40,7 @@ import { getOrderParams } from './utils/getOrderParams'

import { buildOrdersTableUrl } from '../../utils/buildOrdersTableUrl'
import {
getParsedOrderFromItem,
getParsedOrderFromTableItem,
isParsedOrder,
OrderTableItem,
tableItemsToOrders,
Expand Down Expand Up @@ -206,6 +206,7 @@ export interface OrdersTableProps {
balancesAndAllowances: BalancesAndAllowances
getSpotPrice: (params: SpotPricesKeyParams) => Price<Currency, Currency> | null
orderActions: OrderActions
ordersPermitStatus: OrdersPermitStatus
}

export function OrdersTable({
Expand All @@ -219,6 +220,7 @@ export function OrdersTable({
getSpotPrice,
orderActions,
currentPageNumber,
ordersPermitStatus,
}: OrdersTableProps) {
const location = useLocation()
const [isRateInverted, setIsRateInverted] = useState(false)
Expand Down Expand Up @@ -261,14 +263,14 @@ export function OrdersTable({
}, [showOrdersExplainerBanner])

const cancellableOrders = useMemo(
() => ordersPage.filter((item) => isOrderOffChainCancellable(getParsedOrderFromItem(item))),
() => ordersPage.filter((item) => isOrderOffChainCancellable(getParsedOrderFromTableItem(item))),
[ordersPage]
)

const allOrdersSelected = useMemo(() => {
if (!cancellableOrders.length) return false

return cancellableOrders.every((item) => selectedOrdersMap[getParsedOrderFromItem(item).id])
return cancellableOrders.every((item) => selectedOrdersMap[getParsedOrderFromTableItem(item).id])
}, [cancellableOrders, selectedOrdersMap])

const getPageUrl = useCallback((index: number) => buildOrdersTableUrl(location, { pageNumber: index }), [location])
Expand Down Expand Up @@ -400,7 +402,7 @@ export function OrdersTable({

<Rows>
{ordersPage.map((item) => {
const { inputToken, outputToken } = getParsedOrderFromItem(item)
const { inputToken, outputToken } = getParsedOrderFromTableItem(item)
const spotPrice = getSpotPrice({
chainId: chainId as SupportedChainId,
sellTokenAddress: inputToken.address,
Expand All @@ -410,6 +412,10 @@ export function OrdersTable({
if (isParsedOrder(item)) {
const order = item

const orderParams = getOrderParams(chainId, balancesAndAllowances, order)

const hasValidPendingPermit = ordersPermitStatus[order.id]

return (
<OrderRow
key={order.id}
Expand All @@ -419,10 +425,11 @@ export function OrdersTable({
order={order}
spotPrice={spotPrice}
prices={pendingOrdersPrices[order.id]}
orderParams={getOrderParams(chainId, balancesAndAllowances, order)}
orderParams={orderParams}
isRateInverted={isRateInverted}
orderActions={orderActions}
onClick={() => orderActions.selectReceiptOrder(order)}
hasValidPendingPermit={hasValidPendingPermit}
/>
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,6 @@ export default (
getSpotPrice={() => null}
orderActions={orderActions}
orderType={TabOrderTypes.LIMIT}
ordersPermitStatus={{}}
/>
)
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export function OrdersTableContainer({
children,
orderType,
pendingActivities,
ordersPermitStatus,
}: OrdersProps) {
const content = () => {
if (!isWalletConnected) {
Expand Down Expand Up @@ -233,6 +234,7 @@ export function OrdersTableContainer({
balancesAndAllowances={balancesAndAllowances}
getSpotPrice={getSpotPrice}
orderActions={orderActions}
ordersPermitStatus={ordersPermitStatus}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export function getOrderParams(
balancesAndAllowances: BalancesAndAllowances,
order: ParsedOrder
): OrderParams {
const sellAmount = CurrencyAmount.fromRawAmount(order.inputToken, order.sellAmount.toString())
const buyAmount = CurrencyAmount.fromRawAmount(order.outputToken, order.buyAmount.toString())
const sellAmount = CurrencyAmount.fromRawAmount(order.inputToken, order.sellAmount)
const buyAmount = CurrencyAmount.fromRawAmount(order.outputToken, order.buyAmount)

const rateInfoParams: RateInfoParams = {
chainId,
Expand Down
Loading

0 comments on commit 11d7e7c

Please sign in to comment.