Guardians audit potential bug in UniswapAdapter contract? #295
-
In function _uniswapInvest(IERC20 token, uint256 amount) internal {
IERC20 counterPartyToken = token == i_weth ? i_tokenOne : i_weth;
// We will do half in WETH and half in the token
uint256 amountOfTokenToSwap = amount / 2;
// the path array is supplied to the Uniswap router, which allows us to create swap paths
// in case a pool does not exist for the input token and the output token
// however, in this case, we are sure that a swap path exists for all pair permutations of WETH, USDC and LINK
// (excluding pair permutations including the same token type)
// the element at index 0 is the address of the input token
// the element at index 1 is the address of the output token
s_pathArray = [address(token), address(counterPartyToken)];
bool succ = token.approve(address(i_uniswapRouter), amountOfTokenToSwap);
if (!succ) {
revert UniswapAdapter__TransferFailed();
}
uint256[] memory amounts = i_uniswapRouter.swapExactTokensForTokens({
amountIn: amountOfTokenToSwap,
amountOutMin: 0,
path: s_pathArray,
to: address(this),
deadline: block.timestamp
});
succ = counterPartyToken.approve(address(i_uniswapRouter), amounts[1]);
if (!succ) {
revert UniswapAdapter__TransferFailed();
}
succ = token.approve(address(i_uniswapRouter), amountOfTokenToSwap + amounts[0]);
if (!succ) {
revert UniswapAdapter__TransferFailed();
}
// amounts[1] should be the WETH amount we got back
(uint256 tokenAmount, uint256 counterPartyTokenAmount, uint256 liquidity) = i_uniswapRouter.addLiquidity({
tokenA: address(token),
tokenB: address(counterPartyToken),
@> amountADesired: amountOfTokenToSwap + amounts[0],
amountBDesired: amounts[1],
amountAMin: 0,
amountBMin: 0,
to: address(this),
deadline: block.timestamp
});
emit UniswapInvested(tokenAmount, counterPartyTokenAmount, liquidity);
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 8 replies
-
Below is the core logic /**
*
* @param tokenA erc20 token that we want to add to the liquidity pool
* @param tokenB erc20 token that we want to add to the liquidity pool
* @param amountADesired the amount of tokenA that we desire to add to the liquidity pool
* @param amountBDesired the amount of tokenB that we desire to add to the liquidity pool
* @param amountAMin the minimum amount of tokenA that we are willing to add to the liquidity pool
* @param amountBMin the minimum amount of tokenB that we are willing to add to the liquidity pool
* @return amountA the amount of tokenA that we end up adding to the liquidity pool
* @return amountB the amount of tokenB that we end up adding to the liquidity pool
*/
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
// we get the reserve of both tokenA and tokenB from the pair contract
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
// if both of the reserve are `0` then there is no liquidity in the pool, so the amount of tokenA and tokenB that will be added to the pool is the amount of token the user desire to add to the pool
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else /** else if there is already liquidity in the pool then we need to do some maths to know the actual amount of tokenA and tokenB that the user needs to add to the liquidity pool */ {
// we call the `quote` helper function to help us get the optimal amount of tokenB that should be deposited to the pool using the desired amount of tokenA that the user specified
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
// we check that the optimal amount of tokenB that we get is less than or equal to the amount of tokenB the user desired to add to the liquidity pool
if (amountBOptimal <= amountBDesired) {
// we check that the optimal amount of tokenB that we get is greater than or equals to the minimum amount of tokenB the user is willing to add to the liquidity pool
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
// we then confirm that the amount of tokenA that will addedd to the liquidity pool is the amount of tokenA desired by the user and the amount of tokenB that will be added to the pool is the amount of tokenB optimal for the amount of tokenA desired by the user
(amountA, amountB) = (amountADesired, amountBOptimal);
} else /** if the optimal amount of tokenB for the amount of tokenA desired by the user is not less than or equal to the amount of tokenB desired by the user we enter this block of code */ {
// we calculate the optimal amount of tokenA that is required to add the user desired amount of tokenB to the liquidity pool
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
// we check that the optimal amount of tokenA we calculated is less than or equal to the user desired amount of tokenA
assert(amountAOptimal <= amountADesired);
// we check that the optimal amount of tokenA we clculated is greater than or equal to the user minimum amount of tokenA
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
// we confirm that the amount of tokenA that will be added to the liquidity pool is the optimal amount of tokenA that we calculated and the amount of tokenB that will be added to the liquidity pool is the user desired amount of tokenB
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
} |
Beta Was this translation helpful? Give feedback.
Below is the core logic
addLiquidity
function, Considering the checks in this function, the function will add liquidity usingamountBDesired
to get the equivalent value needed foramountADesired
which should work as that should be the half amount that is remained after the first swap.