Skip to content

Commit deb31b0

Browse files
authored
Merge pull request #6356 from cowprotocol/main
Main -> develop
2 parents d0b5685 + e192b33 commit deb31b0

File tree

11 files changed

+365
-10
lines changed

11 files changed

+365
-10
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"apps/cowswap-frontend": "1.119.0",
2+
"apps/cowswap-frontend": "1.119.1",
33
"apps/explorer": "2.55.0",
44
"libs/permit-utils": "1.0.0",
55
"libs/widget-lib": "0.20.0",

apps/cowswap-frontend/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## [1.119.1](https://github.com/cowprotocol/cowswap/compare/cowswap-v1.119.0...cowswap-v1.119.1) (2025-10-03)
4+
5+
6+
### Bug Fixes
7+
8+
* **account-modal:** prevent crash with unexpected empty appData.metadata ([#6335](https://github.com/cowprotocol/cowswap/issues/6335)) ([db263c7](https://github.com/cowprotocol/cowswap/commit/db263c7846f999266cecaf1acaea4766c29d73cc))
9+
* **bridging:** disable Across bridging provider on prod like envs ([#6336](https://github.com/cowprotocol/cowswap/issues/6336)) ([f7e21fe](https://github.com/cowprotocol/cowswap/commit/f7e21fe17fc4ba7937b8a4680cce5bf90c966391))
10+
311
## [1.119.0](https://github.com/cowprotocol/cowswap/compare/cowswap-v1.118.13...cowswap-v1.119.0) (2025-10-02)
412

513

apps/cowswap-frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cowprotocol/cowswap",
3-
"version": "1.119.0",
3+
"version": "1.119.1",
44
"description": "CoW Swap",
55
"main": "index.js",
66
"author": "",

apps/cowswap-frontend/src/common/containers/OrderHooksDetails/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export function OrderHooksDetails({ appData, children, margin, isTradeConfirmati
4242
if (isTradeConfirmation) mutate()
4343
}, [isTradeConfirmation, mutate])
4444

45-
if (!appDataDoc) return null
45+
// Not all versions of appData have metadata
46+
if (!appDataDoc?.metadata) return null
4647

4748
const metadata = appDataDoc.metadata as cowAppDataLatestScheme.Metadata
4849

apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { BalancesCombinedUpdater } from 'modules/combinedBalances/updater/Balanc
1919
import { InFlightOrderFinalizeUpdater } from 'modules/ethFlow'
2020
import { CowEventsUpdater, InjectedWidgetUpdater, useInjectedWidgetParams } from 'modules/injectedWidget'
2121
import { FinalizeTxUpdater } from 'modules/onchainTransactions'
22-
import { ProgressBarExecutingOrdersUpdater } from 'modules/orderProgressBar'
22+
import { OrderProgressEventsUpdater, ProgressBarExecutingOrdersUpdater } from 'modules/orderProgressBar'
2323
import { OrdersNotificationsUpdater } from 'modules/orders'
2424
import { useSourceChainId } from 'modules/tokensList'
2525
import { TradeType, useTradeTypeInfo } from 'modules/trade'
@@ -91,6 +91,7 @@ export function Updaters(): ReactNode {
9191
<UsdPricesUpdater />
9292
<OrdersNotificationsUpdater />
9393
<ProgressBarExecutingOrdersUpdater />
94+
<OrderProgressEventsUpdater />
9495
<SolversInfoUpdater />
9596
<AnnouncementsUpdater />
9697
<BridgingEnabledUpdater />
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { getProgressBarStepName } from './useOrderProgressBarProps'
2+
3+
import { OrderProgressBarStepName } from '../constants'
4+
import { OrderProgressBarState } from '../types'
5+
6+
const OPEN_STATUS = 'open' as OrderProgressBarState['backendApiStatus']
7+
const EXECUTING_STATUS = 'executing' as OrderProgressBarState['backendApiStatus']
8+
9+
describe('getProgressBarStepName', () => {
10+
function callGetProgressBarStepName({
11+
isUnfillable = false,
12+
backendApiStatus,
13+
previousStepName = OrderProgressBarStepName.SOLVING,
14+
previousBackendApiStatus,
15+
}: {
16+
isUnfillable?: boolean
17+
backendApiStatus?: OrderProgressBarState['backendApiStatus']
18+
previousStepName?: OrderProgressBarStepName | undefined
19+
previousBackendApiStatus?: OrderProgressBarState['previousBackendApiStatus']
20+
}): OrderProgressBarStepName {
21+
return getProgressBarStepName(
22+
isUnfillable,
23+
false, // isCancelled
24+
false, // isExpired
25+
false, // isCancelling
26+
undefined, // cancellationTriggered
27+
false, // isConfirmed
28+
null, // countdown
29+
backendApiStatus,
30+
previousBackendApiStatus,
31+
previousStepName,
32+
undefined, // bridgingStatus
33+
false, // isBridgingTrade
34+
)
35+
}
36+
37+
it('keeps the solving animation when an order recovers from unfillable without backend status', () => {
38+
const result = callGetProgressBarStepName({
39+
previousStepName: OrderProgressBarStepName.UNFILLABLE,
40+
})
41+
42+
expect(result).toBe(OrderProgressBarStepName.SOLVING)
43+
})
44+
45+
it('keeps the solving animation when backend status is open after an unfillable recovery', () => {
46+
const result = callGetProgressBarStepName({
47+
backendApiStatus: OPEN_STATUS,
48+
previousStepName: OrderProgressBarStepName.UNFILLABLE,
49+
})
50+
51+
expect(result).toBe(OrderProgressBarStepName.SOLVING)
52+
})
53+
54+
it('still transitions to executing when the backend reports progress', () => {
55+
const result = callGetProgressBarStepName({
56+
backendApiStatus: EXECUTING_STATUS,
57+
previousStepName: OrderProgressBarStepName.UNFILLABLE,
58+
previousBackendApiStatus: OPEN_STATUS,
59+
})
60+
61+
expect(result).toBe(OrderProgressBarStepName.EXECUTING)
62+
})
63+
})

apps/cowswap-frontend/src/modules/orderProgressBar/hooks/useOrderProgressBarProps.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ function useProgressBarStepNameUpdater(
347347
setProgressBarStepName(orderId, name || DEFAULT_STEP_NAME)
348348
}
349349

350-
let timer: NodeJS.Timeout
350+
let timer: NodeJS.Timeout | undefined
351351

352352
const timeSinceLastChange = lastTimeChangedSteps ? Date.now() - lastTimeChangedSteps : 0
353353

@@ -371,15 +371,15 @@ function useProgressBarStepNameUpdater(
371371
}
372372

373373
return () => {
374-
clearInterval(timer)
374+
if (timer) clearTimeout(timer)
375375
}
376376
}, [orderId, stepName, lastTimeChangedSteps, setProgressBarStepName])
377377
}
378378

379379
// TODO: Break down this large function into smaller functions
380380
// TODO: Reduce function complexity by extracting logic
381381
// eslint-disable-next-line complexity
382-
function getProgressBarStepName(
382+
export function getProgressBarStepName(
383383
isUnfillable: boolean,
384384
isCancelled: boolean,
385385
isExpired: boolean,
@@ -438,6 +438,13 @@ function getProgressBarStepName(
438438
} else if (isUnfillable) {
439439
// out of market order
440440
return OrderProgressBarStepName.UNFILLABLE
441+
} else if (
442+
(backendApiStatus == null || backendApiStatus === 'open' || backendApiStatus === 'scheduled') &&
443+
previousStepName === OrderProgressBarStepName.UNFILLABLE
444+
) {
445+
// Order just recovered from being unfillable but backend has not progressed yet.
446+
// Keep showing the solving animation so the favicon restarts instead of idling.
447+
return OrderProgressBarStepName.SOLVING
441448
} else if (backendApiStatus === 'active' && countdown === 0) {
442449
// solving, but took longer than stipulated countdown
443450
return OrderProgressBarStepName.DELAYED

apps/cowswap-frontend/src/modules/orderProgressBar/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Updaters
22

33
export { ProgressBarExecutingOrdersUpdater } from './updaters/ProgressBarExecutingOrdersUpdater'
4+
export { OrderProgressEventsUpdater } from './updaters/OrderProgressEventsUpdater'
45

56
// Containers
67
export { SurplusModalSetup } from './containers/SurplusModalSetup'
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import type { OrderFillability } from 'common/hooks/usePendingOrdersFillability'
2+
3+
import { computeUnfillableOrderIds, getNewlyFillableOrderIds } from './OrderProgressEventsUpdater'
4+
5+
type TestOrder = {
6+
id: string
7+
isUnfillable?: boolean
8+
}
9+
10+
const FILLABILITY_OK: OrderFillability = {
11+
hasEnoughBalance: true,
12+
hasEnoughAllowance: true,
13+
hasPermit: false,
14+
}
15+
16+
const FILLABILITY_LACKING_BALANCE: OrderFillability = {
17+
hasEnoughBalance: false,
18+
hasEnoughAllowance: true,
19+
hasPermit: false,
20+
}
21+
22+
const FILLABILITY_LACKING_ALLOWANCE: OrderFillability = {
23+
hasEnoughBalance: true,
24+
hasEnoughAllowance: false,
25+
hasPermit: false,
26+
}
27+
28+
describe('computeUnfillableOrderIds', () => {
29+
it('includes orders flagged as unfillable by price', () => {
30+
const orders: TestOrder[] = [{ id: '1', isUnfillable: true }]
31+
32+
const result = computeUnfillableOrderIds(orders, {})
33+
34+
expect(result).toEqual(['1'])
35+
})
36+
37+
it('includes orders lacking balance or allowance', () => {
38+
const orders: TestOrder[] = [{ id: '2' }]
39+
40+
const result = computeUnfillableOrderIds(orders, {
41+
'2': FILLABILITY_LACKING_BALANCE,
42+
})
43+
44+
expect(result).toEqual(['2'])
45+
})
46+
47+
it('deduplicates orders flagged by both sources', () => {
48+
const orders: TestOrder[] = [{ id: '3', isUnfillable: true }]
49+
50+
const result = computeUnfillableOrderIds(orders, {
51+
'3': FILLABILITY_LACKING_ALLOWANCE,
52+
})
53+
54+
expect(result).toEqual(['3'])
55+
})
56+
57+
it('ignores orders that are fillable and not flagged', () => {
58+
const orders: TestOrder[] = [{ id: '4', isUnfillable: false }, { id: '5' }]
59+
60+
const result = computeUnfillableOrderIds(orders, {
61+
'4': FILLABILITY_OK,
62+
'5': FILLABILITY_OK,
63+
})
64+
65+
expect(result).toEqual([])
66+
})
67+
})
68+
69+
describe('getNewlyFillableOrderIds', () => {
70+
it('returns orders that were previously unfillable but not in the current set', () => {
71+
const previous = new Set(['1', '2', '3'])
72+
const current = new Set(['2', '3', '4'])
73+
74+
const result = getNewlyFillableOrderIds(previous, current)
75+
76+
expect(result).toEqual(['1'])
77+
})
78+
79+
it('returns an empty list when nothing recovered', () => {
80+
const previous = new Set(['1'])
81+
const current = new Set(['1'])
82+
83+
const result = getNewlyFillableOrderIds(previous, current)
84+
85+
expect(result).toEqual([])
86+
})
87+
88+
it('handles an empty previous set', () => {
89+
const previous = new Set<string>()
90+
const current = new Set(['1'])
91+
92+
const result = getNewlyFillableOrderIds(previous, current)
93+
94+
expect(result).toEqual([])
95+
})
96+
})

0 commit comments

Comments
 (0)