feat: UniswapV2 SwapExecutor
--- don't change below this line --- ENG-4033 Took 52 minutes Took 3 minutes Took 5 minutes Took 36 seconds Took 2 minutes Took 30 seconds
This commit is contained in:
73
foundry/src/executors/Uniswapv2SwapExecutor.sol
Normal file
73
foundry/src/executors/Uniswapv2SwapExecutor.sol
Normal file
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.28;
|
||||
|
||||
import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {ISwapExecutor} from "../interfaces/ISwapExecutor.sol";
|
||||
|
||||
contract UniswapV2SwapExecutor is ISwapExecutor {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
function swap(uint256 givenAmount, bytes calldata data)
|
||||
external
|
||||
returns (uint256 calculatedAmount)
|
||||
{
|
||||
address target;
|
||||
address receiver;
|
||||
bool zeroForOne;
|
||||
bool exactOut;
|
||||
IERC20 tokenIn;
|
||||
|
||||
(tokenIn, target, receiver, zeroForOne, exactOut) = _decodeData(data);
|
||||
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
||||
tokenIn.safeTransfer(target, givenAmount);
|
||||
|
||||
IUniswapV2Pair pool = IUniswapV2Pair(target);
|
||||
if (zeroForOne) {
|
||||
pool.swap(0, calculatedAmount, receiver, "");
|
||||
} else {
|
||||
pool.swap(calculatedAmount, 0, receiver, "");
|
||||
}
|
||||
}
|
||||
|
||||
function _decodeData(bytes calldata data)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
IERC20 inToken,
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne,
|
||||
bool exactOut
|
||||
)
|
||||
{
|
||||
inToken = IERC20(address(bytes20(data[0:20])));
|
||||
target = address(bytes20(data[20:40]));
|
||||
receiver = address(bytes20(data[40:60]));
|
||||
zeroForOne = uint8(data[60]) > 0;
|
||||
exactOut = uint8(data[61]) > 0;
|
||||
}
|
||||
|
||||
function _getAmountOut(address target, uint256 amountIn, bool zeroForOne)
|
||||
internal
|
||||
view
|
||||
returns (uint256 amount)
|
||||
{
|
||||
IUniswapV2Pair pair = IUniswapV2Pair(target);
|
||||
uint112 reserveIn;
|
||||
uint112 reserveOut;
|
||||
if (zeroForOne) {
|
||||
// slither-disable-next-line unused-return
|
||||
(reserveIn, reserveOut,) = pair.getReserves();
|
||||
} else {
|
||||
// slither-disable-next-line unused-return
|
||||
(reserveOut, reserveIn,) = pair.getReserves();
|
||||
}
|
||||
|
||||
require(reserveIn > 0 && reserveOut > 0, "L");
|
||||
uint256 amountInWithFee = amountIn * 997;
|
||||
uint256 numerator = amountInWithFee * uint256(reserveOut);
|
||||
uint256 denominator = (uint256(reserveIn) * 1000) + amountInWithFee;
|
||||
amount = numerator / denominator;
|
||||
}
|
||||
}
|
||||
37
foundry/src/interfaces/ISwapExecutor.sol
Normal file
37
foundry/src/interfaces/ISwapExecutor.sol
Normal file
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.28;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
pragma abicoder v2;
|
||||
|
||||
interface ISwapExecutor {
|
||||
/**
|
||||
* @notice Performs a swap on a liquidity pool.
|
||||
* @dev This method can either take the amount of the input token or the amount
|
||||
* of the output token that we would like to swap. If called with the amount of
|
||||
* the input token, the amount of the output token will be returned, and vice
|
||||
* versa. Whether it is the input or output that is given, is encoded in the data
|
||||
* parameter.
|
||||
*
|
||||
* Note Part of the informal interface is that the executor supports sending the received
|
||||
* tokens to a receiver address. If the underlying smart contract does not provide this
|
||||
* functionality consider adding an additional transfer in the implementation.
|
||||
*
|
||||
* This function is marked as `payable` to accommodate delegatecalls, which can forward
|
||||
* a potential `msg.value` to it.
|
||||
*
|
||||
* @param givenAmount The amount of either the input token or output token to swap.
|
||||
* @param data Data that holds information necessary to perform the swap.
|
||||
* @return calculatedAmount The amount of either the input token or output token
|
||||
* swapped, depending on the givenAmount inputted.
|
||||
*/
|
||||
function swap(uint256 givenAmount, bytes calldata data)
|
||||
external
|
||||
returns (uint256 calculatedAmount);
|
||||
}
|
||||
|
||||
interface ISwapExecutorErrors {
|
||||
error InvalidParameterLength(uint256);
|
||||
error UnknownCurveType(uint8);
|
||||
}
|
||||
Reference in New Issue
Block a user