The Router Contract: Comparison between Soroswap and UniswapV2
Until now, we have developed the Factory and the Pair contract. The factory knows how many pairs it has created and can give us their contract addresses. Also, if we want to trade between token A and token B, and if that pair exists, the Factory will also give us the corresponding pair contract address. But what happens if there are two pairs, A-B and B-C, and a user wants to make a trade between A and C? We could first trade A to B and then B to C! This is why we have the Router Contract. The Router Contract allows swapping of tokens when a direct pair does not exist. It also handles liquidity provision and manages deposit and withdrawal functions for liquidity providers within the Soroswap ecosystem.The native token: ETH, WETH, and XLM.
In theUniswapV2Router02, there is a very important distinction between any ERC20 tokens and the native token ETH (and its wrapped version WETH). In particular, in the contract we find:
addLiquidityETHinstead ofaddLiquidityremoveLiquidityETHinstead ofremoveLiquidityremoveLiquidityETHWithPermitinstead ofremoveLiquidityWithPermit- Instead of just having
swapExactTokensForTokensandswapTokensForExactTokens; Uniswap Router needs to add 4 extra functions:swapExactETHForTokens,swapTokensForExactETH,swapExactTokensForETH,swapETHForExactTokens. - Instead of just having
swapExactTokensForTokensSupportingFeeOnTransferTokens, Uniswap Router needs to add 2 extra functions:swapExactETHForTokensSupportingFeeOnTransferTokensandswapExactTokensForETHSupportingFeeOnTransferTokens
SafeMath
The Router relies on the same overflow and underflow protections as the rest of Soroswap, described in the SoroswapLibrary comparison.Deadlines
In Ethereum we can send a transaction with low gas price, and that transaction could be accepted 5, 10 or more minutes later. In order to avoid unwanted transactions after a period of time, Uniswap introduces thedeadline parameter and the ensure(deadline) modifier:
soroban-sdk. So we’ll need to build a special function using the env.ledger().timestamp() object.
Permit
InUniswapV2Router02 we use the permit method of the UniswapV2ERC20.sol contracts that is defined here:
approve and `transfer, which allows users to modify the allowance mapping using a signed message. this function allows a token holder to grant permission for a specific address (spender) to spend their tokens up to a certain amount (value) with a specified expiration time (deadline). The signature ensures the authenticity of the permit, and the function enforces that the permit hasn’t expired and that it was signed by the legitimate token owner.
In Soroban we don’t need to implement something like this, as we use the require.auth() method when sending tokens from the user into the smart contract.
Conclusion: We don’t need to impement the removeLiquidityWithPermit, neither the removeLiquidityETHWithPermit functions (neither removeLiquidityETHWithPermitSupportingFeeOnTransferTokens)
Fees on Transfer
In UniswapV2, there is a special function that allows the user to swap tokens that charge a fee when doing a transfer. This tokens are popular in the deflactionist community, and indeed it made Uniswap upgrade their original UniswapV2Router (latter called UniswapV2Router01) contract to a UniswapV2Router02 version! You can read all the discussion of the Uniswap design in this issue In the code we see many functions that have the wordSupportingFeeOnTransferTokens:
_swapSupportingFeeOnTransferTokensswapExactTokensForTokensSupportingFeeOnTransferTokensswapExactETHForTokensSupportingFeeOnTransferTokensswapExactTokensForETHSupportingFeeOnTransferTokensremoveLiquidityETHSupportingFeeOnTransferTokens
_swapSupportingFeeOnTransferTokens and removeLiquidityETHSupportingFeeOnTransferTokens
These functions work equal to _swap and removeLiquidityETH but succeeds for tokens that take a fee on transfer.
Because Soroswap wanted to support all types of tokens, the plan at the time was to carry this logic into the SoroswapRouter contract.