feat(fx): validate swap-quote sell + buy tokens in validatePoolFlow - #54
Merged
Merged
Conversation
Follow-up to PR Railgun-Community#53 (item Railgun-Community#3 from @zy0n's review). validatePoolFlow now performs a direction-aware shape check on the provided swapQuote, in addition to the existing presence check. The shape check runs on BOTH named-pool and custom-pool refs (zy0n's "both of those logic branches" comment): 'deposit' (open / topup / topup-and-borrow): sellTokenAddress must equal WETH buyERC20Amount.tokenAddress must equal pool.collateralToken 'withdraw' (close): sellTokenAddress must equal pool.collateralToken buyERC20Amount.tokenAddress must equal WETH The direction asymmetry surfaced during implementation: open/topup recipes hardcode `inputToken = FX_ADDRESSES.WETH` and target pool.collateralToken, while close-recipe reverses (withdraws collateral, swaps to WETH). A single direction-agnostic check would reject every valid close-recipe quote, so validatePoolFlow takes a third arg. Compares are case-insensitive. Mismatches raise a clear `fxmint:` error at recipe construction time, replacing what previously surfaced as a confusing on-chain gas-estimate revert. Tests: 9 new cases in the validatePoolFlow describe block, covering both directions (deposit + withdraw), both branches (named + custom), and the checksum-vs-lowercase case-insensitivity path. Existing presence-check tests pass unchanged after adding the direction arg. Fixture sweep across the four recipe test files added the previously- missing sellTokenAddress (the fixtures were cast `as unknown as SwapQuoteData` to bypass the type check; the new shape check would otherwise throw TypeError on undefined). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #53 (item #3 from @zy0n's review).
Summary
validatePoolFlowpreviously checked only that aswapQuotewas present when a named pool required one (e.g.,wstETH-Long). It did not validate the quote's contents — so a caller could pass a quote that swaps the wrong tokens, and the failure surfaced later as a confusing on-chain gas-estimate revert.This PR adds an inner shape check: when a
swapQuoteis provided, the helper verifies that its sell and buy tokens match what the recipe will actually execute. The check is direction-aware:'deposit'(open / topup / topup-and-borrow):sellTokenAddress === WETH,buyERC20Amount.tokenAddress === pool.collateralToken'withdraw'(close):sellTokenAddress === pool.collateralToken,buyERC20Amount.tokenAddress === WETHThe direction asymmetry surfaced during implementation: open/topup recipes hardcode
inputToken = FX_ADDRESSES.WETHand targetpool.collateralToken, while close-recipe reverses (withdraws collateral, swaps to WETH). A single direction-agnostic check would have rejected every valid close-recipe quote, sovalidatePoolFlowtakes a thirddirectionargument.Both layers — presence AND shape — run on both named-pool and custom-pool refs (addresses @zy0n's "both of those logic branches" comment). Compares are case-insensitive.
Behavior change
Quotes that were previously accepted and later reverted on-chain now fail fast at recipe construction time with a clear
fxmint:error message. Correctly-formed quotes continue to work unchanged.validatePoolFlowgains a required third arg (direction: SwapDirection), updated at all four internal call sites.Test plan
describe('validatePoolFlow', …)block: deposit + withdraw directions, named + custom pool refs, sell-side mismatch, buy-side mismatch, and case-insensitivity.'deposit'as the new third arg; behavior unchanged.fakeSwapQuoteconstants across the four recipe test files now includesellTokenAddress(previously castas unknown as SwapQuoteDatato bypass the type check; the new shape check would otherwise throwTypeErroron undefined).npm run lint— no new errors (pre-existing baseline unchanged).npm test— 143 passing (baseline +9), 19 pending, 10 failing. The 10 failures are pre-existing environmental (missingZeroXConfig.API_KEY+ RPC 503s oneth.llamarpc.com).🤖 Generated with Claude Code