Skip to content

[Bug] USDC zap mint reverts — study MintPad contract and fix #470

@realproject7

Description

@realproject7

Summary

USDC zap mint still reverts on mainnet despite multiple fix attempts. The estimateMint() call works but the actual mint() tx reverts with ZapPlotLink__SlippageExceeded(). The root cause is in the contract's USDC→ETH→PLOT multi-hop flow — the BOND.mint(storylineToken, ...) call fails after the Uniswap swap.

This is NOT a liquidity issue — pool was seeded with additional liquidity and estimates return valid amounts. The error comes from the try BOND.mint(...) catch { revert SlippageExceeded } block.

Failed tx

  • 0x5c6fbbe55b0e7744a70d75ba2dc2ba273b14082ca7c4792d9cbec2ddba0473e5
  • mint(USDC, 0x25617...7c379, 2000 tokens, maxUSDC=8338)
  • Reverts with ZapPlotLink__SlippageExceeded() at the BOND.mint stage

Previous fix attempts (all insufficient)

  1. PR [#203] Writer dashboard with storyline details #62 — Fixed action constants (SWAP_EXACT_IN/OUT)
  2. PR Fix USDC multi-hop encoding, redeploy Zap, re-enable USDC #469 — Fixed struct encoding (_encodeAsStruct helper)
  3. Added pool liquidity (1000 PLOT + 0.01 ETH)
  4. PR Disable USDC zap pending contract fix (#464) #466 — Disabled USDC temporarily, PR Fix USDC multi-hop encoding, redeploy Zap, re-enable USDC #469 re-enabled

What to do

Study MintPad's deployed ZapUniV4MCV2 contract source code:

  1. Read the verified source on Basescan: 0xa2e7BcA51A84Ed635909a8E845d5f66602742A75
  2. Find successful USDC→HUNT child token mint txs on Basescan and trace the execution
  3. Compare MintPad's mint() function flow vs our ZapPlotLinkV2's — specifically:
    • How does MintPad handle getReserveForToken return values? (Does it include royalty or not?)
    • How does MintPad call BOND.mint — what is the maxReserveAmount parameter?
    • Does MintPad do the swap THEN mint, or is the ordering different?
    • How does MintPad handle the PLOT balance after swap — does it check actual balance vs estimated?
  4. Rewrite our USDC mint flow to exactly match MintPad's proven pattern
  5. Redeploy and test with a real USDC trade

Key suspicion

The comment says getReserveForToken returns (reserveAmount, royalty) where reserveAmount already includes royaltyverify this is actually true. If reserveAmount does NOT include royalty, then plotRequired is too low, the swap gets insufficient PLOT, and BOND.mint fails because it needs reserveAmount + royalty.

Contract references

  • Our ZapPlotLinkV2: 0x952606df750C01e0a12458C3F814598B94AD5C5f (source: plotlink-contracts/src/ZapPlotLinkV2.sol)
  • MintPad ZapUniV4MCV2: 0xa2e7BcA51A84Ed635909a8E845d5f66602742A75 (verified on Basescan)
  • MCV2_Bond: 0xc5a076cad94176c2996B32d8466Be1cE757FAa27
  • PLOT: 0xF8A2C39111FCEB9C950aAf28A9E34EBaD99b85C1

After fix

  1. Redeploy ZapPlotLinkV2
  2. Update ZAP_PLOTLINK in lib/contracts/constants.ts
  3. Execute a successful USDC zap trade and document tx hash
  4. Update README with new address

Acceptance Criteria

  • MintPad's contract source studied and differences documented
  • Root cause confirmed
  • Contract fixed and redeployed
  • Successful USDC mint tx on mainnet (document hash)
  • ETH and HUNT zap still work
  • Constants and README updated

Branch

task/470-usdc-zap-final-fix in plotlink-contracts repo (+ plotlink for constants)

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