Skip to content

add chain-agnostic smoke tests for v2, v3, v4 (with UR swap)#139

Merged
david-uniswap merged 5 commits into
mainfrom
david-nick/robinhood-smoke-tests
May 29, 2026
Merged

add chain-agnostic smoke tests for v2, v3, v4 (with UR swap)#139
david-uniswap merged 5 commits into
mainfrom
david-nick/robinhood-smoke-tests

Conversation

@david-uniswap

Copy link
Copy Markdown
Collaborator

Pull Request

Description

Adds three Foundry scripts under script/smoke/ that exercise the full LP + swap flow for v2, v3, and v4 against deployed contracts on any chain.

What each test does

  • V2SmokeTest: wraps ETH → deploys a fresh test ERC-20 → addLiquidity via Router02 → swaps test token to WETH
  • V3SmokeTest: wraps ETH → deploys a fresh test ERC-20 → creates + initializes a 0.3% pool → mints a position via NonfungiblePositionManager → swaps via SwapRouter02
  • V4SmokeTest: wraps ETH → deploys a fresh test ERC-20 → initializes pool via PositionManager → mints a position through the Permit2 + modifyLiquidities flow → swaps test token to WETH via UniversalRouter's V4_SWAP command

The v4 swap path validates Permit2 wiring, the PoolManager unlock pattern, the V4Router calldata decoder, and UR command dispatch all end-to-end.

Chain-agnostic by design

Each test reads contract addresses from deployments/json/<chainId>.json via vm.parseJsonAddress. WETH is derived from a deployed contract (Router02.WETH() for v2, NPM.WETH9() for v3 and v4) so no external chain-specific config is needed.

To run on any chain that has a corresponding deployments JSON:

forge script script/smoke/V2SmokeTest.s.sol --tc V2SmokeTest \
  --rpc-url $RPC --account <keystore> --sender <deployer> \
  --broadcast --slow -vv

Three Foundry scripts under script/smoke/ that exercise the full LP+swap
flow against deployed contracts. They read addresses from the chain's
deployments/json/<chainId>.json so they work on any chain that has the
expected contracts recorded — not specific to Robinhood.

What each test does:
- V2SmokeTest: wraps ETH, deploys a fresh test ERC-20, addLiquidity via
  Router02 to create a new pair, swaps test token -> WETH.
- V3SmokeTest: same setup, creates+initializes a 0.3% pool via Factory,
  mints a position via NonfungiblePositionManager, swaps via SwapRouter02.
- V4SmokeTest: same setup, initializes a pool via PositionManager,
  mints a position through the Permit2 + modifyLiquidities flow, then
  swaps test token -> WETH via UniversalRouter's V4_SWAP command
  (validates Permit2 wiring, PoolManager unlock pattern, V4Router
  decoder, and UR command dispatch all end-to-end).

WETH address is derived from a deployed contract (v2 Router02.WETH() for
v2 test, v3 NPM.WETH9() for v3 and v4 tests) so no external chain-specific
config is needed.

foundry.toml: added "deployments/" to fs_permissions so the tests can
read the deployments registry.

.gitignore: excluded broadcast/V*SmokeTest.s.sol/** — smoke test broadcast
logs are transient validation artifacts, not deployment records.

Validated on Robinhood Chain (4663):
- V2: total 0.000352 ETH, swap landed
- V3: total 0.000618 ETH, swap landed
- V4: total 0.000159 ETH, swap via UR landed (1 TEST -> ~5e13 wei WETH)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@david-uniswap david-uniswap force-pushed the david-nick/robinhood-smoke-tests branch from 690c1a0 to 5980410 Compare May 22, 2026 21:59
UR v2.1.1 (PR #470 upstream) added a minHopPriceX36 field to the V4Router
ExactInputSingleParams struct, between amountOutMinimum and hookData.
The smoke test's local struct definition + instantiation needed to match
or the V4Router decoder reads misaligned calldata and reverts on swap.

Set to 0 to disable the per-hop price check (smoke tests don't care
about slippage protection, they just need the swap to land).

Verified end-to-end against the new UR v2.1.1 at
0x8876789976decbfcbbbe364623c63652db8c0904 (Robinhood Chain 4663):
swap delta 49997492603174 matches v2.1.0 since the pool math is
unchanged. Tested in simulation; onchain broadcast is left for the next
chain that exercises the smoke tests post-merge.
Adds V2/V3/V4 smoke test variants in script/smoke/native-is-erc20/
for chains where the native gas token is itself an ERC-20 (CELO, Arc,
similar Circle partner chains). On these chains the WETH9 dependency
is wired to UnsupportedProtocol (or similar) which reverts on
deposit/withdraw, so the standard smoke tests halt at the WETH wrap
step.

These variants skip the WETH leg entirely and use two freshly-deployed
TestTokens to exercise the same v2/v3/v4 + UR code paths. Chain-
agnostic via vm.parseJsonAddress reads from deployments/json/<id>.json,
matching the parent PR's pattern.

Tested end-to-end on Arc Mainnet (chain 5042). All three pass:
- V2: pair created, 1000:1000 liquidity, swap 1 A -> 0.996 B (0.3% fee)
- V3: pool init at 1:1, position minted, exactInputSingle 1 A -> 0.996 B
- V4: pool init, modifyLiquidities mint with Permit2 dual-approval,
       swap via UR V4_SWAP command

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
david-uniswap and others added 2 commits May 28, 2026 10:23
…-tests

add native-is-erc20 chain smoke test variants
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@david-uniswap david-uniswap merged commit 4827da3 into main May 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants