feat: add Wasabi Prop AMM adapter and related interfaces#1
feat: add Wasabi Prop AMM adapter and related interfaces#1WEBthe3rd wants to merge 5 commits intoKyberNetwork:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new DEX adapter to let the aggregator route swaps through Wasabi Prop AMM pools (Base), including native ETH wrapping/unwrapping support.
Changes:
- Introduces
WasabiPropAmmAdapterwith support for native ETH in/out via WETH. - Adds minimal
IPropPoolandIWETHinterfaces for pool interaction and wrapping. - Adds fork-based fuzz tests for ERC20 and native ETH swap paths.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/adapters/wasabi-prop-amm/WasabiPropAmmAdapter.sol |
Implements PropPool swap execution and native ETH wrap/unwrap handling |
src/adapters/wasabi-prop-amm/IPropPool.sol |
Minimal PropPool interface for swapping and token discovery |
src/adapters/wasabi-prop-amm/IWETH.sol |
Minimal WETH interface used for deposit/withdraw |
test/adapters/wasabi-prop-amm/WasabiPropAmmAdapter.t.sol |
Base fork fuzz tests for ERC20 swaps + native ETH in/out scenarios |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| address pool = data.decodeAddress(0); | ||
|
|
||
| // Resolve actual ERC20 token address for input (native ETH -> WETH) | ||
| address actualTokenIn = tokenIn.isNative() ? WETH : tokenIn; | ||
|
|
||
| // Wrap native ETH to WETH if needed | ||
| if (tokenIn.isNative()) { | ||
| if (msg.value != amountIn) revert InvalidMsgValue(); | ||
| IWETH(WETH).deposit{value: amountIn}(); | ||
| } else if (msg.value != 0) { | ||
| revert InvalidMsgValue(); | ||
| } | ||
|
|
||
| // Approve pool to pull tokenIn from this adapter | ||
| actualTokenIn.forceApprove(pool, amountIn); | ||
|
|
||
| // Execute swap -- pool pulls tokenIn, sends tokenOut back to this contract | ||
| amountOut = IPropPool(pool).swapExactInput(actualTokenIn, amountIn, 1); | ||
|
|
||
| // Only explicitly transfer if native ETH is requested as output; | ||
| // ERC20 outputs are left in the adapter for the framework to collect | ||
| if (tokenOut.isNative()) { | ||
| IWETH(WETH).withdraw(amountOut); | ||
| TokenHelper.safeTransferNative(recipient, amountOut); | ||
| } |
There was a problem hiding this comment.
executeWasabiPropAmm doesn’t validate that tokenIn/tokenOut match the pool’s pair. If the caller supplies mismatched tokens, the swap may still succeed (outputting the pool’s “other” token) while the framework believes it received tokenOut; additionally, tokenOut.isNative() will attempt to unwrap WETH even if the pool didn’t output WETH. Consider checking IPropPool(pool).getBaseToken()/getQuoteToken() and reverting when (actualTokenIn, actualTokenOut) isn’t exactly the pool’s pair (with native mapped to WETH).
| // Only explicitly transfer if native ETH is requested as output; | ||
| // ERC20 outputs are left in the adapter for the framework to collect | ||
| if (tokenOut.isNative()) { | ||
| IWETH(WETH).withdraw(amountOut); | ||
| TokenHelper.safeTransferNative(recipient, amountOut); |
There was a problem hiding this comment.
ERC20 outputs are left in the adapter, so the recipient parameter is ignored for non-native tokenOut. This differs from the other adapters in this repo (which send output directly to recipient) and also leaves token balances sitting in an externally-callable contract; any leftover balance can be pulled out by a subsequent call that approves a malicious pool and uses that balance as amountIn. Consider transferring ERC20 tokenOut to recipient (or adding access control / an explicit, safe collection mechanism if retention is required).
| // Only explicitly transfer if native ETH is requested as output; | |
| // ERC20 outputs are left in the adapter for the framework to collect | |
| if (tokenOut.isNative()) { | |
| IWETH(WETH).withdraw(amountOut); | |
| TokenHelper.safeTransferNative(recipient, amountOut); | |
| // Transfer output to the recipient. If native ETH is requested, unwrap WETH first; | |
| // otherwise, transfer the ERC20 tokenOut directly. | |
| if (tokenOut.isNative()) { | |
| IWETH(WETH).withdraw(amountOut); | |
| TokenHelper.safeTransferNative(recipient, amountOut); | |
| } else { | |
| tokenOut.safeTransfer(recipient, amountOut); |
| // Execute swap -- pool pulls tokenIn, sends tokenOut back to this contract | ||
| amountOut = IPropPool(pool).swapExactInput(actualTokenIn, amountIn, 1); | ||
|
|
There was a problem hiding this comment.
swapExactInput is called with minAmountOut hardcoded to 1, effectively disabling slippage protection at the adapter layer even though the PropPool API supports it. If the surrounding framework can provide a minimum acceptable output, consider encoding/decoding it from data (or adding a parameter) and passing it through.
|
Hi @WEBthe3rd, if the pool contracts do not support the native token directly, you can ignore it since we have an internal flow to wrap it if needed 😄 |
Got it, I just stripped out the native token handling. Let me know if any other changes are needed! |
|
@WEBthe3rd pls allow maintainers to commit to your branch |
Summary
PropPoolcontracts (not through thePropSwapRouter), following the guideline to prefer direct pool interactionDetails
Each Wasabi Prop AMM pool pairs a single base token (e.g. WETH) with USDC as the quote token. The adapter handles one pool per call -- for token-to-token routes (e.g. WETH -> WBTC), the aggregator chains two calls through USDC.
The
dataparameter encodes only the pool address:ERC20 output tokens are left in the adapter for the framework to collect. Native token wrapping/unwrapping is handled by KyberSwap's internal flow and does not need to be implemented in the adapter.
Deployment note: The adapter contract must be granted
AUTHORIZED_SWAPPER_ROLE(role 100) on thePropPoolFactory's access manager after deployment.New files
src/adapters/wasabi-prop-amm/WasabiPropAmmAdapter.solsrc/adapters/wasabi-prop-amm/IPropPool.soltest/adapters/wasabi-prop-amm/WasabiPropAmmAdapter.t.solTest plan