This is a summary with vulnerabilites of medium impact. A complete report can be found here. Vulnerabilities of high impact could not be found.
The complete report can be recreated by running yp_sa.sh. Make sure to have git, slither-analyzer and solc-select preinstalled.
- unused-return-yield-utils-v2 (1 results) (Impact: Medium)
- reentrancy-no-eth-I-yield-utils-v2 (7 results) (Impact: Medium)
- mapping-deletion-yield-utils-v2 (1 results) (Impact: Medium)
- uninitialized-local-yield-utils-v2 (2 results) (Impact: Medium)
- divide-before-multiply-yield-utils-v2 (1 results) (Impact: Medium)
- reentrancy-no-eth-II-yield-utils-v2 (7 results) (Impact: Medium)
- write-after-write-vault-v2 (1 results) (Impact: Medium)
- divide-before-multiply-vault-v2 (8 results) (Impact: Medium)
- erc20-interface-vault-v2 (3 results) (Impact: Medium)
Ensure that all the return values of the function calls are used.
Impact: Medium Confidence: Medium Smart contract under scope: https://github.com/yieldprotocol/yield-utils-v2/tree/main/lib/forge-std/lib/ds-test/demo/demo.sol
- ID-0 DemoTest.test_trace() ignores return value by this.echo(string 1,string 2)
yield-utils-v2/lib/forge-std/lib/ds-test/demo/demo.sol#L43-L45
Apply the check-effects-interactions pattern.
Impact: Medium Confidence: Medium Smart contract under scope: https://github.com/yieldprotocol/yield-utils-v2/tree/main/src/token/ERC20Rewards.sol
- ID-0
Reentrancy in ERC20Rewards._updateRewardsPerToken():
External calls:
- rewardsPerToken_.accumulated = (rewardsPerToken_.accumulated + 1e18 * unaccountedTime * rewardsPerToken_.rate / totalSupply_).u128() State variables written after the call(s):
- rewardsPerToken = rewardsPerToken_ ERC20Rewards.rewardsPerToken can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewardsPerToken
- ERC20Rewards.setRewards(uint32,uint32,uint96)
yield-utils-v2/src/token/ERC20Rewards.sol#L104-L124
- ID-1 Reentrancy in ERC20Rewards._updateUserRewards(address): External calls:
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- rewards[user] = userRewards_ ERC20Rewards.rewards can be used in cross function reentrancies:
- ERC20Rewards._claim(address,address)
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewards
yield-utils-v2/src/token/ERC20Rewards.sol#L128-L139
- ID-2 Reentrancy in ERC20Rewards.setRewards(uint32,uint32,uint96): External calls:
- _updateRewardsPerToken()
- rewardsPerToken_.accumulated = (rewardsPerToken_.accumulated + 1e18 * unaccountedTime * rewardsPerToken_.rate / totalSupply_).u128() State variables written after the call(s):
- rewardsPerToken.lastUpdated = start ERC20Rewards.rewardsPerToken can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewardsPerToken
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- rewardsPerToken.rate = rate ERC20Rewards.rewardsPerToken can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewardsPerToken
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- rewardsPeriod.start = start ERC20Rewards.rewardsPeriod can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards.rewardsPeriod
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- rewardsPeriod.end = end ERC20Rewards.rewardsPeriod can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards.rewardsPeriod
- ERC20Rewards.setRewards(uint32,uint32,uint96)
yield-utils-v2/src/token/ERC20Rewards.sol#L68-L100
- ID-3 Reentrancy in ERC20Rewards._mint(address,uint256): External calls:
- _updateRewardsPerToken()
- _updateUserRewards(dst)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- super._mint(dst,wad)
- _balanceOf[dst] = _balanceOf[dst] + wad ERC20._balanceOf can be used in cross function reentrancies:
- ERC20._transfer(address,address,uint256)
- ERC20Rewards._updateUserRewards(address)
- ERC20.balanceOf(address)
- super._mint(dst,wad)
- _totalSupply = _totalSupply + wad ERC20._totalSupply can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20.totalSupply()
yield-utils-v2/src/token/ERC20Rewards.sol#L142-L149
- ID-4 Reentrancy in ERC20Rewards._burn(address,uint256): External calls:
- _updateRewardsPerToken()
- _updateUserRewards(src)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- super._burn(src,wad)
- _balanceOf[src] = _balanceOf[src] - wad ERC20._balanceOf can be used in cross function reentrancies:
- ERC20._transfer(address,address,uint256)
- ERC20Rewards._updateUserRewards(address)
- ERC20.balanceOf(address)
- super._burn(src,wad)
- _totalSupply = _totalSupply - wad ERC20._totalSupply can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20.totalSupply()
yield-utils-v2/src/token/ERC20Rewards.sol#L152-L159
- ID-5 Reentrancy in ERC20Rewards._claim(address,address): External calls:
- _updateRewardsPerToken()
- claiming = _updateUserRewards(from)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- rewards[from].accumulated = 0 ERC20Rewards.rewards can be used in cross function reentrancies:
- ERC20Rewards._claim(address,address)
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewards
yield-utils-v2/src/token/ERC20Rewards.sol#L186-L195
- ID-6 Reentrancy in ERC20Rewards._transfer(address,address,uint256): External calls:
- _updateRewardsPerToken()
- _updateUserRewards(src)
- _updateUserRewards(dst)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- super._transfer(src,dst,wad)
- _balanceOf[src] = _balanceOf[src] - wad
- _balanceOf[dst] = _balanceOf[dst] + wad ERC20._balanceOf can be used in cross function reentrancies:
- ERC20._transfer(address,address,uint256)
- ERC20Rewards._updateUserRewards(address)
- ERC20.balanceOf(address)
- _updateUserRewards(dst)
- rewards[user] = userRewards_ ERC20Rewards.rewards can be used in cross function reentrancies:
- ERC20Rewards._claim(address,address)
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewards
yield-utils-v2/src/token/ERC20Rewards.sol#L162-L167
Use a lock mechanism instead of a deletion to disable structure containing a mapping.
Impact: Medium Confidence: High Smart contract under scope: https://github.com/yieldprotocol/yield-utils-v2/tree/main/src/utils/EmergencyBrake.sol
- ID-0 EmergencyBrake._erase(address) deletes IEmergencyBrake.Plan which contains a mapping: -delete plans[user]
yield-utils-v2/src/utils/EmergencyBrake.sol#L175-L192
Initialize all the variables. If a variable is meant to be initialized to zero, explicitly set it to zero to improve code readability.
Impact: Medium Confidence: Medium Smart contract under scope: https://github.com/yieldprotocol/yield-utils-v2/tree/main/src/utils/EmergencyBrake.sol
- ID-1 EmergencyBrake.add(address,IEmergencyBrake.Permission[]).i is a local variable never initialized
yield-utils-v2/src/utils/EmergencyBrake.sol#L94
- ID-2 EmergencyBrake.remove(address,IEmergencyBrake.Permission[]).i is a local variable never initialized
yield-utils-v2/src/utils/EmergencyBrake.sol#L129
Consider ordering multiplication before division.
Impact: Medium Confidence: Medium Smart contract under scope: https://github.com/yieldprotocol/yield-utils-v2/tree/main/src/utils/Math.sol
- ID-0 Math.wpow(uint256,uint256) performs a multiplication on the result of a division:
yield-utils-v2/src/utils/Math.sol#L41-L116
Apply the check-effects-interactions pattern.
Impact: Medium Confidence: Medium Smart contract under scope: https://github.com/yieldprotocol/yield-utils-v2/tree/main/src/token/ERC20Rewards.sol
- ID-0
Reentrancy in ERC20Rewards._updateRewardsPerToken():
External calls:
- rewardsPerToken_.accumulated = (rewardsPerToken_.accumulated + 1e18 * unaccountedTime * rewardsPerToken_.rate / totalSupply_).u128() State variables written after the call(s):
- rewardsPerToken = rewardsPerToken_ ERC20Rewards.rewardsPerToken can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewardsPerToken
- ERC20Rewards.setRewards(uint32,uint32,uint96)
yield-utils-v2/src/token/ERC20Rewards.sol#L104-L124
- ID-1
Reentrancy in ERC20Rewards._updateUserRewards(address):
External calls:
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- rewards[user] = userRewards_ ERC20Rewards.rewards can be used in cross function reentrancies:
- ERC20Rewards._claim(address,address)
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewards
yield-utils-v2/src/token/ERC20Rewards.sol#L128-L139
- ID-2
Reentrancy in ERC20Rewards.setRewards(uint32,uint32,uint96):
External calls:
- _updateRewardsPerToken()
- rewardsPerToken_.accumulated = (rewardsPerToken_.accumulated + 1e18 * unaccountedTime * rewardsPerToken_.rate / totalSupply_).u128() State variables written after the call(s):
- rewardsPerToken.lastUpdated = start ERC20Rewards.rewardsPerToken can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewardsPerToken
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- rewardsPerToken.rate = rate ERC20Rewards.rewardsPerToken can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewardsPerToken
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- rewardsPeriod.start = start ERC20Rewards.rewardsPeriod can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards.rewardsPeriod
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- rewardsPeriod.end = end ERC20Rewards.rewardsPeriod can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20Rewards.rewardsPeriod
- ERC20Rewards.setRewards(uint32,uint32,uint96)
- _updateRewardsPerToken()
yield-utils-v2/src/token/ERC20Rewards.sol#L68-L100
- ID-3
Reentrancy in ERC20Rewards._mint(address,uint256):
External calls:
- _updateRewardsPerToken()
- _updateUserRewards(dst)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- super._mint(dst,wad)
- _balanceOf[dst] = _balanceOf[dst] + wad ERC20._balanceOf can be used in cross function reentrancies:
- ERC20._transfer(address,address,uint256)
- ERC20Rewards._updateUserRewards(address)
- ERC20.balanceOf(address)
- super._mint(dst,wad)
- _totalSupply = _totalSupply + wad ERC20._totalSupply can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20.totalSupply()
yield-utils-v2/src/token/ERC20Rewards.sol#L142-L149
- ID-4
Reentrancy in ERC20Rewards._burn(address,uint256):
External calls:
- _updateRewardsPerToken()
- _updateUserRewards(src)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- super._burn(src,wad)
- _balanceOf[src] = _balanceOf[src] - wad ERC20._balanceOf can be used in cross function reentrancies:
- ERC20._transfer(address,address,uint256)
- ERC20Rewards._updateUserRewards(address)
- ERC20.balanceOf(address)
- super._burn(src,wad)
- _totalSupply = _totalSupply - wad ERC20._totalSupply can be used in cross function reentrancies:
- ERC20Rewards._updateRewardsPerToken()
- ERC20.totalSupply()
yield-utils-v2/src/token/ERC20Rewards.sol#L152-L159
- ID-5
Reentrancy in ERC20Rewards._claim(address,address):
External calls:
- _updateRewardsPerToken()
- claiming = _updateUserRewards(from)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- rewards[from].accumulated = 0 ERC20Rewards.rewards can be used in cross function reentrancies:
- ERC20Rewards._claim(address,address)
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewards
yield-utils-v2/src/token/ERC20Rewards.sol#L186-L195
- ID-6
Reentrancy in ERC20Rewards._transfer(address,address,uint256):
External calls:
- _updateRewardsPerToken()
- _updateUserRewards(src)
- _updateUserRewards(dst)
- userRewards_.accumulated = (userRewards_.accumulated + balanceOf[user] * (rewardsPerToken.accumulated - userRewards_.checkpoint) / 1e18).u128() State variables written after the call(s):
- super._transfer(src,dst,wad)
- _balanceOf[src] = _balanceOf[src] - wad
- _balanceOf[dst] = _balanceOf[dst] + wad ERC20._balanceOf can be used in cross function reentrancies:
- ERC20._transfer(address,address,uint256)
- ERC20Rewards._updateUserRewards(address)
- ERC20.balanceOf(address)
- _updateUserRewards(dst)
- rewards[user] = userRewards_ ERC20Rewards.rewards can be used in cross function reentrancies:
- ERC20Rewards._claim(address,address)
- ERC20Rewards._updateUserRewards(address)
- ERC20Rewards.rewards
yield-utils-v2/src/token/ERC20Rewards.sol#L162-L167
Fix or remove the writes.
Impact: Medium Confidence: High Smart contract under scope: https://github.com/yieldprotocol/vault-v2/tree/main/src/mocks/oracles/OracleMock.sol
- ID-0 OracleMock.updated is written in both updated = block.timestamp (spot * amount / 1e18,updated = block.timestamp)
vault-v2/src/mocks/oracles/OracleMock.sol#L12
Consider ordering multiplication before division.
Impact: Medium Confidence: Medium Smart contract under scope: https://github.com/yieldprotocol/vault-v2/tree/main/src/oracles/uniswap/uniswapv0.8/FullMath.sol
- ID-0 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-1 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-2 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-3 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-4 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-5 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-6 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
- ID-7 FullMath.mulDiv(uint256,uint256,uint256) performs a multiplication on the result of a division:
vault-v2/src/oracles/uniswap/uniswapv0.8/FullMath.sol#L14-L106
Set the appropriate return values and types for the defined ERC20 functions.
Impact: Medium Confidence: High Smart contract under scope: https://github.com/yieldprotocol/vault-v2/tree/main/src/other/tether/IUSDT.sol
- ID-0 IUSDT has incorrect ERC20 function interface:IUSDT.transfer(address,uint256)
vault-v2/src/other/tether/IUSDT.sol#L7-L34
- ID-1 IUSDT has incorrect ERC20 function interface:IUSDT.transferFrom(address,address,uint256)
vault-v2/src/other/tether/IUSDT.sol#L7-L34
- ID-2 IUSDT has incorrect ERC20 function interface:IUSDT.approve(address,uint256)
vault-v2/src/other/tether/IUSDT.sol#L7-L34