Skip to content

fix(swap): force flashloan flow for Paraswap collateral swaps#3012

Open
mgrabina wants to merge 1 commit into
mainfrom
worktree/dreamy-galileo-abcdff
Open

fix(swap): force flashloan flow for Paraswap collateral swaps#3012
mgrabina wants to merge 1 commit into
mainfrom
worktree/dreamy-galileo-abcdff

Conversation

@mgrabina

@mgrabina mgrabina commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

General Changes

  • Fixes Paraswap collateral swaps failing with Source Decimals Mismatch (reported on Sonic, USDC → wS).

Developer Notes

Root cause. A no-flashloan collateral swap renders the generic SwapActionsViaParaswap path (see CollateralSwapActions dispatcher), which builds the Paraswap tx on the aToken addresses (state.sourceToken.addressToSwap). Paraswap can't price or trade aTokens — it doesn't list them, so it ignores the srcDecimals we send and defaults the unknown token to 18. Reproduced against the live API on Sonic (chainId 146):

# quote on aUSDC (sent srcDecimals=6) -> priceRoute came back with srcDecimals: 18
GET /prices?srcToken=0x578Ee1ca...&srcDecimals=6&destToken=0x6C5E14A2...&amount=100000&side=SELL&network=146
  -> priceRoute.srcDecimals = 18   # wrong, USDC is 6

The build sends srcDecimals from the quote wrapper (6) plus that priceRoute (18). Paraswap's /transactions validates body.srcDecimals === priceRoute.srcDecimals (6 !== 18) → Source Decimals Mismatch. This also explains the $0.00 input USD in the report: the route priced 100000 base units as an 18-decimal token (~1e-13 ≈ $0). The destination matched only by coincidence (wS is 18 and Paraswap's default for the unknown aWS was also 18), which is why the error is Source and not Destination.

Even if the API had accepted it, the on-chain tx would revert — aTokens have no DEX liquidity. The non-flashloan path is fundamentally non-functional for Paraswap collateral swaps.

On Sonic, CoW is unsupported, so getSwitchProvider always falls back to Paraswap; with a healthy health factor, useFlowSelector left useFlashloan = false, routing into that broken path.

Fix. Force the flashloan flow for Paraswap collateral swaps in useFlowSelector, alongside the existing CoW repay/debt rule. This routes the dispatcher to CollateralSwapActionsViaParaswapAdapters (which unwraps aTokens → underlying → swaps underlying via Paraswap → re-supplies) and, because usesAddressToSwap is gated on useFlashloan === false, also makes the quote use the underlying tokens. Both sides then agree on real, priceable tokens.

Scope:

  • DebtSwap / RepayWithCollateral via Paraswap are unaffected — single action each, both build on the underlying.
  • CoW collateral swaps are untouched — CoW can trade aTokens directly, so its non-flashloan path stays.
  • Sonic's SWAP_COLLATERAL_ADAPTER (0x78F8…) is deployed, so the flashloan path works there.

Note: the first revision of this PR fixed the quote token selection in useSwapQuote.ts. An independent review (codex) flagged that it would only move the error to Source Token Mismatch, since the no-flashloan build path uses aToken addresses. Replaced with the flow-selector fix above.

@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
interface Error Error Jun 8, 2026 9:42pm

Request Review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f12961556b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/transactions/Swap/hooks/useSwapQuote.ts Outdated
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

📦 Next.js Bundle Analysis for aave-ui

This analysis was generated by the Next.js Bundle Analysis action. 🤖

🎉 Global Bundle Size Decreased

Page Size (compressed)
global 1.25 MB (-32 B)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

One Page Changed Size

The following page changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load
/history 36.34 KB (🟡 +6 B) 1.29 MB
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

Next to the size is how much the size has increased or decreased compared with the base branch of this PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this.

A no-flashloan collateral swap routes through the simple SwapActionsViaParaswap
path, which builds the tx on the aToken addresses. Paraswap can't price or
trade aTokens: it doesn't list them and defaults unknown tokens to 18 decimals,
so the priceRoute came back with srcDecimals=18 for a 6-decimal asset while
buildTx sent 6, and Paraswap rejected it with "Source Decimals Mismatch". On
Sonic, where CoW is unsupported and the provider falls back to Paraswap, this
hit any collateral swap with a healthy health factor.

Force the flashloan flow for Paraswap collateral swaps so they use the adapter
(which unwraps to the underlying), matching the existing CoW repay/debt
handling. This routes the dispatcher to CollateralSwapActionsViaParaswapAdapters
and flips usesAddressToSwap off, so the quote runs on the underlying tokens too.
Both sides then agree on real, priceable tokens.
@mgrabina mgrabina force-pushed the worktree/dreamy-galileo-abcdff branch from f129615 to e503750 Compare June 8, 2026 21:39
@mgrabina mgrabina changed the title fix(swap): quote Paraswap collateral swaps on underlying tokens fix(swap): force flashloan flow for Paraswap collateral swaps Jun 8, 2026
@mgrabina

mgrabina commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e503750296

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

(state.swapType === SwapType.RepayWithCollateral || state.swapType === SwapType.DebtSwap);
(state.provider === SwapProvider.COW_PROTOCOL &&
(state.swapType === SwapType.RepayWithCollateral || state.swapType === SwapType.DebtSwap)) ||
(state.provider === SwapProvider.PARASWAP && state.swapType === SwapType.CollateralSwap);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Force flashloan before requiring a ParaSwap quote

This new ParaSwap collateral-swap override only runs after the early guard has already required state.swapRate (line 97), but the first quote is still requested with useFlashloan === false, so useSwapQuote uses the aToken addressToSwap pair for ParaSwap. For any collateral pair where ParaSwap rejects the unlisted aToken quote instead of returning a bogus route, state.swapRate remains undefined and this line is never reached, leaving the flow stuck on the broken non-flashloan/aToken path with a quote error. The forced flow needs to be selected before the initial quote can fail, or this fix only works for aTokens that happen to get a response.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

📦 Next.js Bundle Analysis for aave-ui

This analysis was generated by the Next.js Bundle Analysis action. 🤖

🎉 Global Bundle Size Decreased

Page Size (compressed)
global 1.25 MB (-31 B)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

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.

1 participant