Skip to content

Commit 4c9e07f

Browse files
Release 2026-06-24 (#7736)
## Summary RELEASE ## Changes 2a7a9a9 feat(widget): control tokens switching (#7717) 8942c59 feat: Widget Configurator Revamp (#7604) 5a38bec feat: add balancec-watcher updater [pr 2 - connection logic] (#7640) e532bc8 fix(widget): add iframe loading retry logic (#7636) ef110aa fix(trade-state): preserve URL chainId on first load when wallet is connected (#7692) d965091 fix: tighten cow-fi content links and remote token parsing (#7619) 257f304 fix: tighten frontend trust boundaries and client secrets (#7623)
2 parents 58b425e + 0cf0fd2 commit 4c9e07f

237 files changed

Lines changed: 12721 additions & 3566 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/deployment-v2.yml

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name: Deployment v2
22

33
on:
44
push:
5-
branches: [ main ]
6-
tags: [ cowswap-*, explorer-* ]
5+
branches: [main]
6+
tags: [cowswap-*, explorer-*]
77

88
concurrency:
99
group: ${{ startsWith(github.ref, 'refs/tags/') && format('release-tag-{0}', github.sha) || 'release-branch-sync' }}
@@ -19,11 +19,13 @@ jobs:
1919
if: startsWith(github.ref, 'refs/tags/')
2020
runs-on: ubuntu-latest
2121
outputs:
22+
release-commit: ${{ steps.collect.outputs.release-commit }}
2223
release-tags: ${{ steps.collect.outputs.release-tags }}
2324
steps:
2425
- name: Checkout code
2526
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2627
with:
28+
ref: refs/heads/main
2729
fetch-depth: 0
2830
persist-credentials: false
2931

@@ -32,9 +34,15 @@ jobs:
3234
run: |
3335
set -euo pipefail
3436
35-
git fetch --tags origin
37+
git fetch --tags origin main
3638
3739
release_commit="$(git rev-list -n 1 "${GITHUB_REF}")"
40+
41+
if ! git merge-base --is-ancestor "${release_commit}" "origin/main"; then
42+
echo "::error::Release tag ${GITHUB_REF_NAME} does not point to a commit reachable from origin/main"
43+
exit 1
44+
fi
45+
3846
release_tags="$(
3947
git tag --points-at "${release_commit}" \
4048
| sort \
@@ -45,6 +53,7 @@ jobs:
4553
release_tags="${GITHUB_REF_NAME}"
4654
fi
4755
56+
echo "release-commit=${release_commit}" >> "$GITHUB_OUTPUT"
4857
echo "release-tags=${release_tags}" >> "$GITHUB_OUTPUT"
4958
5059
sync-develop:
@@ -61,6 +70,7 @@ jobs:
6170
- name: Checkout workflow repository
6271
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6372
with:
73+
ref: refs/heads/main
6474
fetch-depth: 0
6575
persist-credentials: false
6676

@@ -132,6 +142,7 @@ jobs:
132142
- name: Checkout workflow repository
133143
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
134144
with:
145+
ref: refs/heads/main
135146
fetch-depth: 0
136147
persist-credentials: false
137148

@@ -148,15 +159,17 @@ jobs:
148159
run: |
149160
set -euo pipefail
150161
151-
git fetch origin main staging
162+
git fetch origin main staging --tags
152163
git checkout -B staging origin/staging
153-
git merge --ff-only origin/main
164+
git merge --ff-only "${RELEASE_COMMIT}"
154165
git push origin staging
166+
env:
167+
RELEASE_COMMIT: ${{ needs.collect-release-metadata.outputs.release-commit }}
155168

156169
notify-production-approval:
157170
name: Notify Slack for production approval
158171
if: startsWith(github.ref, 'refs/tags/cowswap-') || startsWith(github.ref, 'refs/tags/explorer-')
159-
needs: [ collect-release-metadata, sync-staging ]
172+
needs: [collect-release-metadata, sync-staging]
160173
runs-on: ubuntu-latest
161174
steps:
162175
- name: Notify Slack
@@ -174,13 +187,14 @@ jobs:
174187
sync-production:
175188
name: Fast-forward production to main
176189
if: startsWith(github.ref, 'refs/tags/cowswap-') || startsWith(github.ref, 'refs/tags/explorer-')
177-
needs: [ collect-release-metadata, notify-production-approval ]
190+
needs: [collect-release-metadata, notify-production-approval]
178191
runs-on: ubuntu-latest
179192
environment: production # Env configured in GitHub UI. Requires manual approval before this job can run
180193
steps:
181194
- name: Checkout workflow repository
182195
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
183196
with:
197+
ref: refs/heads/main
184198
fetch-depth: 0
185199
persist-credentials: false
186200
- name: Setup release sync
@@ -196,7 +210,9 @@ jobs:
196210
run: |
197211
set -euo pipefail
198212
199-
git fetch origin main production
213+
git fetch origin main production --tags
200214
git checkout -B production origin/production
201-
git merge --ff-only origin/main
215+
git merge --ff-only "${RELEASE_COMMIT}"
202216
git push origin production
217+
env:
218+
RELEASE_COMMIT: ${{ needs.collect-release-metadata.outputs.release-commit }}

apps/cow-fi/app/(main)/tokens/[tokenId]/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ type Props = {
1515

1616
function getTokenMetaData(token: TokenDetails) {
1717
const { name, symbol, change24h, priceUsd } = token
18-
const change24 = parseFloat(change24h as string)
19-
const change24hFormatted = change24.toFixed(2)
20-
const isIncrease = parseFloat(change24h as string) >= 0
21-
const priceChangeEmoji = isIncrease ? '🟢' : '🔴'
22-
const changeDirection = isIncrease ? '▲' : '▼'
23-
const title = `${priceChangeEmoji} ${name} (${symbol}) $${priceUsd} (${change24hFormatted}% ${changeDirection}) - ${CONFIG.metatitle_tokenDetail} - ${CONFIG.title.default}`
18+
const priceSegment = typeof priceUsd === 'number' ? `$${priceUsd}` : 'Price unavailable'
19+
const change24hFormatted = typeof change24h === 'number' ? change24h.toFixed(2) : '0.00'
20+
const isIncrease = typeof change24h === 'number' ? change24h >= 0 : true
21+
const priceChangeEmoji = typeof change24h === 'number' ? (isIncrease ? '🟢' : '🔴') : '⚪'
22+
const changeDirection = typeof change24h === 'number' ? (isIncrease ? '▲' : '▼') : '•'
23+
const title = `${priceChangeEmoji} ${name} (${symbol}) ${priceSegment} (${change24hFormatted}% ${changeDirection}) - ${CONFIG.metatitle_tokenDetail} - ${CONFIG.title.default}`
2424
const description = `Track the latest ${name} (${symbol}) price, market cap, trading volume, and more with CoW DAO's live ${name} price chart.`
2525

2626
return { title, description }

apps/cow-fi/app/(main)/widget/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const widgetParams: CowSwapWidgetParams = {
5151
appCode: 'CoW Protocol: Widget Demo',
5252
theme: 'light',
5353
standaloneMode: true,
54-
width: '100%',
54+
rootStyle: { width: '100%' },
5555
}
5656

5757
export default function Page(): ReactNode {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/** @jest-environment jsdom */
2+
3+
import type { JSX, ReactNode } from 'react'
4+
5+
import { render } from '@testing-library/react'
6+
7+
import { ChartSection } from '.'
8+
9+
const mockUseQuery = jest.fn()
10+
11+
jest.mock('@apollo/client', () => ({
12+
useQuery: (...args: unknown[]) => mockUseQuery(...args),
13+
}))
14+
15+
jest.mock('@visx/responsive', () => ({
16+
ParentSize: ({ children }: { children: ({ width }: { width: number }) => JSX.Element }) => children({ width: 320 }),
17+
}))
18+
19+
jest.mock('services/uniswap-price/queries', () => ({
20+
tokenPriceQuery: 'token-price-query',
21+
HistoryDuration: {
22+
Day: 'day',
23+
},
24+
Chain: {
25+
Ethereum: 'ethereum',
26+
},
27+
}))
28+
29+
jest.mock('util/fixChart', () => ({
30+
fixChart: jest.fn(() => ({ prices: [], blanks: [] })),
31+
}))
32+
33+
jest.mock('lib/hooks/usePriceHistory', () => ({
34+
usePriceHistory: jest.fn(() => null),
35+
}))
36+
37+
jest.mock('../Chart/LoadingChart', () => ({
38+
ChartContainer: ({ children }: { children: ReactNode }) => <div>{children}</div>,
39+
LoadingChart: () => <div>Loading chart</div>,
40+
}))
41+
42+
jest.mock('../Chart', () => ({
43+
Chart: () => <div>Chart</div>,
44+
TimePeriod: {
45+
DAY: 'DAY',
46+
},
47+
}))
48+
49+
describe('ChartSection', () => {
50+
beforeEach(() => {
51+
jest.clearAllMocks()
52+
mockUseQuery.mockReturnValue({ data: undefined, loading: false })
53+
})
54+
55+
it('skips the Ethereum price query when the ethereum platform is missing', () => {
56+
expect(() =>
57+
render(
58+
<ChartSection
59+
platforms={{
60+
base: {
61+
contractAddress: '0x4200000000000000000000000000000000000006',
62+
decimalPlace: 18,
63+
},
64+
}}
65+
/>,
66+
),
67+
).not.toThrow()
68+
69+
expect(mockUseQuery).toHaveBeenCalledWith('token-price-query', {
70+
variables: undefined,
71+
skip: true,
72+
})
73+
})
74+
})

apps/cow-fi/components/ChartSection/index.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { JSX } from 'react'
12
import { useMemo } from 'react'
23

34
import { useQuery } from '@apollo/client'
@@ -10,8 +11,7 @@ import { fixChart } from 'util/fixChart'
1011
import { usePriceHistory } from 'lib/hooks/usePriceHistory'
1112

1213
import { Chart, TimePeriod } from '../Chart'
13-
import { ChartContainer } from '../Chart/LoadingChart'
14-
import { LoadingChart } from '../Chart/LoadingChart'
14+
import { ChartContainer, LoadingChart } from '../Chart/LoadingChart'
1515

1616
type ChartSectionProps = {
1717
platforms: Platforms
@@ -23,18 +23,20 @@ type QueryVars = {
2323
address: string
2424
}
2525

26-
export function ChartSection({ platforms }: ChartSectionProps) {
26+
export function ChartSection({ platforms }: ChartSectionProps): JSX.Element {
27+
const ethereumAddress = platforms.ethereum?.contractAddress
28+
2729
const queryVariables = useMemo<QueryVars | undefined>(() => {
28-
if (!platforms.ethereum.contractAddress) {
30+
if (!ethereumAddress) {
2931
return undefined
3032
}
3133

3234
return {
3335
duration: HistoryDuration.Day,
3436
chain: Chain.Ethereum,
35-
address: platforms.ethereum.contractAddress,
37+
address: ethereumAddress,
3638
}
37-
}, [platforms.ethereum.contractAddress])
39+
}, [ethereumAddress])
3840

3941
const { data, loading } = useQuery(tokenPriceQuery, {
4042
variables: queryVariables,

apps/cow-fi/data/cow-amm/const.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export const FAQ_DATA = [
215215
<>
216216
CoW AMM pools live on Balancer can be found at{' '}
217217
<Link
218-
href="http://balancer.fi/pools/cow"
218+
href="https://balancer.fi/pools/cow"
219219
external
220220
utmContent="cow-amm-balancer-pools"
221221
onClick={() =>

0 commit comments

Comments
 (0)