Skip to content

Commit 1d187b9

Browse files
ci(release): publish latest release
1 parent 6096d68 commit 1d187b9

906 files changed

Lines changed: 42476 additions & 17634 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.

.agents/skills/argent-react-native-app-workflow/SKILL.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,34 @@ Once you discover the correct build/run workflow for a project, **save it to pro
151151

152152
For full simulator setup workflow, refer to the `argent-ios-simulator-setup` skill.
153153

154+
### 3.6 Verifying Local Release-Variant Builds — Stale-Code Gotchas
155+
156+
**Applies to Android local release-variant builds** (`bun mobile android:<flavor>:release:local`, i.e. `apps/mobile/scripts/runAndroidLocal.sh`). Release variants **embed the JS bundle in the APK**, so a verify-on-device loop can silently test **old code** through **two independent caching layers**. Each makes a change look like it had "no effect" when it was never in the installed APK. **Both must be defeated — disabling one alone is not enough.** `runAndroidLocal.sh` handles both by default; this section is for recognizing the symptoms if a build looks stale or you build with another command.
157+
158+
#### Gotcha 1 — EAS build cache reinstalls a stale APK
159+
160+
`apps/mobile/app.config.ts` sets `experiments.buildCacheProvider: 'eas'`. `expo run:android` computes a **native** fingerprint and, on a match, downloads + installs a cached APK instead of building. A **JS-only** change does not move the native fingerprint, so for a release variant it reinstalls an APK with old JS.
161+
162+
- **Symptom (logs):** `Searching builds with matching fingerprint on EAS servers``Successfully downloaded cached build` → install path under `…/eas-build-run-cache/….apk`.
163+
- **Detection:** you changed only JS/TS, yet the install line points at an `eas-build-run-cache` path.
164+
- **Fix:** build via `runAndroidLocal.sh` — it exports `EXPO_LOCAL_NO_BUILD_CACHE=1`, which gates the provider off in `app.config.ts` so a real build runs. Confirm `› Building app...` in the logs (not "downloaded cached build"). If invoking `expo run:android` directly, export `EXPO_LOCAL_NO_BUILD_CACHE=1` yourself.
165+
166+
#### Gotcha 2 — gradle `createBundle<Variant>JsAndAssets` stays UP-TO-DATE
167+
168+
Even with the EAS cache off, gradle's incremental check misses changes to monorepo JS sources (e.g. `packages/uniswap/**`), so the bundle task stays `UP-TO-DATE` and the APK embeds the **previously-bundled** `index.android.bundle`.
169+
170+
- **Symptom (logs):** `> Task :app:createBundleDevReleaseJsAndAssets UP-TO-DATE`.
171+
- **Detection:** compare the embedded bundle mtime to your edit time:
172+
```bash
173+
ls -la apps/mobile/android/app/build/generated/assets/createBundle<Variant>JsAndAssets/index.android.bundle
174+
```
175+
- **Fix:** `runAndroidLocal.sh` deletes the bundle task outputs by default (pass `--no-clean-js` to skip for native-only rebuilds). To clear them manually, remove:
176+
- `apps/mobile/android/app/build/generated/assets/createBundle<Variant>JsAndAssets`
177+
- `apps/mobile/android/app/build/generated/res/createBundle<Variant>JsAndAssets`
178+
- `apps/mobile/android/app/build/intermediates/assets/<variant>`
179+
180+
A successful regen logs `> Task :app:createBundle<Variant>JsAndAssets` (no `UP-TO-DATE`) and `Writing bundle output to …`. `<Variant>` is the capitalized gradle variant (`DevRelease`, `BetaRelease`, `ProdRelease`); `<variant>` is the camelCase form (`devRelease`, …).
181+
154182
---
155183

156184
## 4. Runtime Problems in the App

RELEASE

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
IPFS hash of the deployment:
2-
- CIDv0: `QmcXGyQ2eF5eus7j3PKm4mRut7EV5X2qcB9ZMoufoZdCKG`
3-
- CIDv1: `bafybeigsxrw3dbnn44hhyi25tyc7dzcggbsbtkqhinpidom2hftu5jmmr4`
2+
- CIDv0: `QmeFNQ5YKGi3RfGVHatRvmBCpc95MLetgWruN5oDNCgGTX`
3+
- CIDv1: `bafybeihmmcsoeabmzjedko3molgj56em3smlek547ljl7fgj6wilejyzay`
44

55
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
66

@@ -10,5 +10,5 @@ You can also access the Uniswap Interface from an IPFS gateway.
1010
Your Uniswap settings are never remembered across different URLs.
1111

