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

fix: Transfer excess back and reset allowance #193

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions contracts/adapters/paraswap/BaseParaSwapBuyAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
* @param maxAmountToSwap Max amount to be swapped
* @param amountToReceive Amount to be received from the swap
* @return amountSold The amount sold during the swap
* @return amountBought The amount bought during the swap
*/
function _buyOnParaSwap(
uint256 toAmountOffset,
Expand All @@ -47,7 +48,7 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
IERC20Detailed assetToSwapTo,
uint256 maxAmountToSwap,
uint256 amountToReceive
) internal returns (uint256 amountSold) {
) internal returns (uint256 amountSold, uint256 amountBought) {
(bytes memory buyCalldata, IParaSwapAugustus augustus) = abi.decode(
paraswapData,
(bytes, IParaSwapAugustus)
Expand Down Expand Up @@ -75,7 +76,6 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
uint256 balanceBeforeAssetTo = assetToSwapTo.balanceOf(address(this));

address tokenTransferProxy = augustus.getTokenTransferProxy();
assetToSwapFrom.safeApprove(tokenTransferProxy, 0);
assetToSwapFrom.safeApprove(tokenTransferProxy, maxAmountToSwap);

if (toAmountOffset != 0) {
Expand All @@ -101,12 +101,15 @@ abstract contract BaseParaSwapBuyAdapter is BaseParaSwapAdapter {
}
}

// Reset allowance
assetToSwapFrom.safeApprove(tokenTransferProxy, 0);

uint256 balanceAfterAssetFrom = assetToSwapFrom.balanceOf(address(this));
amountSold = balanceBeforeAssetFrom - balanceAfterAssetFrom;
require(amountSold <= maxAmountToSwap, 'WRONG_BALANCE_AFTER_SWAP');
uint256 amountReceived = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo);
require(amountReceived >= amountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED');
amountBought = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo);
require(amountBought >= amountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED');

emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountReceived);
emit Bought(address(assetToSwapFrom), address(assetToSwapTo), amountSold, amountBought);
}
}
1 change: 1 addition & 0 deletions contracts/adapters/paraswap/BaseParaSwapSellAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter {
revert(0, returndatasize())
}
}

require(
assetToSwapFrom.balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap,
'WRONG_BALANCE_AFTER_SWAP'
Expand Down
26 changes: 21 additions & 5 deletions contracts/adapters/paraswap/ParaSwapRepayAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
// Pull aTokens from user
_pullATokenAndWithdraw(address(collateralAsset), msg.sender, collateralAmount, permitSignature);
//buy debt asset using collateral asset
uint256 amountSold = _buyOnParaSwap(
(uint256 amountSold, uint256 amountBought) = _buyOnParaSwap(
buyAllBalanceOffset,
paraswapData,
collateralAsset,
Expand All @@ -127,15 +127,23 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {

//deposit collateral back in the pool, if left after the swap(buy)
if (collateralBalanceLeft > 0) {
IERC20(collateralAsset).safeApprove(address(POOL), 0);
IERC20(collateralAsset).safeApprove(address(POOL), collateralBalanceLeft);
POOL.deposit(address(collateralAsset), collateralBalanceLeft, msg.sender, 0);
IERC20(collateralAsset).safeApprove(address(POOL), 0);
}

// Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix
IERC20(debtAsset).safeApprove(address(POOL), 0);
IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount);
POOL.repay(address(debtAsset), debtRepayAmount, debtRateMode, msg.sender);
IERC20(debtAsset).safeApprove(address(POOL), 0);

{
//transfer excess of debtAsset back to the user, if any
uint256 debtAssetExcess = amountBought - debtRepayAmount;
if (debtAssetExcess > 0) {
IERC20(debtAsset).safeTransfer(msg.sender, debtAssetExcess);
}
}
}

/**
Expand Down Expand Up @@ -170,7 +178,7 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
initiator
);

uint256 amountSold = _buyOnParaSwap(
(uint256 amountSold, uint256 amountBought) = _buyOnParaSwap(
buyAllBalanceOffset,
paraswapData,
collateralAsset,
Expand All @@ -180,9 +188,9 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
);

// Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
IERC20(debtAsset).safeApprove(address(POOL), 0);
IERC20(debtAsset).safeApprove(address(POOL), debtRepayAmount);
POOL.repay(address(debtAsset), debtRepayAmount, rateMode, initiator);
IERC20(debtAsset).safeApprove(address(POOL), 0);

uint256 neededForFlashLoanRepay = amountSold.add(premium);

Expand All @@ -194,6 +202,14 @@ contract ParaSwapRepayAdapter is BaseParaSwapBuyAdapter, ReentrancyGuard {
permitSignature
);

{
//transfer excess of debtAsset back to the user, if any
uint256 debtAssetExcess = amountBought - debtRepayAmount;
if (debtAssetExcess > 0) {
IERC20(debtAsset).safeTransfer(initiator, debtAssetExcess);
}
}

// Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
IERC20(collateralAsset).safeApprove(address(POOL), 0);
IERC20(collateralAsset).safeApprove(address(POOL), collateralAmount.add(premium));
Expand Down
34 changes: 28 additions & 6 deletions contracts/mocks/swap/MockParaSwapAugustus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
uint256 _expectedToAmountMax;
uint256 _expectedToAmountMin;

uint256 _excessFromAmount;
uint256 _excessToAmount;

constructor() {
TOKEN_TRANSFER_PROXY = new MockParaSwapTokenTransferProxy();
}
Expand Down Expand Up @@ -58,6 +61,11 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
_expectedToAmountMax = toAmountMax;
}

function expectExcess(uint256 excessFrom, uint256 excessTo) external {
_excessFromAmount = excessFrom;
_excessToAmount = excessTo;
}

function swap(
address fromToken,
address toToken,
Expand All @@ -72,10 +80,17 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
'From amount out of range'
);
require(_receivedAmount >= toAmount, 'Received amount of tokens are less than expected');
TOKEN_TRANSFER_PROXY.transferFrom(fromToken, msg.sender, address(this), fromAmount);
MintableERC20(toToken).mint(_receivedAmount);
IERC20(toToken).transfer(msg.sender, _receivedAmount);
TOKEN_TRANSFER_PROXY.transferFrom(
fromToken,
msg.sender,
address(this),
fromAmount - _excessFromAmount
);
MintableERC20(toToken).mint(_receivedAmount + _excessToAmount);
IERC20(toToken).transfer(msg.sender, _receivedAmount + _excessToAmount);
_expectingSwap = false;
_excessFromAmount = 0;
_excessToAmount = 0;
return _receivedAmount;
}

Expand All @@ -93,10 +108,17 @@ contract MockParaSwapAugustus is IParaSwapAugustus {
'To amount out of range'
);
require(_fromAmount <= fromAmount, 'From amount of tokens are higher than expected');
TOKEN_TRANSFER_PROXY.transferFrom(fromToken, msg.sender, address(this), _fromAmount);
MintableERC20(toToken).mint(toAmount);
IERC20(toToken).transfer(msg.sender, toAmount);
TOKEN_TRANSFER_PROXY.transferFrom(
fromToken,
msg.sender,
address(this),
_fromAmount - _excessFromAmount
);
MintableERC20(toToken).mint(toAmount + _excessToAmount);
IERC20(toToken).transfer(msg.sender, toAmount + _excessToAmount);
_expectingSwap = false;
_excessFromAmount = 0;
_excessToAmount = 0;
return fromAmount;
}
}
Loading
Loading