Skip to content

Commit

Permalink
fix: mutiple swap + deflationary token support + swapExactTokensForTo…
Browse files Browse the repository at this point in the history
…kens
  • Loading branch information
Debugger022 committed Feb 2, 2023
1 parent ae85c72 commit 9437a22
Showing 1 changed file with 70 additions and 43 deletions.
113 changes: 70 additions & 43 deletions contracts/Swap/SwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pragma solidity 0.8.13;

import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IPancakeSwapV2Router.sol";
import "./interfaces/IVtoken.sol";
import "./interfaces/IWBNB.sol";
Expand Down Expand Up @@ -96,15 +97,9 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
address[] calldata path,
uint256 deadline
) external override ensure(deadline) {
uint256[] memory swapAmounts = _swapExactTokensForTokens(amountIn, amountOutMin, path, msg.sender);
TransferHelper.safeApprove(path[1], vTokenAddress, 0);
TransferHelper.safeApprove(path[1], vTokenAddress, swapAmounts[1]);
uint256 response = IVToken(vTokenAddress).mintBehalf(msg.sender, swapAmounts[1]);
if (response != 0) {
revert SupplyError(msg.sender, vTokenAddress, response);
} else {
emit SupplyOnBehalf(msg.sender, vTokenAddress, swapAmounts[1]);
}
uint256[] memory swapAmounts = _swapExactTokensForTokens(amountIn, amountOutMin, path, address(this));
uint256 swapAmount = swapAmounts[swapAmounts.length - 1];
_supplyInternal(path[1], vTokenAddress, swapAmount);
}

/**
Expand All @@ -122,14 +117,25 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
address[] calldata path,
uint256 deadline
) external payable override ensure(deadline) {
uint256[] memory swapAmounts = _swapExactETHForTokens(amountOutMin, path, msg.sender);
TransferHelper.safeApprove(path[1], vTokenAddress, 0);
TransferHelper.safeApprove(path[1], vTokenAddress, swapAmounts[1]);
uint256 response = IVToken(vTokenAddress).mintBehalf(msg.sender, swapAmounts[1]);
uint256[] memory swapAmounts = _swapExactETHForTokens(amountOutMin, path, address(this));
uint256 swapAmount = swapAmounts[swapAmounts.length - 1];
_supplyInternal(path[1], vTokenAddress, swapAmount);
}

/**
* @notice supply token to a Venus market
* @param path the addresses of the underlying token
* @param vTokenAddress The address of the vToken contract for supplying assets.
* @param swapAmount the amount of tokens supply to Venus Market.
*/
function _supplyInternal(address path, address vTokenAddress, uint256 swapAmount) internal {
TransferHelper.safeApprove(path, vTokenAddress, 0);
TransferHelper.safeApprove(path, vTokenAddress, swapAmount);
uint256 response = IVToken(vTokenAddress).mintBehalf(msg.sender, swapAmount);
if (response != 0) {
revert SupplyError(msg.sender, vTokenAddress, response);
} else {
emit SupplyOnBehalf(msg.sender, vTokenAddress, swapAmounts[1]);
emit SupplyOnBehalf(msg.sender, vTokenAddress, swapAmount);
}
}

Expand All @@ -148,15 +154,9 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
address[] calldata path,
uint256 deadline
) external override ensure(deadline) {
uint256[] memory swapAmounts = _swapExactTokensForTokens(amountIn, amountOutMin, path, msg.sender);
TransferHelper.safeApprove(path[1], vTokenAddress, 0);
TransferHelper.safeApprove(path[1], vTokenAddress, swapAmounts[1]);
uint256 response = IVToken(vTokenAddress).repayBorrowBehalf(msg.sender, swapAmounts[1]);
if (response != 0) {
revert RepayError(msg.sender, vTokenAddress, response);
} else {
emit RepayOnBehalf(msg.sender, vTokenAddress, swapAmounts[1]);
}
uint256[] memory swapAmounts = _swapExactTokensForTokens(amountIn, amountOutMin, path, address(this));
uint256 swapAmount = swapAmounts[swapAmounts.length - 1];
_repayInternal(path[1], vTokenAddress, swapAmount);
}

