From 9d1cb50d769adb2b584f18d1c82aa2bf7bf76668 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 17:36:41 +0100 Subject: [PATCH] Add reentrancy guard to adapter Fixes MixBytes Warning 2. --- .../adapters/ParaSwapLiquiditySwapAdapter.sol | 7 ++- .../contracts/ReentrancyGuard.sol | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index 338fa09e..c5ff6305 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -7,13 +7,14 @@ import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddresses import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol'; import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; +import {ReentrancyGuard} from '../dependencies/openzeppelin/contracts/ReentrancyGuard.sol'; /** * @title ParaSwapLiquiditySwapAdapter * @notice Adapter to swap liquidity using ParaSwap. * @author Jason Raymond Bell */ -contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { +contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter, ReentrancyGuard { constructor( ILendingPoolAddressesProvider addressesProvider ) public BaseParaSwapSellAdapter(addressesProvider) { @@ -42,7 +43,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { uint256[] calldata premiums, address initiator, bytes calldata params - ) external override returns (bool) { + ) external override nonReentrant returns (bool) { require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL'); require( assets.length == 1 && amounts.length == 1 && premiums.length == 1, @@ -107,7 +108,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { bytes calldata swapCalldata, IParaSwapAugustus augustus, PermitSignature calldata permitParams - ) external { + ) external nonReentrant { IERC20WithPermit aToken = IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress); diff --git a/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol new file mode 100644 index 00000000..24c90c32 --- /dev/null +++ b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () internal { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +}