Router

The router is a smart contract for swapping the tokens through the paths.

Function onUpgrade

This function was introduced in the Facet Swap contracts. It can be used to reset the contract owner and the pause state of the contract. The function does not enforce access control. We were informed by the Facet team that the router contracts will be present in the genesis state and already initialized to version 3. Since the function is decorated with the reinitializer(3) modifier, it will not be possible to call it and change the owner or pause state.

Since failing to deploy the contracts with the correct version would create a severe security issue, we recommend adding tests to the code that generate the genesis state to ensure all routers are initialized correctly and reject calls to onUpgrade.

This observation was addressed in commit , which removed the onUpgrade function from the router contract.

Functions _swapExactTokensForTokens and swapExactTokensForTokens

The internal function _swapExactTokensForTokens is functionally equivalent to the external function swapExactTokensForTokens from the Uniswap codebase. Since the function is now internal, it cannot be directly invoked, but must be invoked through the public swapExactTokensForTokens function. It performs a swap of an exact quantity of input tokens, in exchange for a minimum desired quantity of output tokens.

The swapExactTokensForTokens function is the new entry point for this functionality and differs from the original entry point in the following ways:

  • The initial input or the final output asset must be WETH.

  • A fee is charged either on the input or output amount, depending on which one is WETH; if both are WETH, the fee is charged on the input.

The fee is determined by the protocolFeeBPS parameter, which is configurable by the contract owner.

We note that the fee logic is not clear, particularly in the case where both the input and output assets are WETH. We recommend adding an assertion that ensures the WETH balance of the contract at the end of the function execution is greater than or equal to the balance at the start, as a defense-in-depth mechanism to prevent possible exploits from stealing protocol fees. This recommendation was adopted in commit .

Functions _swapTokensForExactTokens and swapTokensForExactTokens

The internal function _swapTokensForExactTokens is functionally equivalent to the external function swapTokensForExactTokens from the Uniswap codebase. Since the function is now internal, it cannot be directly invoked, but must be invoked through the public swapTokensForExactTokens function. It allows to perform a swap of a maximum given quantity of input tokens, in exchange for a specific quantity of output tokens.

The swapTokensForExactTokens function is the new entry point for this functionality and differs from the original entry point in the following ways:

  • The initial input or the final output asset must be WETH.

  • A fee is charged either on the input or output amount, depending on which one is WETH; if both are WETH, the fee is charged on the input.

The fee is determined by the protocolFeeBPS parameter, which is configurable by the contract owner.

We note that, similarly to swapExactTokensForTokens, the fee logic is not clear, particularly in the case where both the input and output assets are WETH. We recommend adding an assertion that ensures the WETH balance of the contract at the end of the function execution is greater than or equal to the balance at the start, as a defense-in-depth mechanism to prevent possible exploits from stealing protocol fees. This recommendation was adopted in commit .

Function initialize

This function can be used to initialize the contract. It does not have a direct counterpart in the original Uniswap contracts.

It does not have security issues that can be exploited without preconditions; however, we note it must be called in the same transaction where the router contract is deployed, or, alternatively, the contract configuration must be checked to ensure no malicious call was made between the time the contract is deployed and the time it is initialized (in which case. the contract must be redeployed and reinitialized).

Functions addLiquidity and _addLiquidity

The public function addLiquidity corresponds to the external function addLiquidity in the Uniswap contracts. It is functionally equivalent and can be used to add liquidity to a pool in exchange for LP tokens.

The internal function _addLiquidity also matches its counterpart in the original code.

Function removeLiquidity

This function can be used to burn LP tokens for a given pair, getting back the corresponding assets.

Function _swap

This internal function can be used to execute a chain of swaps. It is functionally equivalent to the original Uniswap version, with the notable exception of the addition of a maximum swap path length. By default, the limit is initialized to three by the initialize function, but it is read from the router contract storage, making it potentially configurable. However, we note that at the moment, there is no functionality that allows to change this limit, besides upgrading the contract.

Function _safeTransferFrom

This function can be used to perform a safeTransfer ERC-20 call. The function does not match the version used by the original contracts and is less compatible with tokens that do not correctly implement the ERC-20 standard. This is not an issue provided that all assets used with Facet Swap correctly implement the ERC-20 standard.

Functions getAmountsOut and getAmountsIn

These functions can be used to obtain the results of, respectively, getAmountOut and getAmountIn for each swap in a chain of swaps.

The bodies of the functions were inlined from UniswapV2Library. They are almost functionally equivalent to the original functions. The Facet versions introduced a limit on the swap path length.

Function getAmountOut

This function can be used to get the maximum output amount to be expected when swapping a specified amount of input asset, given the values of the pool reserves.

The function was inlined from UniswapV2Library, with modifications required to support the variable swap fee rate, which is obtained from the factory contract.

Function getAmountIn

This function can be used to get the minimum input amount needed to perform a swap resulting in a specified amount of output asset, given the values of the pool reserves.

The function was inlined from UniswapV2Library, with modifications required to support the variable swap fee rate, which is obtained from the factory contract.

Other functions inlined from UniswapV2Library

The following functions were inlined from UniswapV2Library and remain functionally equivalent to the original code. Minor changes were made to support accessing storage in a manner compatible with the chosen upgradability pattern and to replace references to Uniswap with references to Facet Swap.

  • quote, which is used to convert an amount of asset into the counterpart, given the current reserves — note that this function does not actually perform a swap and does not account for fees or slippage

  • getReserves, which is used to get the value of the reserves (cached balance) for a given pair of assets

  • pairFor, which is used to get the address of the pool for a given pair of assets from the factory contract

  • sortTokens, which is used to sort tokens in lexicographic order

Function calculateFeeAmount

This function can be used to compute the fees charged by the router to a given asset amount.

Function updateProtocolFee

This function can be used by the contract owner to update the fee percentage charged by the router.

Function withdrawFees

This function can be used by the contract owner to withdraw fees accrued by the router.

Functions pause and unpause

These functions can be used to pause and unpause the contract. They were introduced by Facet Swap and work as intended work as intended with respect to the router contract, preventing swaps and adding or removing liquidity through the router.

We note, however, that the pause feature does not prevent calling the pools directly.

Function userStats

This function can be used to retrieve information about a given user related to a token pair:

  • User balances for the two assets

  • User LP token balance for the corresponding pool

  • Address of the pool

  • Pool reserve values

  • Names of the two assets

Function factory

This function can be used to retrieve the address of the factory contract. The Uniswap contract did not contain this function explicitly, as it was automatically generated by the compiler due to the factory state variable being public. Since the Facet Swap contracts adopt the chosen upgradability pattern, public getters are not generated by the Solidity compiler and had to be manually implemented.

Zellic © 2025Back to top ↑