/**
Expand All @@ -173,14 +173,25 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
address[] calldata path,
uint256 deadline
) external payable override ensure(deadline) {
uint256[] memory swapAmounts = _swapExactETHForTokens(amountOutMin, path, msg.sender);
TransferHelper.safeApprove(path[1], vTokenAddress, 0);
TransferHelper.safeApprove(path[1], vTokenAddress, swapAmounts[1]);
uint256 response = IVToken(vTokenAddress).repayBorrowBehalf(msg.sender, swapAmounts[1]);
uint256[] memory swapAmounts = _swapExactETHForTokens(amountOutMin, path, address(this));
uint256 swapAmount = swapAmounts[swapAmounts.length - 1];
_repayInternal(path[1], vTokenAddress, swapAmount);
}

/**
* @notice repay a borrow from Venus market
* @param path the addresses of the underlying token
* @param vTokenAddress The address of the vToken contract for supplying assets.
* @param swapAmount the amount of tokens repay to Venus Market.
*/
function _repayInternal(address path, address vTokenAddress, uint256 swapAmount) internal {
TransferHelper.safeApprove(path, vTokenAddress, 0);
TransferHelper.safeApprove(path, vTokenAddress, swapAmount);
uint256 response = IVToken(vTokenAddress).repayBorrowBehalf(msg.sender, swapAmount);
if (response != 0) {
revert RepayError(msg.sender, vTokenAddress, response);
} else {
emit RepayOnBehalf(msg.sender, vTokenAddress, swapAmounts[1]);
emit RepayOnBehalf(msg.sender, vTokenAddress, swapAmount);
}
}

Expand Down Expand Up @@ -269,17 +280,34 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
// **** INTERNAL FUNCTIONS ****
// ****************************

// **** SWAP (supporting fee-on-transfer tokens) ****
// requires the initial amount to have already been sent to the first pair
function _swap(uint256[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint256 i; i < path.length - 1; ++i) {
function _swapSupportingFeeOnTransferTokens(
uint amountIn,
address[] memory path,
address _to
) internal virtual returns (uint256[] memory amounts) {
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0, ) = PancakeLibrary.sortTokens(input, output);
uint256 amountOut = amounts[i + 1];
(uint256 amount0Out, uint256 amount1Out) = input == token0
? (uint256(0), amountOut)
: (amountOut, uint256(0));
IPancakePair pair = IPancakePair(PancakeLibrary.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{
// scope to avoid stack too deep errors
(uint reserve0, uint reserve1, ) = pair.getReserves();
(uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
uint balance = IERC20(input).balanceOf(address(pair));
require(balance <= reserveInput, "subtraction overflow");
amountInput = balance - reserveInput;
amountOutput = PancakeLibrary.getAmountOut(amountInput, reserveInput, reserveOutput);
amounts[i + 1] = amountOutput;
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? PancakeLibrary.pairFor(factory, output, path[i + 2]) : _to;
IPancakePair(PancakeLibrary.pairFor(factory, input, output)).swap(amount0Out, amount1Out, to, new bytes(0));
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}

Expand All @@ -289,13 +317,12 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
address[] calldata path,
address to
) internal returns (uint256[] memory amounts) {
amounts = PancakeLibrary.getAmountsOut(factory, amountIn, path);
address pairAddress = PancakeLibrary.pairFor(factory, path[0], path[1]);
TransferHelper.safeTransferFrom(path[0], msg.sender, pairAddress, amountIn);
amounts = _swapSupportingFeeOnTransferTokens(amountIn, path, to);
if (amounts[amounts.length - 1] < amountOutMin) {
revert OutputAmountBelowMinimum(amounts[amounts.length - 1], amountOutMin);
}
address pairAddress = PancakeLibrary.pairFor(factory, path[0], path[1]);
TransferHelper.safeTransferFrom(path[0], msg.sender, pairAddress, amounts[0]);
_swap(amounts, path, to);
emit SwapTokensForTokens(msg.sender, path, amounts);
}

Expand All @@ -308,13 +335,13 @@ contract SwapRouter is Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, IPan
if (path[0] != wBNBAddress) {
revert WrongAddress(wBNBAddress, path[0]);
}
amounts = PancakeLibrary.getAmountsOut(factory, msg.value, path);
uint amountIn = msg.value;
IWBNB(wBNBAddress).deposit{ value: amountIn }();
assert(IWBNB(wBNBAddress).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amountIn));
amounts = _swapSupportingFeeOnTransferTokens(amountIn, path, to);
if (amounts[amounts.length - 1] < amountOutMin) {
revert OutputAmountBelowMinimum(amounts[amounts.length - 1], amountOutMin);
}
IWBNB(wBNBAddress).deposit{ value: amounts[0] }();
assert(IWBNB(wBNBAddress).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
emit SwapBnbForTokens(msg.sender, path, amounts);
}
}

0 comments on commit 9437a22

Please sign in to comment.