diff --git a/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol new file mode 100644 index 00000000..b148fe56 --- /dev/null +++ b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +// From version of 12/04/2021 on https://github.com/OpenZeppelin/openzeppelin-contracts/commit/555be63c909cc29617d828df62052f0b95147e50 +// Adapting syntax to 0.6.12 + +/** + * @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() public { + _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; + } +} diff --git a/contracts/protocol/tokenization/StaticAToken.sol b/contracts/protocol/tokenization/StaticAToken.sol index 41565590..8f789a5c 100644 --- a/contracts/protocol/tokenization/StaticAToken.sol +++ b/contracts/protocol/tokenization/StaticAToken.sol @@ -7,6 +7,7 @@ import {IStaticAToken} from '../../interfaces/IStaticAToken.sol'; import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; import {IAToken} from '../../interfaces/IAToken.sol'; import {ERC20} from '../../dependencies/openzeppelin/contracts/ERC20.sol'; +import {ReentrancyGuard} from '../../dependencies/openzeppelin/contracts/ReentrancyGuard.sol'; import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol'; import {WadRayMath} from '../../protocol/libraries/math/WadRayMath.sol'; @@ -17,7 +18,7 @@ import {WadRayMath} from '../../protocol/libraries/math/WadRayMath.sol'; * - Only supporting deposits and withdrawals * @author Aave **/ -contract StaticAToken is IStaticAToken, ERC20 { +contract StaticAToken is IStaticAToken, ReentrancyGuard, ERC20 { using SafeERC20 for IERC20; using WadRayMath for uint256; @@ -73,7 +74,7 @@ contract StaticAToken is IStaticAToken, ERC20 { uint256 amount, uint16 referralCode, bool fromUnderlying - ) external override returns (uint256) { + ) external override nonReentrant returns (uint256) { return _deposit(msg.sender, recipient, amount, referralCode, fromUnderlying); } @@ -91,7 +92,7 @@ contract StaticAToken is IStaticAToken, ERC20 { address recipient, uint256 amount, bool toUnderlying - ) external override returns (uint256, uint256) { + ) external override nonReentrant returns (uint256, uint256) { return _withdraw(msg.sender, recipient, amount, 0, toUnderlying); } @@ -109,7 +110,7 @@ contract StaticAToken is IStaticAToken, ERC20 { address recipient, uint256 amount, bool toUnderlying - ) external override returns (uint256, uint256) { + ) external override nonReentrant returns (uint256, uint256) { return _withdraw(msg.sender, recipient, 0, amount, toUnderlying); } @@ -177,7 +178,7 @@ contract StaticAToken is IStaticAToken, ERC20 { uint256 deadline, SignatureParams calldata sigParams, uint256 chainId - ) external override returns (uint256) { + ) external override nonReentrant returns (uint256) { require(depositor != address(0), 'INVALID_DEPOSITOR'); //solium-disable-next-line require(block.timestamp <= deadline, 'INVALID_EXPIRATION'); @@ -234,7 +235,7 @@ contract StaticAToken is IStaticAToken, ERC20 { uint256 deadline, SignatureParams calldata sigParams, uint256 chainId - ) external override returns (uint256, uint256) { + ) external override nonReentrant returns (uint256, uint256) { require(owner != address(0), 'INVALID_DEPOSITOR'); //solium-disable-next-line require(block.timestamp <= deadline, 'INVALID_EXPIRATION'); diff --git a/package.json b/package.json index b857b89a..b95a57ed 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "test-weth": "hardhat test test/__setup.spec.ts test/weth-gateway.spec.ts", "test-uniswap": "hardhat test test/__setup.spec.ts test/uniswapAdapters*.spec.ts", "test:main:check-list": "MAINNET_FORK=true TS_NODE_TRANSPILE_ONLY=1 hardhat test test/__setup.spec.ts test/mainnet/check-list.spec.ts", - "test:main:staticAToken": "MAINNET_FORK=true FORKING_BLOCK=12063148 TS_NODE_TRANSPILE_ONLY=1 hardhat test test/mainnet/static-atoken.spec.ts", + "test:main:staticAToken": "MAINNET_FORK=true FORKING_BLOCK=12225650 TS_NODE_TRANSPILE_ONLY=1 hardhat test test/mainnet/static-atoken.spec.ts", "dev:coverage": "buidler compile --force && buidler coverage --network coverage", "aave:evm:dev:migration": "npm run compile && hardhat aave:dev", "aave:docker:full:migration": "npm run compile && npm run hardhat:docker -- aave:mainnet",