Skip to content

[Bug] USDC zap trade reverts — investigate multi-hop routing #464

@realproject7

Description

@realproject7

Summary

USDC zap via ZapPlotLinkV2 reverts on Base mainnet. ETH and HUNT routes work fine. USDC was never live-tested (E2E script skipped it due to no balance). The action constants were fixed in PR #62 but USDC still fails.

Evidence

  • PR [#203] Writer dashboard with storyline details #62 fixed action constants (SWAP_EXACT_IN0x07, SWAP_EXACT_OUT0x09)
  • estimateMint(USDC, ...) returns valid quotes (4 units for 1 storyline token)
  • But actual USDC mint tx reverts when submitted from frontend

Key difference from MintPad

MintPad's ZapUniV4MCV2 contract handles USDC routing internally — the frontend just passes fromToken=USDC and the contract figures out the path. MintPad's frontend treats USDC the same as any other token, only adjusting for 6 decimals on the frontend side (parseUnits(amount, 6)).

Our ZapPlotLinkV2 has explicit multi-hop code (USDC→ETH→PLOT) which may have encoding issues.

Investigation steps

  1. Compare with MintPad: Check MintPad's deployed ZapUniV4MCV2 (0xa2e7BcA51A84Ed635909a8E845d5f66602742A75) on Basescan — look at successful USDC swap txs and compare the calldata/routing with ours

  2. Check multi-hop encoding: Our _executeV4MultiHopSwapExactIn builds a 2-step PathKey array. Verify:

    • USDC/ETH pool exists on V4 with fee=500, tickSpacing=10 (our usdcPoolFee and usdcPoolTickSpacing)
    • PathKey encoding order is correct for V4 Universal Router
    • SETTLE_ALL and TAKE action params match what Universal Router expects for multi-hop
  3. Check decimal handling: USDC is 6 decimals. Verify:

    • Frontend passes correct 6-decimal amounts via parseUnits(amount, 6)
    • Contract's _validateAndTransferInput handles 6-decimal safeTransferFrom correctly
    • maxFromTokenAmount slippage calculation doesn't overflow with 6-decimal amounts
  4. Simulate the failing tx: Use cast call --trace on a USDC mint to get the exact revert reason

  5. Check if a USDC/ETH V4 pool actually exists: The contract assumes fee=500, tickSpacing=10 for the USDC/ETH leg. Verify this pool is initialized on Base mainnet's PoolManager.

Possible fixes

  • If USDC/ETH V4 pool doesn't exist: change the multi-hop route or use a pool that does exist
  • If encoding is wrong: fix PathKey order/params to match V4 Universal Router spec
  • If decimal issue: add USDC-specific decimal handling in the contract

Reference

  • MintPad ZapUniV4MCV2: 0xa2e7BcA51A84Ed635909a8E845d5f66602742A75 (Base mainnet)
  • MintPad frontend: ~/Projects/mintpad/src/helpers/zap.ts — treats all tokens same, only varies decimals
  • Our contract: plotlink-contracts/src/ZapPlotLinkV2.sol lines 463-535 (multi-hop functions)
  • Current ZapPlotLinkV2: 0x04f557F8D2806B34FC832a534c08DF514D4dfEeF

Acceptance Criteria

  • Root cause identified
  • USDC zap trade succeeds on Base mainnet
  • Contract redeployed if fix needed (update constants in plotlink repo too)
  • Tx hash of successful USDC trade documented in PR

Branch

task/463-usdc-zap-fix in plotlink-contracts repo (+ plotlink if constants change)

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/T3Assigned to T3 builder agentbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions