Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a wrapper contract that allows users to use ETH instead of WETH #404

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Fix compile issues
penandlim committed Jun 18, 2021
commit e2fbf60337b11347ca2eca3e2801c7f34df515ad
92 changes: 60 additions & 32 deletions contracts/SwapEthWrapper.sol
Original file line number Diff line number Diff line change
@@ -4,42 +4,46 @@ pragma solidity 0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "./Swap.sol";
import "./interfaces/IWETH9.sol";

contract SwapEthWrapper {
using SafeERC20 for IERC20;
using SafeMath for uint256;

Swap public immutable swap;
Swap public immutable swapInstance;
LPToken public immutable lpToken;
address public immutable weth;
address payable public immutable weth;
IERC20[] public pooledTokens;
uint256 public immutable wethIndex;
uint8 public immutable wethIndex;

uint8 private constant MAX_UINT8 = 2**8 - 1;
uint256 private constant MAX_UINT256 = 2**256 - 1;

constructor(address wethAddress, Swap swapAddress) public {
swap = swapAddress;
lpToken = swap.swapStorage().lpToken;
wethIndex = MAX_UINT8;
constructor(address payable wethAddress, Swap swapAddress) public {
(, , , , , , LPToken lpToken_) = swapAddress.swapStorage();
uint8 wethIndex_ = MAX_UINT8;

for (uint8 = 0; i < 32; i++) {
try swap.getToken(i) returns (IERC20 token) {
for (uint8 i = 0; i < 32; i++) {
try swapAddress.getToken(i) returns (IERC20 token) {
pooledTokens.push(token);
if (token == wethAddress) {
wethIndex = i;
if (address(token) == wethAddress) {
wethIndex_ = i;
}
// Approve pooled tokens to be used by Swap
token.approve(swap, MAX_UINT256);
token.approve(address(swapAddress), MAX_UINT256);
} catch {
break;
}
}
require(wethIndex != MAX_UINT8, "WETH was not found in the swap pool");
require(wethIndex_ != MAX_UINT8, "WETH was not found in the swap pool");
// Set immutable variables
wethIndex = wethIndex_;
weth = wethAddress;
swapInstance = swapAddress;
lpToken = lpToken_;
// Approve LPToken to be used by Swap
lpToken.approve(swap, MAX_UINT256);
lpToken_.approve(address(swapAddress), MAX_UINT256);
}

function addLiquidity(
@@ -52,11 +56,12 @@ contract SwapEthWrapper {
IWETH9(weth).deposit{value: msg.value}();
}
// If using WETH, transfer them to this contract.
if (amounts[wethIndex] > 0) {
IWETH9(weth).transferFrom(msg.sender, address(this), amount);
uint256 wethAmount = amounts[wethIndex];
if (wethAmount > 0) {
IWETH9(weth).transferFrom(msg.sender, address(this), wethAmount);
}
// Sum up the ETH and WETH amount.
amounts[wethIndex] = amounts[wethIndex].add(msg.value);
amounts[wethIndex] = wethAmount.add(msg.value);
// Go through amounts array and transfer respective tokens to this contract.
for (uint256 i = 0; i < amounts.length; i++) {
uint256 amount = amounts[i];
@@ -69,9 +74,10 @@ contract SwapEthWrapper {
}
}
// Add the assets to the pool
uint256 lpTokenAmount = swap.addLiquidity(amounts, minToMint, deadline);
uint256 lpTokenAmount =
swapInstance.addLiquidity(amounts, minToMint, deadline);
// Send the LPToken to msg.sender
IERC20(lpToken).safeTransfer(msg.sender, lpTokenAmount);
IERC20(address(lpToken)).safeTransfer(msg.sender, lpTokenAmount);
return lpTokenAmount;
}

@@ -81,10 +87,14 @@ contract SwapEthWrapper {
uint256 deadline
) external returns (uint256[] memory) {
// Transfer LPToken from msg.sender to this contract.
IERC20(lpToken).safeTransferFrom(msg.sender, address(this), amount);
IERC20(address(lpToken)).safeTransferFrom(
msg.sender,
address(this),
amount
);
// Remove liquidity
uint256[] memory amounts =
swap.removeLiquidity(amount, minAmounts, deadline);
swapInstance.removeLiquidity(amount, minAmounts, deadline);
// Send the tokens back to the user
for (uint256 i = 0; i < amounts.length; i++) {
if (i != wethIndex) {
@@ -105,22 +115,22 @@ contract SwapEthWrapper {
uint256 deadline
) external returns (uint256) {
// Transfer LPToken from msg.sender to this contract.
IERC20(lpToken).safeTransferFrom(
IERC20(address(lpToken)).safeTransferFrom(
msg.sender,
address(this),
tokenAmount
);
// Withdraw via single token
uint256 amount =
swap.removeLiquidityOneToken(
swapInstance.removeLiquidityOneToken(
tokenAmount,
tokenIndex,
minAmount,
deadline
);
// Transfer the token to msg.sender accordingly
if (tokenIndex != wethIndex) {
pooledTokens[i].safeTransfer(msg.sender, amount);
pooledTokens[tokenIndex].safeTransfer(msg.sender, amount);
} else {
IWETH9(weth).withdraw(amount);
(bool success, ) = msg.sender.call{value: amount}("");
@@ -135,14 +145,18 @@ contract SwapEthWrapper {
uint256 deadline
) external returns (uint256) {
// Transfer LPToken from msg.sender to this contract.
IERC20(lpToken).safeTransferFrom(
IERC20(address(lpToken)).safeTransferFrom(
msg.sender,
address(this),
tokenAmount
maxBurnAmount
);
// Withdraw in imbalanced ratio
uint256 burnedLpTokenAmount =
swap.removeLiquidityImbalance(amounts, maxBurnAmount, deadline);
swapInstance.removeLiquidityImbalance(
amounts,
maxBurnAmount,
deadline
);
// Send the tokens back to the user
for (uint256 i = 0; i < amounts.length; i++) {
if (i != wethIndex) {
@@ -153,6 +167,14 @@ contract SwapEthWrapper {
require(success, "ETH_TRANSFER_FAILED");
}
}
// Send any extra LP tokens back as well
uint256 extraLpTokenAmount = maxBurnAmount.sub(burnedLpTokenAmount);
if (extraLpTokenAmount > 0) {
IERC20(address(lpToken)).safeTransfer(
msg.sender,
extraLpTokenAmount
);
}
return burnedLpTokenAmount;
}

@@ -162,7 +184,7 @@ contract SwapEthWrapper {
uint256 dx,
uint256 minDy,
uint256 deadline
) external returns (uint256) {
) external payable returns (uint256) {
// Transfer tokens from msg.sender to this contract
if (tokenIndexFrom != wethIndex) {
IERC20(pooledTokens[tokenIndexFrom]).safeTransferFrom(
@@ -175,13 +197,19 @@ contract SwapEthWrapper {
}
// Execute swap
uint256 dy =
swap.swap(tokenIndexFrom, tokenIndexTo, dx, minDy, deadline);
swapInstance.swap(
tokenIndexFrom,
tokenIndexTo,
dx,
minDy,
deadline
);
// Transfer the swapped tokens to msg.sender
if (tokenIndexTo != wethIndex) {
IERC20(pooledTokens[tokenIndexTo]).safeTransfer(msg.sender, dy);
} else {
IWETH9(weth).withdraw(amounts[i]);
(bool success, ) = msg.sender.call{value: amounts[i]}("");
IWETH9(weth).withdraw(dy);
(bool success, ) = msg.sender.call{value: dy}("");
require(success, "ETH_TRANSFER_FAILED");
}
return dy;
33 changes: 33 additions & 0 deletions contracts/interfaces/IWETH9.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT

pragma solidity >=0.4.0;

interface IWETH9 {
function name() external view returns (string memory);

function symbol() external view returns (string memory);

function decimals() external view returns (uint8);

function balanceOf(address) external view returns (uint256);

function allowance(address, address) external view returns (uint256);

receive() external payable;

function deposit() external payable;

function withdraw(uint256 wad) external;

function totalSupply() external view returns (uint256);

function approve(address guy, uint256 wad) external returns (bool);

function transfer(address dst, uint256 wad) external returns (bool);

function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
}