-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
58 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,61 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ~0.6.8; | ||
pragma solidity >=0.4.0 <0.8.0; | ||
|
||
import "@openzeppelin/contracts/math/SafeMath.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "../interfaces/uniswap/IUniswapV2Pair.sol"; | ||
import "../interfaces/uniswap/IUniswapV3Pool.sol"; | ||
import "../interfaces/uniswap/Quoter.sol"; | ||
import "../interfaces/uniswap/SafeCast.sol"; | ||
import "../interfaces/uniswap/TickMath.sol"; | ||
import "./ISwappaPairV1.sol"; | ||
|
||
contract PairUniswapV3 is ISwappaPairV1 { | ||
using SafeMath for uint; | ||
using SafeCast for uint; | ||
|
||
function swap( | ||
address input, | ||
address output, | ||
address to, | ||
bytes calldata data | ||
) external override { | ||
(address pairAddr, uint feeK) = parseData(data); | ||
uint inputAmount = ERC20(input).balanceOf(address(this)); | ||
require( | ||
ERC20(input).transfer(pairAddr, inputAmount), | ||
"PairUniswapV2: transfer failed!"); | ||
IUniswapV2Pair pair = IUniswapV2Pair(pairAddr); | ||
(uint reserve0, uint reserve1,) = pair.getReserves(); | ||
if (pair.token0() == input) { | ||
uint outputAmount = getAmountOut(inputAmount, reserve0, reserve1, feeK); | ||
pair.swap(0, outputAmount, to, new bytes(0)); | ||
} else { | ||
uint outputAmount = getAmountOut(inputAmount, reserve1, reserve0, feeK); | ||
pair.swap(outputAmount, 0, to, new bytes(0)); | ||
} | ||
} | ||
|
||
function parseData(bytes memory data) private pure returns (address pairAddr, uint fee) { | ||
require(data.length == 21, "PairUniswapV2: invalid data!"); | ||
fee = uint(1000).sub(uint8(data[20])); | ||
assembly { | ||
pairAddr := mload(add(data, 20)) | ||
function swap( | ||
address input, | ||
address output, | ||
address to, | ||
bytes calldata data | ||
) external override { | ||
address pairAddr = parseData(data); | ||
uint inputAmount = ERC20(input).balanceOf(address(this)); | ||
require( | ||
ERC20(input).transfer(pairAddr, inputAmount), | ||
"PairUniswapV3: transfer failed!"); | ||
IUniswapV3Pool pair = IUniswapV3Pool(pairAddr); | ||
bool zeroForOne = pair.token0() == input; | ||
pair.swap( | ||
to, | ||
zeroForOne, | ||
inputAmount.toInt256(), | ||
zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1, | ||
new bytes(0)); | ||
} | ||
} | ||
|
||
function getOutputAmount( | ||
address input, | ||
address output, | ||
uint amountIn, | ||
bytes calldata data | ||
) external view override returns (uint amountOut) { | ||
(address pairAddr, uint feeK) = parseData(data); | ||
IUniswapV2Pair pair = IUniswapV2Pair(pairAddr); | ||
(uint reserve0, uint reserve1,) = pair.getReserves(); | ||
(uint reserveIn, uint reserveOut) = pair.token0() == input ? (reserve0, reserve1) : (reserve1, reserve0); | ||
return getAmountOut(amountIn, reserveIn, reserveOut, feeK); | ||
} | ||
function parseData(bytes memory data) private pure returns (address pairAddr) { | ||
require(data.length == 20, "PairUniswapV3: invalid data!"); | ||
assembly { | ||
pairAddr := mload(add(data, 20)) | ||
} | ||
} | ||
|
||
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut, uint feeK) internal pure returns (uint amountOut) { | ||
uint amountInWithFee = amountIn.mul(feeK); | ||
uint numerator = amountInWithFee.mul(reserveOut); | ||
uint denominator = reserveIn.mul(1000).add(amountInWithFee); | ||
amountOut = numerator / denominator; | ||
} | ||
function getOutputAmount( | ||
address input, | ||
address output, | ||
uint amountIn, | ||
bytes calldata data | ||
) external view override returns (uint amountOut) { | ||
address pairAddr = parseData(data); | ||
IUniswapV3Pool pair = IUniswapV3Pool(pairAddr); | ||
bool zeroForOne = pair.token0() == input; | ||
// amount0, amount1 are delta of the pair reserves | ||
(int256 amount0, int256 amount1) = Quoter.quote( | ||
pair, | ||
zeroForOne, | ||
amountIn.toInt256(), | ||
zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1); | ||
return zeroForOne ? uint256(-amount1) : uint256(-amount0); | ||
} | ||
} |