1212
IPFS gateways:
13-
- https://bafybeigsxrw3dbnn44hhyi25tyc7dzcggbsbtkqhinpidom2hftu5jmmr4.ipfs.dweb.link/
14-
- [ipfs://QmcXGyQ2eF5eus7j3PKm4mRut7EV5X2qcB9ZMoufoZdCKG/](ipfs://QmcXGyQ2eF5eus7j3PKm4mRut7EV5X2qcB9ZMoufoZdCKG/)
13+
- https://bafybeihmmcsoeabmzjedko3molgj56em3smlek547ljl7fgj6wilejyzay.ipfs.dweb.link/
14+
- [ipfs://QmeFNQ5YKGi3RfGVHatRvmBCpc95MLetgWruN5oDNCgGTX/](ipfs://QmeFNQ5YKGi3RfGVHatRvmBCpc95MLetgWruN5oDNCgGTX/)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
web/5.148.9
1+
web/5.149.0

apps/extension/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@
117117
"dev:firefox": "nx dev:firefox extension",
118118
"env:local:download": "nx env:local:download extension",
119119
"env:local:upload": "nx env:local:upload extension",
120-
"format": "nx format extension",
121-
"format:check": "nx format:check extension",
120+
"format": "nx run extension:format",
121+
"format:check": "nx run extension:format:check",
122122
"lint": "nx lint extension",
123123
"lint:fix": "nx lint:fix extension",
124124
"postinstall": "nx postinstall extension",

apps/extension/project.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
"outputs": ["{projectRoot}/.wxt/types", "{projectRoot}/.wxt/tsconfig.json", "{projectRoot}/.wxt/wxt.d.ts"]
9595
},
9696
"config:pull": {
97-
"command": "if [ \"$USE_NEW_CONFIGS\" = \"true\" ]; then bun config:pull extension --env \"${CONFIG_ENV:-development}\"; fi",
97+
"command": "if [ \"$USE_NEW_CONFIGS\" = \"true\" ] && [ \"$SKIP_CONFIG_PULL\" != \"true\" ]; then bun config:pull extension --env \"${CONFIG_ENV:-development}\"; fi",
9898
"options": { "cwd": "{workspaceRoot}" }
9999
},
100100
"snapshots": {
@@ -176,7 +176,7 @@
176176
"BUILD_NUM": "0"
177177
}
178178
},
179-
"inputs": ["dependencies", "sourceFiles", "tsConfig"],
179+
"inputs": ["sourceFiles"],
180180
"outputs": ["{projectRoot}/.output/chrome-mv3"],
181181
"cache": true,
182182
"dependsOn": ["^build", "prepare"]
@@ -186,7 +186,7 @@
186186
"options": {
187187
"cwd": "{projectRoot}"
188188
},
189-
"inputs": ["dependencies", "sourceFiles", "tsConfig"],
189+
"inputs": ["sourceFiles"],
190190
"outputs": ["{projectRoot}/build"],
191191
"cache": true,
192192
"dependsOn": ["^build", "prepare"]
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import { PositionStatus } from '@uniswap/client-data-api/dist/data/v1/poolTypes_pb'
2+
import { PoolsTab } from 'src/app/components/tabs/PoolsTab'
3+
import { render, screen } from 'src/test/test-utils'
4+
import { useWalletPositions } from 'uniswap/src/features/positions/hooks/useWalletPositions'
5+
6+
jest.mock('uniswap/src/features/positions/hooks/useWalletPositions', () => ({
7+
useWalletPositions: jest.fn(),
8+
}))
9+
10+
jest.mock('wallet/src/features/transactions/hooks/usePendingLiquidityTransactionsChangeListener', () => ({
11+
usePendingLiquidityTransactionsChangeListener: jest.fn(),
12+
}))
13+
14+
jest.mock('uniswap/src/features/chains/hooks/useEnabledChains', () => ({
15+
useEnabledChains: () => ({ chains: [1] }),
16+
}))
17+
18+
jest.mock('utilities/src/react/useInfiniteScroll', () => ({
19+
useInfiniteScroll: () => ({ sentinelRef: { current: null } }),
20+
}))
21+
22+
jest.mock('uniswap/src/components/portfolio/PositionItem/PositionItem', () => ({
23+
PositionItem: ({ positionInfo }: { positionInfo: { poolId: string } }) => {
24+
const { Text } = jest.requireActual('ui/src')
25+
return <Text testID={`position-${positionInfo.poolId}`}>{positionInfo.poolId}</Text>
26+
},
27+
}))
28+
29+
const mockUseWalletPositions = useWalletPositions as jest.MockedFunction<typeof useWalletPositions>
30+
31+
const baseResult = {
32+
positions: [],
33+
hiddenPositions: [],
34+
allPositions: [],
35+
isLoading: false,
36+
isFetching: false,
37+
isFetchingNextPage: false,
38+
isPlaceholderData: false,
39+
hasNextPage: false,
40+
hasData: true,
41+
error: null,
42+
refetch: jest.fn(),
43+
fetchNextPage: jest.fn(),
44+
} as unknown as ReturnType<typeof useWalletPositions>
45+
46+
const position = (poolId: string, status: PositionStatus = PositionStatus.IN_RANGE): never =>
47+
({ poolId, tokenId: 't', chainId: 1, status }) as never
48+
49+
describe('PoolsTab', () => {
50+
beforeEach(() => {
51+
jest.clearAllMocks()
52+
})
53+
54+
it('renders the error state when the query errors before any data', () => {
55+
mockUseWalletPositions.mockReturnValue({
56+
...baseResult,
57+
hasData: false,
58+
error: new Error('boom') as never,
59+
})
60+
61+
render(<PoolsTab address="0xabc" />)
62+
63+
expect(screen.getByText('Pools balances currently unavailable')).toBeDefined()
64+
expect(screen.getByText('Try again')).toBeDefined()
65+
})
66+
67+
it('renders the loading skeleton while the first page loads (no data, no error)', () => {
68+
mockUseWalletPositions.mockReturnValue({
69+
...baseResult,
70+
isFetching: true,
71+
hasData: false,
72+
})
73+
74+
render(<PoolsTab address="0xabc" />)
75+
76+
expect(screen.getByText('Status')).toBeDefined()
77+
expect(screen.getByTestId('pools-loading-skeleton')).toBeDefined()
78+
expect(screen.queryByText('Pools balances currently unavailable')).toBeNull()
79+
})
80+
81+
it('swaps the error view for the loading skeleton while a retry re-drives the list', () => {
82+
mockUseWalletPositions.mockReturnValue({
83+
...baseResult,
84+
hasData: false,
85+
error: new Error('boom') as never,
86+
isFetching: true,
87+
isFetchingNextPage: false,
88+
})
89+
90+
render(<PoolsTab address="0xabc" />)
91+
92+
expect(screen.getByTestId('pools-loading-skeleton')).toBeDefined()
93+
expect(screen.queryByText('Pools balances currently unavailable')).toBeNull()
94+
})
95+
96+
it('renders the status filter with the default "Open" selection', () => {
97+
mockUseWalletPositions.mockReturnValue(baseResult)
98+
99+
render(<PoolsTab address="0xabc" />)
100+
101+
expect(screen.getByText('Status')).toBeDefined()
102+
expect(screen.getByText('Open')).toBeDefined()
103+
})
104+
105+
it('shows no no-results message for the empty open filter', () => {
106+
mockUseWalletPositions.mockReturnValue({ ...baseResult, positions: [], hasData: true })
107+
108+
render(<PoolsTab address="0xabc" openPositionsCount={3} />)
109+
110+
expect(screen.queryByText('No closed positions')).toBeNull()
111+
expect(screen.queryByText(/View .* open position/)).toBeNull()
112+
})
113+
114+
it('renders visible position rows', () => {
115+
mockUseWalletPositions.mockReturnValue({
116+
...baseResult,
117+
positions: [position('pool-a'), position('pool-b')],
118+
})
119+
120+
render(<PoolsTab address="0xabc" />)
121+
122+
expect(screen.getByTestId('position-pool-a')).toBeDefined()
123+
expect(screen.getByTestId('position-pool-b')).toBeDefined()
124+
expect(screen.queryByText('Pools balances currently unavailable')).toBeNull()
125+
})
126+
127+
it('filters hidden positions by status, hiding the expando when none match the filter', () => {
128+
mockUseWalletPositions.mockReturnValue({
129+
...baseResult,
130+
positions: [],
131+
hiddenPositions: [position('pool-hidden-closed', PositionStatus.CLOSED)],
132+
})
133+
134+
// Default filter is Open; a closed hidden position must not surface the expando.
135+
render(<PoolsTab address="0xabc" />)
136+
137+
expect(screen.queryByText(/Hidden/)).toBeNull()
138+
})
139+
140+
it('shows the hidden expando with the hidden count and reveals rows when expanded', () => {
141+
mockUseWalletPositions.mockReturnValue({
142+
...baseResult,
143+
positions: [position('pool-a')],
144+
hiddenPositions: [position('pool-hidden-1'), position('pool-hidden-2')],
145+
})
146+
147+
render(<PoolsTab address="0xabc" />)
148+
149+
expect(screen.getByText(/Hidden .*\(2\)/)).toBeDefined()
150+
expect(screen.queryByTestId('position-pool-hidden-1')).toBeNull()
151+
})
152+
153+
it('filters out positions that do not match the active status filter (default open)', () => {
154+
mockUseWalletPositions.mockReturnValue({
155+
...baseResult,
156+
positions: [position('pool-open'), position('pool-closed', PositionStatus.CLOSED)],
157+
hiddenPositions: [position('pool-hidden-closed', PositionStatus.CLOSED)],
158+
})
159+
160+
render(<PoolsTab address="0xabc" />)
161+
162+
expect(screen.getByTestId('position-pool-open')).toBeDefined()
163+
expect(screen.queryByTestId('position-pool-closed')).toBeNull()
164+
expect(screen.queryByText(/Hidden/)).toBeNull()
165+
})
166+
})

0 commit comments

Comments
 (0)