Add DODO-only EnhancedSwapRouterV2 routing helpers

This commit is contained in:
defiQUG
2026-04-29 23:50:26 -07:00
parent 1a14622b22
commit 6aaa100bbc
12 changed files with 564 additions and 173 deletions

View File

@@ -39,12 +39,19 @@ contract MockDodoProviderV2 is ILiquidityProvider {
quoteAmount[tokenIn][tokenOut] = amountOut;
}
function getQuote(address tokenIn, address tokenOut, uint256) external view returns (uint256 amountOut, uint256 slippageBps) {
function getQuote(address tokenIn, address tokenOut, uint256)
external
view
returns (uint256 amountOut, uint256 slippageBps)
{
if (!supported[tokenIn][tokenOut]) return (0, 10000);
return (quoteAmount[tokenIn][tokenOut], 30);
}
function executeSwap(address tokenIn, address tokenOut, uint256 amountIn, uint256) external returns (uint256 amountOut) {
function executeSwap(address tokenIn, address tokenOut, uint256 amountIn, uint256)
external
returns (uint256 amountOut)
{
require(supported[tokenIn][tokenOut], "unsupported");
amountOut = quoteAmount[tokenIn][tokenOut];
ERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
@@ -71,13 +78,11 @@ contract MockUniswapQuoterV2 {
quotes[keccak256(abi.encode(tokenIn, tokenOut, fee))] = amountOut;
}
function quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256,
uint160
) external view returns (uint256) {
function quoteExactInputSingle(address tokenIn, address tokenOut, uint24 fee, uint256, uint160)
external
view
returns (uint256)
{
return quotes[keccak256(abi.encode(tokenIn, tokenOut, fee))];
}
@@ -93,17 +98,13 @@ contract MockUniswapRouterV2 {
quotes[keccak256(abi.encode(tokenIn, tokenOut, fee))] = amountOut;
}
function exactInputSingle(
ISwapRouter.ExactInputSingleParams calldata params
) external returns (uint256 amountOut) {
function exactInputSingle(ISwapRouter.ExactInputSingleParams calldata params) external returns (uint256 amountOut) {
amountOut = quotes[keccak256(abi.encode(params.tokenIn, params.tokenOut, params.fee))];
ERC20(params.tokenIn).transferFrom(msg.sender, address(this), params.amountIn);
ERC20(params.tokenOut).transfer(params.recipient, amountOut);
}
function exactInput(
ISwapRouter.ExactInputParams calldata
) external pure returns (uint256) {
function exactInput(ISwapRouter.ExactInputParams calldata) external pure returns (uint256) {
revert("path unsupported in mock");
}
}
@@ -136,22 +137,18 @@ contract MockBalancerVaultV2 {
return (address(0xBEEF), 0);
}
function queryBatchSwap(
IBalancerVault.SwapKind,
IBalancerVault.SingleSwap[] memory,
address[] memory
) external pure returns (int256[] memory assetDeltas) {
function queryBatchSwap(IBalancerVault.SwapKind, IBalancerVault.SingleSwap[] memory, address[] memory)
external
pure
returns (int256[] memory assetDeltas)
{
assetDeltas = new int256[](0);
}
function getPoolTokens(bytes32 requestedPoolId)
external
view
returns (
address[] memory,
uint256[] memory,
uint256
)
returns (address[] memory, uint256[] memory, uint256)
{
require(requestedPoolId == poolId, "bad pool");
return (tokens, balances, block.number);
@@ -189,26 +186,22 @@ contract MockCurvePoolV2 {
contract MockBridgeIntentExecutorV2 is IBridgeIntentExecutor {
event Bridged(bytes32 indexed bridgeType, address indexed token, uint256 amount, address recipient);
function validateBridge(
bytes32,
bytes calldata,
address token,
uint256 amount,
address recipient
) external pure returns (bool ok, string memory reason) {
function validateBridge(bytes32, bytes calldata, address token, uint256 amount, address recipient)
external
pure
returns (bool ok, string memory reason)
{
if (token == address(0) || amount == 0 || recipient == address(0)) {
return (false, "invalid bridge request");
}
return (true, "");
}
function executeBridge(
bytes32 bridgeType,
bytes calldata,
address token,
uint256 amount,
address recipient
) external payable returns (bytes32 referenceId) {
function executeBridge(bytes32 bridgeType, bytes calldata, address token, uint256 amount, address recipient)
external
payable
returns (bytes32 referenceId)
{
ERC20(token).transferFrom(msg.sender, address(this), amount);
emit Bridged(bridgeType, token, amount, recipient);
return keccak256(abi.encode(bridgeType, token, amount, recipient));
@@ -250,11 +243,11 @@ contract MockD3MMV2 {
quoteAmount[tokenIn][tokenOut] = amountOut;
}
function querySellTokens(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 payFromAmount, uint256 receiveToAmount, uint256 vusdAmount, uint256 swapFee, uint256 mtFee) {
function querySellTokens(address fromToken, address toToken, uint256 fromAmount)
external
view
returns (uint256 payFromAmount, uint256 receiveToAmount, uint256 vusdAmount, uint256 swapFee, uint256 mtFee)
{
payFromAmount = fromAmount;
receiveToAmount = quoteAmount[fromToken][toToken];
vusdAmount = 0;
@@ -301,14 +294,8 @@ contract MockD3ProxyV2 {
) external payable returns (uint256 receiveToAmount) {
require(deadLine >= block.timestamp, "expired");
SwapCallbackData memory swapData = SwapCallbackData({data: data, payer: msg.sender});
receiveToAmount = MockD3MMV2(pool).sellToken(
to,
fromToken,
toToken,
fromAmount,
minReceiveAmount,
abi.encode(swapData)
);
receiveToAmount =
MockD3MMV2(pool).sellToken(to, fromToken, toToken, fromAmount, minReceiveAmount, abi.encode(swapData));
}
function d3MMSwapCallBack(address token, uint256 value, bytes calldata callbackData) external {
@@ -589,6 +576,39 @@ contract EnhancedSwapRouterV2Test is Test {
vm.stopPrank();
}
function testQuoteConfiguredProviderQuotesSingleDodoRoute() public view {
RouteTypesV2.ProviderQuote memory quote =
router.quoteConfiguredProvider(address(weth), address(usdt), 1 ether, RouteTypesV2.Provider.Dodo);
assertEq(uint256(quote.provider), uint256(RouteTypesV2.Provider.Dodo));
assertEq(quote.target, address(dodoProvider));
assertEq(quote.amountOut, 1_800 ether);
assertEq(quote.estimatedGas, 140000);
assertTrue(quote.executable);
assertEq(abi.decode(quote.providerData, (address)), address(0xA11CE));
}
function testQuoteConfiguredProviderRevertsWhenProviderDisabled() public {
router.setProviderEnabled(RouteTypesV2.Provider.Dodo, false);
vm.expectRevert(EnhancedSwapRouterV2.ProviderDisabled.selector);
router.quoteConfiguredProvider(address(weth), address(usdt), 1 ether, RouteTypesV2.Provider.Dodo);
}
function testQuoteConfiguredProviderRevertsWhenRouteMissing() public {
vm.expectRevert(EnhancedSwapRouterV2.RouteNotConfigured.selector);
router.quoteConfiguredProvider(address(weth), address(dai), 1 ether, RouteTypesV2.Provider.Dodo);
}
function testQuoteConfiguredProvidersStillDiscoversConfiguredRoutes() public view {
RouteTypesV2.ProviderQuote[] memory quotes =
router.quoteConfiguredProviders(address(weth), address(usdt), 1 ether);
assertEq(quotes.length, 1);
assertEq(uint256(quotes[0].provider), uint256(RouteTypesV2.Provider.Dodo));
assertEq(quotes[0].amountOut, 1_800 ether);
}
function testMultiLegExecutionUsesPreviousLegOutput() public {
vm.startPrank(user);
weth.approve(address(router), 1 ether);