feat: Verify the amount out was received correctly for arbitrage swaps

Took 25 minutes


Took 3 minutes

Took 23 seconds
This commit is contained in:
Diana Carvalho
2025-05-13 11:41:11 +01:00
parent 67eba8d7d2
commit 70230bf05f

View File

@@ -436,16 +436,15 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
Address.sendValue(payable(receiver), amountOut);
}
if (tokenIn != tokenOut) {
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(
userAmount, amountOut
_verifyAmountOutWasReceived(
tokenIn,
tokenOut,
initialBalanceTokenOut,
amountOut,
receiver,
amountIn
);
}
}
}
/**
* @notice Internal implementation of the core swap logic shared between singleSwap() and singleSwapPermit2().
@@ -493,16 +492,15 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
Address.sendValue(payable(receiver), amountOut);
}
if (tokenIn != tokenOut) {
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(
userAmount, amountOut
_verifyAmountOutWasReceived(
tokenIn,
tokenOut,
initialBalanceTokenOut,
amountOut,
receiver,
amountIn
);
}
}
}
/**
* @notice Internal implementation of the core swap logic shared between sequentialSwap() and sequentialSwapPermit2().
@@ -546,17 +544,15 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
_unwrapETH(amountOut);
Address.sendValue(payable(receiver), amountOut);
}
if (tokenIn != tokenOut) {
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(
userAmount, amountOut
_verifyAmountOutWasReceived(
tokenIn,
tokenOut,
initialBalanceTokenOut,
amountOut,
receiver,
amountIn
);
}
}
}
/**
* @dev Executes sequential swaps as defined by the provided swap graph.
@@ -784,4 +780,27 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
return
token == address(0) ? owner.balance : IERC20(token).balanceOf(owner);
}
/**
* @dev Verifies that the expected amount of output tokens was received by the receiver.
* It also handles the case of arbitrage swaps where the input and output tokens are the same.
*/
function _verifyAmountOutWasReceived(
address tokenIn,
address tokenOut,
uint256 initialBalanceTokenOut,
uint256 amountOut,
address receiver,
uint256 amountIn
) internal view {
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
if (tokenIn == tokenOut) {
// If it is an arbitrage, we need to remove the amountIn from the initial balance to get a correct userAmount
initialBalanceTokenOut -= amountIn;
}
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut);
}
}
}