feat: TychoRouter swap method not requiring Permit2

- Assume the tokens have been transferred into our router beforehand.
This commit is contained in:
TAMARA LIPOWSKI
2025-02-19 16:15:57 -05:00
parent 1c56431690
commit c3482a509a
3 changed files with 161 additions and 14 deletions

View File

@@ -66,6 +66,80 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
_weth = IWETH(weth);
}
/**
* @notice Executes a swap operation based on a predefined swap graph, supporting internal token amount splits.
* This function enables multi-step swaps, optional ETH wrapping/unwrapping, and validates the output amount
* against a user-specified minimum. This function expects the input tokens to already be in the router at
* the time of calling.
*
* @dev
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router.
* - Swaps are executed sequentially using the `_swap` function.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is bigger than 0.
*
* @param amountIn The input token amount to be swapped.
* @param tokenIn The address of the input token. Use `address(0)` for native ETH when `wrapEth` is true.
* @param tokenOut The address of the output token. Use `address(0)` for native ETH when `unwrapEth` is true.
* @param minAmountOut The minimum acceptable amount of the output token. Reverts if this condition is not met. If it's 0, no check is performed.
* @param wrapEth If true, treats the input token as native ETH and wraps it into WETH.
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
* @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations).
* @param receiver The address to receive the output tokens.
* @param swaps Encoded swap graph data containing details of each swap.
*
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable.
*/
function swap(
uint256 amountIn,
address tokenIn,
address tokenOut,
uint256 minAmountOut,
bool wrapEth,
bool unwrapEth,
uint256 nTokens,
address receiver,
bytes calldata swaps
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
if (receiver == address(0)) {
revert TychoRouter__AddressZero();
}
// Assume funds already in our router.
if (wrapEth) {
_wrapETH(amountIn);
tokenIn = address(_weth);
}
amountOut = _swap(amountIn, nTokens, swaps);
if (fee > 0) {
uint256 feeAmount = (amountOut * fee) / 10000;
amountOut -= feeAmount;
IERC20(tokenOut).safeTransfer(feeReceiver, feeAmount);
}
if (minAmountOut > 0 && amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
}
uint256 leftoverAmountIn = IERC20(tokenIn).balanceOf(address(this));
if (leftoverAmountIn > 0) {
revert TychoRouter__AmountInNotFullySpent(leftoverAmountIn);
}
if (unwrapEth) {
_unwrapETH(amountOut);
}
if (tokenOut == address(0)) {
Address.sendValue(payable(receiver), amountOut);
} else {
IERC20(tokenOut).safeTransfer(receiver, amountOut);
}
}
/**
* @notice Executes a swap operation based on a predefined swap graph, supporting internal token amount splits.
* This function enables multi-step swaps, optional ETH wrapping/unwrapping, and validates the output amount
@@ -93,7 +167,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
*
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable.
*/
function swap(
function swapPermit2(
uint256 amountIn,
address tokenIn,
address tokenOut,