Skip to content

Commit

Permalink
chore: v3 forks
Browse files Browse the repository at this point in the history
  • Loading branch information
exception committed Jun 18, 2024
1 parent d9d06d4 commit efad095
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 11 deletions.
144 changes: 144 additions & 0 deletions contracts/callers/UniswapV3Caller.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.12;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import { IWETH9 } from "../interfaces/IWETH9.sol";
import { Base } from "../shared/Base.sol";
import { TokensHandler } from "../shared/TokensHandler.sol";
import { Weth } from "../shared/Weth.sol";
// solhint-disable-next-line
import { CallbackValidation } from "@uniswap/v3-periphery/contracts/libraries/CallbackValidation.sol";
import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol";
// solhint-disable-next-line
import { UniswapV3Swap } from "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol";

contract UniswapV3Caller is TokensHandler, Weth {
address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

constructor(address _weth) Weth(_weth) {}

function callBytes(bytes calldata callerCallData) external {
(
address inputToken,
address outputToken,
address pool,
uint256 fixedSideAmount,
bool isExactInput
) = abi.decode(callerCallData, (address, address, address, uint256, bool));

if (inputToken == ETH) {
depositEth(fixedSideAmount);
inputToken = getWeth();
}

if (isExactInput) {
exactInputSwap(inputToken, outputToken, pool, fixedSideAmount);
} else {
exactOutputSwap(inputToken, outputToken, pool, fixedSideAmount);
}

if (outputToken == ETH) {
withdrawEth();
Base.transfer(ETH, msg.sender, Base.getBalance(ETH));
} else {
Base.transfer(outputToken, msg.sender, Base.getBalance(outputToken));
}

if (inputToken != ETH) {
Base.transfer(inputToken, msg.sender, Base.getBalance(inputToken));
}
}

function exactInputSwap(
address inputToken,
address outputToken,
address pool,
uint256 amountIn
) internal {
IUniswapV3Pool v3Pool = IUniswapV3Pool(pool);

SafeERC20.safeApprove(IERC20(inputToken), pool, amountIn);

(int256 amount0, int256 amount1) = v3Pool.swap(
address(this),
inputToken < outputToken,
int256(amountIn),
inputToken < outputToken ? -TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1,
abi.encode(inputToken, outputToken)
);
}

function exactOutputSwap(
address inputToken,
address outputToken,
address pool,
uint256 amountOut
) internal {
IUniswapV3Pool v3Pool = IUniswapV3Pool(pool);

int256 amountInMaximum = int256(
calculateMaxInput(inputToken, outputToken, pool, amountOut)
);

SafeERC20.safeApprove(IERC20(inputToken), pool, uint256(amountInMaximum));

(int256 amount0, int256 amount1) = v3Pool.swap(
address(this),
inputToken < outputToken,
-int256(amountOut),
inputToken < outputToken ? -TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1,
abi.encode(inputToken, outputToken)
);

// Refund any excess tokens
uint256 refundAmount = uint256(
amountInMaximum - (inputToken < outputToken ? amount0 : amount1)
);
if (refundAmount > 0) {
SafeERC20.safeTransfer(IERC20(inputToken), msg.sender, refundAmount);
}
}

function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external {
(address inputToken, address outputToken) = abi.decode(data, (address, address));

if (amount0Delta > 0) {
SafeERC20.safeTransfer(IERC20(inputToken), msg.sender, uint256(amount0Delta));
} else {
SafeERC20.safeTransfer(IERC20(outputToken), msg.sender, uint256(amount1Delta));
}
}

function calculateMaxInput(
address inputToken,
address outputToken,
address pool,
uint256 amountOut
) internal view returns (uint256 memory maxInput) {
IUniswapV3Pool v3Pool = IUniswapV3Pool(pool);

(uint160 sqrtRatioX96, , , , , , ) = v3Pool.slot0();
uint256 price = (sqrtRatioX96 * sqrtRatioX96) / (2 ** 96);

if (inputToken < outputToken) {
return (amountOut * price) / 1e18;
} else {
return (amountOut * 1e18) / price;
}
}

function depositEth(uint256 amount) internal {
IWETH9(getWeth()).deposit{ value: amount }();
}

function withdrawEth() internal {
uint256 wethBalance = IERC20(getWeth()).balanceOf(address(this));
if (wethBalance > uint256(0)) IWETH9(getWeth()).withdraw(wethBalance);
}
}
100 changes: 91 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
"license": "LGPL-3.0-only",
"repository": "https://github.com/zeriontech/defi-sdk",
"dependencies": {
"@openzeppelin/contracts": "4.4.0"
"@openzeppelin/contracts": "4.4.0",
"@uniswap/v3-core": "^1.0.1",
"@uniswap/v3-periphery": "^1.4.4"
},
"devDependencies": {
"@babel/core": "7.22.9",
Expand All @@ -41,8 +43,8 @@
"@matterlabs/hardhat-zksync-deploy": "^0.6.3",
"@matterlabs/hardhat-zksync-solc": "^0.4.1",
"@matterlabs/hardhat-zksync-verify": "^0.2.0",
"@nomiclabs/hardhat-ethers": "2.2.3",
"@nomicfoundation/hardhat-verify": "1.1.1",
"@nomiclabs/hardhat-ethers": "2.2.3",
"@nomiclabs/hardhat-waffle": "2.0.6",
"@types/chai": "4.3.5",
"@types/mocha": "10.0.1",
Expand Down

0 comments on commit efad095

Please sign in to comment.