Merge pull request #195 from propeller-heads/router/dc/ENG-4529-arbitrage-balance-check

feat: Arbitrage balance check and explicitly handle the TransferType.NONE case
This commit is contained in:
dianacarvalho1
2025-05-14 15:00:00 +01:00
committed by GitHub
2 changed files with 53 additions and 29 deletions

View File

@@ -436,15 +436,14 @@ 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
);
}
/**
@@ -493,15 +492,14 @@ 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
);
}
/**
@@ -546,16 +544,14 @@ 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
);
}
/**
@@ -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);
}
}
}

View File

@@ -6,6 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
error TokenTransfer__AddressZero();
error TokenTransfer__InvalidTransferType();
contract TokenTransfer {
using SafeERC20 for IERC20;
@@ -45,7 +46,9 @@ contract TokenTransfer {
uint256 amount,
TransferType transferType
) internal {
if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
if (transferType == TransferType.NONE) {
return;
} else if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
if (tokenIn == address(0)) {
payable(receiver).transfer(amount);
} else {
@@ -65,6 +68,8 @@ contract TokenTransfer {
permit2.transferFrom(
sender, address(this), uint160(amount), tokenIn
);
} else {
revert TokenTransfer__InvalidTransferType();
}
}
}