From f8a5f1d417fb707cd0117551067af2ea08ed660d Mon Sep 17 00:00:00 2001
From: Steffel <2143646+steffenix@users.noreply.github.com>
Date: Tue, 6 Apr 2021 01:42:07 +0200
Subject: [PATCH] chore: update to solidity 0.8 (#244)

* feat: solidity 0.8

* chore: openzeppelin 4.0.0

* fix: update README.md

Co-authored-by: Just some guy <3859395+fubuloubu@users.noreply.github.com>

* fix: suggestions
Co-authored-by: Just some guy <3859395+fubuloubu@users.noreply.github.com>

fix: missed

Co-authored-by: Just some guy <3859395+fubuloubu@users.noreply.github.com>

* fix: fix unwanted replace

* fix: missed suggestions

Co-authored-by: Just some guy <3859395+fubuloubu@users.noreply.github.com>
---
 README.md                         |  4 ++--
 brownie-config.yaml               |  7 +++---
 contracts/BaseStrategy.sol        | 37 +++++++++++++---------------
 contracts/BaseWrapper.sol         | 40 +++++++++++++------------------
 contracts/test/AffiliateToken.sol | 23 +++++++++++-------
 contracts/test/TestGuestList.sol  |  5 ++--
 contracts/test/TestStrategy.sol   | 20 ++++++++--------
 contracts/test/Token.sol          | 30 ++++++++++++-----------
 contracts/yToken.sol              | 23 +++++++-----------
 9 files changed, 90 insertions(+), 99 deletions(-)

diff --git a/README.md b/README.md
index 27efe61e..8ced17d0 100644
--- a/README.md
+++ b/README.md
@@ -99,11 +99,11 @@ Any command `in code blocks` is meant to be executed from a Mac/Linux terminal o
     - If you're in Windows using WSL, type `code .` to launch VSCode
       - At this point install [Solidity Compiler](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity) - be sure to _Install in WSL_
       - Install [Vyper](https://marketplace.visualstudio.com/items?itemName=tintinweb.vscode-vyper) as well on WSL
-    - Open one of the .sol files, right click the code and click _Soldity: Change Workspace compiler version (Remote)_, Change to 0.6.12
+    - Open one of the .sol files, right click the code and click _Solidity: Change Workspace compiler version (Remote)_, Change to 0.8.3
       - Alternatively, go to File -> Preferences -> Settings
       - If you’re using WSL, go to the Remote [WSL] tab
       - Otherwise choose the Workspace tab
-        - Search for _Solidity_ and copy and paste _v0.6.12+commit.27d51765_ into the _Solidity: Compile Using Remote Version_ textbox
+        - Search for _Solidity_ and copy and paste _v0.8.3_ into the _Solidity: Compile Using Remote Version_ textbox
     - Set Black as the linter.
       - You'll see a toast notification the bottom right asking about linting, choose _black_
       - If you don't see this, just go to _File_ -> _Preferences_ -> _Settings_
diff --git a/brownie-config.yaml b/brownie-config.yaml
index ccb46535..e1af621b 100644
--- a/brownie-config.yaml
+++ b/brownie-config.yaml
@@ -6,20 +6,19 @@ autofetch_sources: true
 
 # require OpenZepplin Contracts
 dependencies:
-  - OpenZeppelin/openzeppelin-contracts@3.1.0
+  - OpenZeppelin/openzeppelin-contracts@4.0.0
 
 # path remapping to support OpenZepplin imports with NPM-style path
 compiler:
   solc:
-    version: 0.6.12
+    version: 0.8.3
     remappings:
-      - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.1.0"
+      - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.0.0"
 
 reports:
   exclude_paths:
     - contracts/test/Token.sol
     - contracts/test/TestGuestList.sol
   exclude_contracts:
-    - SafeMath
     - SafeERC20
     - Address
diff --git a/contracts/BaseStrategy.sol b/contracts/BaseStrategy.sol
index d7307c1d..d2cf277b 100644
--- a/contracts/BaseStrategy.sol
+++ b/contracts/BaseStrategy.sol
@@ -1,10 +1,9 @@
 // SPDX-License-Identifier: GPL-3.0
-pragma solidity >=0.6.0 <0.7.0;
-pragma experimental ABIEncoderV2;
+pragma solidity >=0.8.0 <0.9.0;
 
 import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
-import "@openzeppelin/contracts/math/SafeMath.sol";
+import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
+import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
 
 struct StrategyParams {
     uint256 performanceFee;
@@ -176,7 +175,6 @@ interface StrategyAPI {
  *  `harvest()`, and `harvestTrigger()` for further details.
  */
 abstract contract BaseStrategy {
-    using SafeMath for uint256;
     using SafeERC20 for IERC20;
     string public metadataURI;
 
@@ -295,7 +293,7 @@ abstract contract BaseStrategy {
         _;
     }
 
-    constructor(address _vault) public {
+    constructor(address _vault) {
         _initialize(_vault, msg.sender, msg.sender, msg.sender);
     }
 
@@ -316,18 +314,17 @@ abstract contract BaseStrategy {
 
         vault = VaultAPI(_vault);
         want = IERC20(vault.token());
-        want.safeApprove(_vault, uint256(-1)); // Give Vault unlimited access (might save gas)
+        want.safeApprove(_vault, type(uint256).max); // Give Vault unlimited access (might save gas)
         strategist = _strategist;
         rewards = _rewards;
         keeper = _keeper;
-
         // initialize variables
         minReportDelay = 0;
         maxReportDelay = 86400;
         profitFactor = 100;
         debtThreshold = 0;
 
-        vault.approve(rewards, uint256(-1)); // Allow rewards to be pulled
+        vault.approve(rewards, type(uint256).max); // Allow rewards to be pulled
     }
 
     /**
@@ -374,7 +371,7 @@ abstract contract BaseStrategy {
         require(_rewards != address(0));
         vault.approve(rewards, 0);
         rewards = _rewards;
-        vault.approve(rewards, uint256(-1));
+        vault.approve(rewards, type(uint256).max);
         emit UpdatedRewards(_rewards);
     }
 
@@ -656,10 +653,10 @@ abstract contract BaseStrategy {
         if (params.activation == 0) return false;
 
         // Should not trigger if we haven't waited long enough since previous harvest
-        if (block.timestamp.sub(params.lastReport) < minReportDelay) return false;
+        if ((block.timestamp - params.lastReport) < minReportDelay) return false;
 
         // Should trigger if hasn't been called in a while
-        if (block.timestamp.sub(params.lastReport) >= maxReportDelay) return true;
+        if ((block.timestamp - params.lastReport) >= maxReportDelay) return true;
 
         // If some amount is owed, pay it back
         // NOTE: Since debt is based on deposits, it makes sense to guard against large
@@ -672,15 +669,15 @@ abstract contract BaseStrategy {
         // Check for profits and losses
         uint256 total = estimatedTotalAssets();
         // Trigger if we have a loss to report
-        if (total.add(debtThreshold) < params.totalDebt) return true;
+        if ((total + debtThreshold) < params.totalDebt) return true;
 
         uint256 profit = 0;
-        if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit!
+        if (total > params.totalDebt) profit = total - params.totalDebt; // We've earned a profit!
 
         // Otherwise, only trigger if it "makes sense" economically (gas cost
         // is <N% of value moved)
         uint256 credit = vault.creditAvailable();
-        return (profitFactor.mul(callCost) < credit.add(profit));
+        return ((profitFactor * callCost) < (credit + profit));
     }
 
     /**
@@ -712,7 +709,7 @@ abstract contract BaseStrategy {
             (debtPayment, loss) = liquidatePosition(totalAssets > debtOutstanding ? totalAssets : debtOutstanding);
             // NOTE: take up any remainder here as profit
             if (debtPayment > debtOutstanding) {
-                profit = debtPayment.sub(debtOutstanding);
+                profit = debtPayment - debtOutstanding;
                 debtPayment = debtOutstanding;
             }
         } else {
@@ -745,7 +742,7 @@ abstract contract BaseStrategy {
         uint256 amountFreed;
         (amountFreed, _loss) = liquidatePosition(_amountNeeded);
         // Send it directly back (NOTE: Using `msg.sender` saves some gas here)
-        want.safeTransfer(msg.sender, amountFreed);
+        SafeERC20.safeTransfer(want, msg.sender, amountFreed);
         // NOTE: Reinvest anything leftover on next `tend`/`harvest`
     }
 
@@ -769,7 +766,7 @@ abstract contract BaseStrategy {
         require(msg.sender == address(vault) || msg.sender == governance());
         require(BaseStrategy(_newStrategy).vault() == vault);
         prepareMigration(_newStrategy);
-        want.safeTransfer(_newStrategy, want.balanceOf(address(this)));
+        SafeERC20.safeTransfer(want, _newStrategy, want.balanceOf(address(this)));
     }
 
     /**
@@ -832,14 +829,14 @@ abstract contract BaseStrategy {
         address[] memory _protectedTokens = protectedTokens();
         for (uint256 i; i < _protectedTokens.length; i++) require(_token != _protectedTokens[i], "!protected");
 
-        IERC20(_token).safeTransfer(governance(), IERC20(_token).balanceOf(address(this)));
+        SafeERC20.safeTransfer(IERC20(_token), governance(), IERC20(_token).balanceOf(address(this)));
     }
 }
 
 abstract contract BaseStrategyInitializable is BaseStrategy {
     event Cloned(address indexed clone);
 
-    constructor(address _vault) public BaseStrategy(_vault) {}
+    constructor(address _vault) BaseStrategy(_vault) {}
 
     function initialize(
         address _vault,
diff --git a/contracts/BaseWrapper.sol b/contracts/BaseWrapper.sol
index 1c2d7951..0ff140a7 100644
--- a/contracts/BaseWrapper.sol
+++ b/contracts/BaseWrapper.sol
@@ -1,11 +1,9 @@
 // SPDX-License-Identifier: GPL-3.0
-pragma solidity ^0.6.12;
-pragma experimental ABIEncoderV2;
+pragma solidity >=0.8.0 <0.9.0;
 
 import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
-import {Math} from "@openzeppelin/contracts/math/Math.sol";
-import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
+import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
+import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
 
 import {VaultAPI} from "./BaseStrategy.sol";
 
@@ -21,7 +19,6 @@ interface RegistryAPI {
 
 abstract contract BaseWrapper {
     using Math for uint256;
-    using SafeMath for uint256;
     using SafeERC20 for IERC20;
 
     IERC20 public token;
@@ -41,7 +38,7 @@ abstract contract BaseWrapper {
     // VaultsAPI.depositLimit is unlimited
     uint256 constant UNCAPPED_DEPOSITS = type(uint256).max;
 
-    constructor(address _token, address _registry) public {
+    constructor(address _token, address _registry) {
         // Recommended to use a token with a `Registry.latestVault(_token) != address(0)`
         token = IERC20(_token);
         // Recommended to use `v2.registry.ychad.eth`
@@ -96,7 +93,7 @@ abstract contract BaseWrapper {
         VaultAPI[] memory vaults = allVaults();
 
         for (uint256 id = 0; id < vaults.length; id++) {
-            balance = balance.add(vaults[id].balanceOf(account).mul(vaults[id].pricePerShare()).div(10**uint256(vaults[id].decimals())));
+            balance += (vaults[id].balanceOf(account) * vaults[id].pricePerShare()) / 10**uint256(vaults[id].decimals());
         }
     }
 
@@ -104,7 +101,7 @@ abstract contract BaseWrapper {
         VaultAPI[] memory vaults = allVaults();
 
         for (uint256 id = 0; id < vaults.length; id++) {
-            assets = assets.add(vaults[id].totalAssets());
+            assets += vaults[id].totalAssets();
         }
     }
 
@@ -118,9 +115,9 @@ abstract contract BaseWrapper {
 
         if (pullFunds) {
             if (amount != DEPOSIT_EVERYTHING) {
-                token.safeTransferFrom(depositor, address(this), amount);
+                SafeERC20.safeTransferFrom(token, depositor, address(this), amount);
             } else {
-                token.safeTransferFrom(depositor, address(this), token.balanceOf(depositor));
+                SafeERC20.safeTransferFrom(token, depositor, address(this), token.balanceOf(depositor));
             }
         }
 
@@ -143,7 +140,7 @@ abstract contract BaseWrapper {
         }
 
         uint256 afterBal = token.balanceOf(address(this));
-        deposited = beforeBal.sub(afterBal);
+        deposited = beforeBal - afterBal;
         // `receiver` now has shares of `_bestVault` as balance, converted to `token` here
         // Issue a refund if not everything was deposited
         if (depositor != address(this) && afterBal > 0) token.safeTransfer(depositor, afterBal);
@@ -191,21 +188,18 @@ abstract contract BaseWrapper {
 
                 if (amount != WITHDRAW_EVERYTHING) {
                     // Compute amount to withdraw fully to satisfy the request
-                    uint256 estimatedShares = amount
-                        .sub(withdrawn) // NOTE: Changes every iteration
-                        .mul(10**uint256(vaults[id].decimals()))
-                        .div(vaults[id].pricePerShare()); // NOTE: Every Vault is different
+                    uint256 estimatedShares = ((amount - withdrawn) * 10**uint256(vaults[id].decimals())) / vaults[id].pricePerShare();
 
                     // Limit amount to withdraw to the maximum made available to this contract
                     // NOTE: Avoid corner case where `estimatedShares` isn't precise enough
                     // NOTE: If `0 < estimatedShares < 1` but `availableShares > 1`, this will withdraw more than necessary
                     if (estimatedShares > 0 && estimatedShares < availableShares) {
-                        withdrawn = withdrawn.add(vaults[id].withdraw(estimatedShares));
+                        withdrawn = withdrawn + (vaults[id].withdraw(estimatedShares));
                     } else {
-                        withdrawn = withdrawn.add(vaults[id].withdraw(availableShares));
+                        withdrawn = withdrawn + (vaults[id].withdraw(availableShares));
                     }
                 } else {
-                    withdrawn = withdrawn.add(vaults[id].withdraw());
+                    withdrawn += vaults[id].withdraw();
                 }
 
                 // Check if we have fully satisfied the request
@@ -218,11 +212,11 @@ abstract contract BaseWrapper {
         // NOTE: Invariant is `withdrawn <= amount`
         if (withdrawn > amount) {
             // Don't forget to approve the deposit
-            if (token.allowance(address(this), address(_bestVault)) < withdrawn.sub(amount)) {
+            if (token.allowance(address(this), address(_bestVault)) < (withdrawn - amount)) {
                 token.safeApprove(address(_bestVault), UNLIMITED_APPROVAL); // Vaults are trusted
             }
 
-            _bestVault.deposit(withdrawn.sub(amount), sender);
+            _bestVault.deposit(withdrawn - amount, sender);
             withdrawn = amount;
         }
 
@@ -254,7 +248,7 @@ abstract contract BaseWrapper {
         uint256 _amount = amount;
         if (_depositLimit < UNCAPPED_DEPOSITS && _amount < WITHDRAW_EVERYTHING) {
             // Can only deposit up to this amount
-            uint256 _depositLeft = _depositLimit.sub(_totalAssets);
+            uint256 _depositLeft = _depositLimit - _totalAssets;
             if (_amount > _depositLeft) _amount = _depositLeft;
         }
 
@@ -268,7 +262,7 @@ abstract contract BaseWrapper {
             // NOTE: Due to the precision loss of certain calculations, there is a small inefficency
             //       on how migrations are calculated, and this could lead to a DoS issue. Hence, this
             //       value is made to be configurable to allow the user to specify how much is acceptable
-            require(withdrawn.sub(migrated) <= maxMigrationLoss);
+            require((withdrawn - migrated) <= maxMigrationLoss);
         } // else: nothing to migrate! (not a failure)
     }
 }
diff --git a/contracts/test/AffiliateToken.sol b/contracts/test/AffiliateToken.sol
index 8ec60621..a3a7400a 100644
--- a/contracts/test/AffiliateToken.sol
+++ b/contracts/test/AffiliateToken.sol
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: MIT
-pragma solidity ^0.6.12;
+pragma solidity 0.8.3;
 
 import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
 
@@ -19,6 +19,7 @@ contract AffiliateToken is ERC20, BaseWrapper {
     address public affiliate;
 
     address public pendingAffiliate;
+    uint8 private immutable _decimals;
 
     modifier onlyAffiliate() {
         require(msg.sender == affiliate);
@@ -30,10 +31,10 @@ contract AffiliateToken is ERC20, BaseWrapper {
         address _registry,
         string memory name,
         string memory symbol
-    ) public BaseWrapper(_token, _registry) ERC20(name, symbol) {
+    ) BaseWrapper(_token, _registry) ERC20(name, symbol) {
         DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes("1")), _getChainId(), address(this)));
         affiliate = msg.sender;
-        _setupDecimals(uint8(ERC20(address(token)).decimals()));
+        _decimals = uint8(ERC20(address(token)).decimals());
     }
 
     function _getChainId() internal view returns (uint256) {
@@ -57,34 +58,34 @@ contract AffiliateToken is ERC20, BaseWrapper {
         uint256 totalShares = totalSupply();
 
         if (totalShares > 0) {
-            return totalVaultBalance(address(this)).mul(numShares).div(totalShares);
+            return (totalVaultBalance(address(this)) * numShares) / totalShares;
         } else {
             return numShares;
         }
     }
 
     function pricePerShare() external view returns (uint256) {
-        return totalVaultBalance(address(this)).mul(10**uint256(decimals())).div(totalSupply());
+        return (totalVaultBalance(address(this)) * (10**uint256(decimals()))) / totalSupply();
     }
 
     function _sharesForValue(uint256 amount) internal view returns (uint256) {
         // total wrapper assets before deposit (assumes deposit already occured)
-        uint256 totalWrapperAssets = totalVaultBalance(address(this)).sub(amount);
+        uint256 totalWrapperAssets = totalVaultBalance(address(this)) - amount;
 
         if (totalWrapperAssets > 0) {
-            return totalSupply().mul(amount).div(totalWrapperAssets);
+            return (totalSupply() * amount) / totalWrapperAssets;
         } else {
             return amount;
         }
     }
 
     function deposit() external returns (uint256) {
-        return deposit(uint256(-1)); // Deposit everything
+        return deposit(type(uint256).max); // Deposit everything
     }
 
     function deposit(uint256 amount) public returns (uint256 deposited) {
         deposited = _deposit(msg.sender, address(this), amount, true); // `true` = pull from `msg.sender`
-        uint256 shares = _sharesForValue(deposited);  // NOTE: Must be calculated after deposit is handled
+        uint256 shares = _sharesForValue(deposited); // NOTE: Must be calculated after deposit is handled
         _mint(msg.sender, shares);
     }
 
@@ -139,4 +140,8 @@ contract AffiliateToken is ERC20, BaseWrapper {
 
         _approve(owner, spender, amount);
     }
+
+    function decimals() public virtual override view returns (uint8) {
+        return _decimals;
+    }
 }
diff --git a/contracts/test/TestGuestList.sol b/contracts/test/TestGuestList.sol
index cc5d9d2c..ff9acecf 100644
--- a/contracts/test/TestGuestList.sol
+++ b/contracts/test/TestGuestList.sol
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-3.0
-pragma solidity >=0.6.0 <0.7.0;
-pragma experimental ABIEncoderV2;
+pragma solidity 0.8.3;
 
 /**
  * @notice A basic guest list contract for testing.
@@ -18,7 +17,7 @@ contract TestGuestList {
      * @dev Note that since this is just for testing, you're unable to change
      * `bouncer`.
      */
-    constructor() public {
+    constructor() {
         bouncer = msg.sender;
     }
 
diff --git a/contracts/test/TestStrategy.sol b/contracts/test/TestStrategy.sol
index ac6dfa65..ffaf1486 100644
--- a/contracts/test/TestStrategy.sol
+++ b/contracts/test/TestStrategy.sol
@@ -1,9 +1,9 @@
 // SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.6.12;
-pragma experimental ABIEncoderV2;
+pragma solidity 0.8.3;
 
 import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
 import {BaseStrategyInitializable, StrategyParams, VaultAPI} from "../BaseStrategy.sol";
+import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
 
 /*
  * This Strategy serves as both a mock Strategy for testing, and an example
@@ -19,7 +19,7 @@ contract TestStrategy is BaseStrategyInitializable {
     // to test `BaseStrategy.protectedTokens()`
     address public constant protectedToken = address(0xbad);
 
-    constructor(address _vault) public BaseStrategyInitializable(_vault) {}
+    constructor(address _vault) BaseStrategyInitializable(_vault) {}
 
     function name() external override view returns (string memory) {
         return string(abi.encodePacked("TestStrategy ", apiVersion()));
@@ -40,7 +40,7 @@ contract TestStrategy is BaseStrategyInitializable {
 
     // NOTE: This is a test-only function to simulate losses
     function _takeFunds(uint256 amount) public {
-        want.safeTransfer(msg.sender, amount);
+        SafeERC20.safeTransfer(want, msg.sender, amount);
     }
 
     // NOTE: This is a test-only function to enable reentrancy on withdraw
@@ -76,17 +76,17 @@ contract TestStrategy is BaseStrategyInitializable {
         uint256 totalDebt = vault.strategies(address(this)).totalDebt;
         if (totalAssets > _debtOutstanding) {
             _debtPayment = _debtOutstanding;
-            totalAssets = totalAssets.sub(_debtOutstanding);
+            totalAssets = totalAssets - _debtOutstanding;
         } else {
             _debtPayment = totalAssets;
             totalAssets = 0;
         }
-        totalDebt = totalDebt.sub(_debtPayment);
+        totalDebt = totalDebt - _debtPayment;
 
         if (totalAssets > totalDebt) {
-            _profit = totalAssets.sub(totalDebt);
+            _profit = totalAssets - totalDebt;
         } else {
-            _loss = totalDebt.sub(totalAssets);
+            _loss = totalDebt - totalAssets;
         }
     }
 
@@ -105,11 +105,11 @@ contract TestStrategy is BaseStrategyInitializable {
         uint256 totalAssets = want.balanceOf(address(this));
         if (_amountNeeded > totalAssets) {
             _liquidatedAmount = totalAssets;
-            _loss = _amountNeeded.sub(totalAssets);
+            _loss = _amountNeeded - totalAssets;
         } else {
             // NOTE: Just in case something was stolen from this contract
             if (totalDebt > totalAssets) {
-                _loss = totalDebt.sub(totalAssets);
+                _loss = totalDebt - totalAssets;
                 if (_loss > _amountNeeded) _loss = _amountNeeded;
             }
             _liquidatedAmount = _amountNeeded;
diff --git a/contracts/test/Token.sol b/contracts/test/Token.sol
index 547dff8d..43c7dc46 100644
--- a/contracts/test/Token.sol
+++ b/contracts/test/Token.sol
@@ -1,15 +1,15 @@
 // SPDX-License-Identifier: MIT
-pragma solidity ^0.6.12;
+pragma solidity 0.8.3;
 
-import "@openzeppelin/contracts/math/SafeMath.sol";
 import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
 
 contract Token is ERC20 {
     mapping(address => bool) public _blocked;
+    uint8 private immutable _decimals;
 
-    constructor(uint8 _decimals) public ERC20("yearn.finance test token", "TEST") {
-        _setupDecimals(_decimals);
-        _mint(msg.sender, 30000 * 10**uint256(_decimals));
+    constructor(uint8 decimals_) ERC20("yearn.finance test token", "TEST") {
+        _decimals = decimals_;
+        _mint(msg.sender, 30000 * 10**uint256(decimals_));
     }
 
     function _setBlocked(address user, bool value) public virtual {
@@ -24,11 +24,13 @@ contract Token is ERC20 {
         require(!_blocked[to], "Token transfer refused. Receiver is on blacklist");
         super._beforeTokenTransfer(from, to, amount);
     }
+
+    function decimals() public virtual override view returns (uint8) {
+        return _decimals;
+    }
 }
 
 contract TokenNoReturn {
-    using SafeMath for uint256;
-
     string public name;
     string public symbol;
     uint8 public decimals;
@@ -42,7 +44,7 @@ contract TokenNoReturn {
 
     mapping(address => bool) public _blocked;
 
-    constructor(uint8 _decimals) public {
+    constructor(uint8 _decimals) {
         name = "yearn.finance test token";
         symbol = "TEST";
         decimals = _decimals;
@@ -56,8 +58,8 @@ contract TokenNoReturn {
 
     function transfer(address receiver, uint256 amount) external {
         require(!_blocked[receiver], "Token transfer refused. Receiver is on blacklist");
-        balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);
-        balanceOf[receiver] = balanceOf[receiver].add(amount);
+        balanceOf[msg.sender] = balanceOf[msg.sender] - amount;
+        balanceOf[receiver] = balanceOf[receiver] + amount;
         emit Transfer(msg.sender, receiver, amount);
     }
 
@@ -72,15 +74,15 @@ contract TokenNoReturn {
         uint256 amount
     ) external {
         require(!_blocked[receiver], "Token transfer refused. Receiver is on blacklist");
-        allowance[sender][msg.sender] = allowance[sender][msg.sender].sub(amount);
-        balanceOf[sender] = balanceOf[sender].sub(amount);
-        balanceOf[receiver] = balanceOf[receiver].add(amount);
+        allowance[sender][msg.sender] = allowance[sender][msg.sender] - amount;
+        balanceOf[sender] = balanceOf[sender] - amount;
+        balanceOf[receiver] = balanceOf[receiver] + amount;
         emit Transfer(sender, receiver, amount);
     }
 }
 
 contract TokenFalseReturn is Token {
-    constructor(uint8 _decimals) public Token(_decimals) {}
+    constructor(uint8 _decimals) Token(_decimals) {}
 
     function transfer(address receiver, uint256 amount) public virtual override returns (bool) {
         return false;
diff --git a/contracts/yToken.sol b/contracts/yToken.sol
index 87afeaea..0da68151 100644
--- a/contracts/yToken.sol
+++ b/contracts/yToken.sol
@@ -1,20 +1,15 @@
 // SPDX-License-Identifier: GPL-3.0
-pragma solidity ^0.6.12;
-pragma experimental ABIEncoderV2;
+pragma solidity 0.8.3;
 
 import {Address} from "@openzeppelin/contracts/utils/Address.sol";
 import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
-import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
-
+import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
 import {VaultAPI, BaseWrapper} from "./BaseWrapper.sol";
 
 contract yToken is IERC20, BaseWrapper {
-    using SafeMath for uint256;
-
     mapping(address => mapping(address => uint256)) public override allowance;
 
-    constructor(address _token, address _registry) public BaseWrapper(_token, _registry) {}
+    constructor(address _token, address _registry) BaseWrapper(_token, _registry) {}
 
     function name() external view returns (string memory) {
         VaultAPI _bestVault = bestVault();
@@ -77,17 +72,17 @@ contract yToken is IERC20, BaseWrapper {
         uint256 amount
     ) public virtual override returns (bool) {
         _transfer(sender, receiver, amount);
-        _approve(sender, msg.sender, allowance[sender][msg.sender].sub(amount));
+        _approve(sender, msg.sender, allowance[sender][msg.sender] - amount);
         return true;
     }
 
     function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
-        _approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
+        _approve(msg.sender, spender, allowance[msg.sender][spender] + addedValue);
         return true;
     }
 
     function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
-        _approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue));
+        _approve(msg.sender, spender, allowance[msg.sender][spender] - subtractedValue);
         return true;
     }
 
@@ -106,7 +101,7 @@ contract yToken is IERC20, BaseWrapper {
     ) internal {
         require(vaults.length == signatures.length);
         for (uint256 i = 0; i < vaults.length; i++) {
-            require(vaults[i].permit(user, address(this), uint256(-1), 0, signatures[i]));
+            require(vaults[i].permit(user, address(this), type(uint256).max, 0, signatures[i]));
         }
     }
 
@@ -167,7 +162,7 @@ interface IWETH {
 contract yWETH is ReentrancyGuard, yToken {
     using Address for address payable;
 
-    constructor(address _weth, address _registry) public yToken(_weth, _registry) {}
+    constructor(address _weth, address _registry) yToken(_weth, _registry) {}
 
     function depositETH() public payable returns (uint256) {
         uint256 amount = msg.value;
@@ -184,7 +179,7 @@ contract yWETH is ReentrancyGuard, yToken {
         // NOTE: `BaseWrapper.token` is WETH
         IWETH(address(token)).withdraw(withdrawn);
         // NOTE: Any unintentionally
-        msg.sender.sendValue(address(this).balance);
+        payable(msg.sender).sendValue(address(this).balance);
     }
 
     receive() external payable {