-
Notifications
You must be signed in to change notification settings - Fork 107
ClaimModule Audit fixes #97
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
30fbbc3
low hanging audit changes
ncitron 2296353
fix tests
ncitron 15c3be7
audit changes
ncitron 65aeb0d
fix tests
ncitron 3c905dc
improve tests
ncitron 883c557
clean up contracts
ncitron 3e2236a
use removeStorage
ncitron 6266aea
review changes
ncitron File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,8 @@ | |
| pragma solidity 0.6.10; | ||
| pragma experimental "ABIEncoderV2"; | ||
|
|
||
| import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
|
||
| import { AddressArrayUtils } from "../../lib/AddressArrayUtils.sol"; | ||
| import { IClaimAdapter } from "../../interfaces/IClaimAdapter.sol"; | ||
| import { IController } from "../../interfaces/IController.sol"; | ||
|
|
@@ -52,10 +54,15 @@ contract ClaimModule is ModuleBase { | |
| event RewardClaimed( | ||
| ISetToken indexed _setToken, | ||
| address indexed _rewardPool, | ||
| IClaimAdapter _adapter, | ||
| IClaimAdapter indexed _adapter, | ||
| uint256 _amount | ||
| ); | ||
|
|
||
| event AnyoneClaimUpdated( | ||
| ISetToken indexed _setToken, | ||
| bool _anyoneClaim | ||
| ); | ||
|
|
||
| /* ============ Modifiers ============ */ | ||
|
|
||
| /** | ||
|
|
@@ -71,11 +78,16 @@ contract ClaimModule is ModuleBase { | |
| // Indicates if any address can call claim or just the manager of the SetToken | ||
| mapping(ISetToken => bool) public anyoneClaim; | ||
|
|
||
| // Array of rewardPool addresses to claim rewards for the SetToken | ||
| // Map and array of rewardPool addresses to claim rewards for the SetToken | ||
| mapping(ISetToken => address[]) public rewardPoolList; | ||
| // Map from set tokens to rewards pool address to isAdded boolean. Used to check if a reward pool has been added in O(1) time | ||
| mapping(ISetToken => mapping(address => bool)) public rewardPoolStatus; | ||
|
|
||
| // Array of adapters associated to the rewardPool for the SetToken | ||
| // Map and array of adapters associated to the rewardPool for the SetToken | ||
| mapping(ISetToken => mapping(address => address[])) public claimSettings; | ||
| // Map from set tokens to rewards pool address to claim adapters to isAdded boolean. Used to check if an adapter has been added in O(1) time | ||
| mapping(ISetToken => mapping(address => mapping(address => bool))) public claimSettingsStatus; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment for what this mapping does and why? Crazy nesting |
||
|
|
||
|
|
||
| /* ============ Constructor ============ */ | ||
|
|
||
|
|
@@ -133,10 +145,10 @@ contract ClaimModule is ModuleBase { | |
| * | ||
| * @param _setToken Address of SetToken | ||
| */ | ||
| function updateAnyoneClaim(ISetToken _setToken) external onlyManagerAndValidSet(_setToken) { | ||
| anyoneClaim[_setToken] = !anyoneClaim[_setToken]; | ||
| function updateAnyoneClaim(ISetToken _setToken, bool _anyoneClaim) external onlyManagerAndValidSet(_setToken) { | ||
| anyoneClaim[_setToken] = _anyoneClaim; | ||
| emit AnyoneClaimUpdated(_setToken, _anyoneClaim); | ||
| } | ||
|
|
||
| /** | ||
| * SET MANAGER ONLY. Adds a new claim integration for an existent rewardPool. If rewardPool doesn't have existing | ||
| * claims then rewardPool is added to rewardPoolLiost. The claim integration is associated to an adapter that | ||
|
|
@@ -252,10 +264,27 @@ contract ClaimModule is ModuleBase { | |
| function removeModule() external override { | ||
| delete anyoneClaim[ISetToken(msg.sender)]; | ||
|
|
||
| // explicitly delete all elements for gas refund | ||
| address[] memory setTokenPoolList = rewardPoolList[ISetToken(msg.sender)]; | ||
| for (uint256 i = 0; i < setTokenPoolList.length; i++) { | ||
|
|
||
ncitron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| address[] storage adapterList = claimSettings[ISetToken(msg.sender)][setTokenPoolList[i]]; | ||
| for (uint256 j = 0; j < adapterList.length; j++) { | ||
|
|
||
| address toRemove = adapterList[j]; | ||
| claimSettingsStatus[ISetToken(msg.sender)][setTokenPoolList[i]][toRemove] = false; | ||
|
|
||
| delete adapterList[j]; | ||
| } | ||
| delete claimSettings[ISetToken(msg.sender)][setTokenPoolList[i]]; | ||
| } | ||
|
|
||
| for (uint256 i = 0; i < rewardPoolList[ISetToken(msg.sender)].length; i++) { | ||
| address toRemove = rewardPoolList[ISetToken(msg.sender)][i]; | ||
| rewardPoolStatus[ISetToken(msg.sender)][toRemove] = false; | ||
|
|
||
| delete rewardPoolList[ISetToken(msg.sender)][i]; | ||
| } | ||
| delete rewardPoolList[ISetToken(msg.sender)]; | ||
| } | ||
|
|
||
|
|
@@ -277,7 +306,7 @@ contract ClaimModule is ModuleBase { | |
| * @return Boolean indicating if the rewardPool is in the list for claims. | ||
| */ | ||
| function isRewardPool(ISetToken _setToken, address _rewardPool) public view returns (bool) { | ||
| return rewardPoolList[_setToken].contains(_rewardPool); | ||
| return rewardPoolStatus[_setToken][_rewardPool]; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -309,7 +338,7 @@ contract ClaimModule is ModuleBase { | |
| returns (bool) | ||
| { | ||
| address adapter = getAndValidateAdapter(_integrationName); | ||
| return claimSettings[_setToken][_rewardPool].contains(adapter); | ||
| return claimSettingsStatus[_setToken][_rewardPool][adapter]; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -329,9 +358,8 @@ contract ClaimModule is ModuleBase { | |
| view | ||
| returns (uint256) | ||
| { | ||
| IClaimAdapter adapter = _getAndValidateIntegrationAdapter(claimSettings[_setToken][_rewardPool], _integrationName); | ||
| uint256 rewards = adapter.getRewards(address(_setToken), _rewardPool); | ||
| return rewards; | ||
| IClaimAdapter adapter = _getAndValidateIntegrationAdapter(_setToken, _rewardPool, _integrationName); | ||
| return adapter.getRewardsAmount(_setToken, _rewardPool); | ||
| } | ||
|
|
||
| /* ============ Internal Functions ============ */ | ||
|
|
@@ -346,40 +374,45 @@ contract ClaimModule is ModuleBase { | |
| */ | ||
| function _claim(ISetToken _setToken, address _rewardPool, string calldata _integrationName) internal { | ||
| require(isRewardPool(_setToken, _rewardPool), "RewardPool not present"); | ||
| IClaimAdapter adapter = _getAndValidateIntegrationAdapter(claimSettings[_setToken][_rewardPool], _integrationName); | ||
| IClaimAdapter adapter = _getAndValidateIntegrationAdapter(_setToken, _rewardPool, _integrationName); | ||
|
|
||
| uint256 rewards = adapter.getRewards(address(_setToken), _rewardPool); | ||
| IERC20 rewardsToken = IERC20(adapter.getTokenAddress(_rewardPool)); | ||
| uint256 initRewardsBalance = rewardsToken.balanceOf(address(_setToken)); | ||
|
|
||
| ( | ||
| address callTarget, | ||
| uint256 callValue, | ||
| bytes memory callByteData | ||
| ) = adapter.getClaimCallData( | ||
| address(_setToken), | ||
| _setToken, | ||
| _rewardPool | ||
| ); | ||
|
|
||
| _setToken.invoke(callTarget, callValue, callByteData); | ||
|
|
||
| emit RewardClaimed(_setToken, _rewardPool, adapter, rewards); | ||
| uint256 finalRewardsBalance = rewardsToken.balanceOf(address(_setToken)); | ||
|
|
||
| emit RewardClaimed(_setToken, _rewardPool, adapter, finalRewardsBalance.sub(initRewardsBalance)); | ||
| } | ||
|
|
||
| /** | ||
| * Gets the adapter and validate it is associated to the list of claim integration of a rewardPool. | ||
| * | ||
| * @param _rewardPoolClaimSettings List of claim integrations associated to a rewardPool | ||
| * @param _integrationName ID of claim module integration (mapping on integration registry) | ||
| * @param _setToken Address of SetToken | ||
| * @param _rewardsPool Sddress of rewards pool | ||
| * @param _integrationName ID of claim module integration (mapping on integration registry) | ||
| */ | ||
| function _getAndValidateIntegrationAdapter( | ||
| address[] memory _rewardPoolClaimSettings, | ||
| ISetToken _setToken, | ||
| address _rewardsPool, | ||
| string calldata _integrationName | ||
| ) | ||
| internal | ||
| view | ||
| returns (IClaimAdapter) | ||
| { | ||
| address adapter = getAndValidateAdapter(_integrationName); | ||
| require(_rewardPoolClaimSettings.contains(adapter), "Adapter integration not present"); | ||
| require(claimSettingsStatus[_setToken][_rewardsPool][adapter], "Adapter integration not present"); | ||
| return IClaimAdapter(adapter); | ||
| } | ||
|
|
||
|
|
@@ -395,11 +428,13 @@ contract ClaimModule is ModuleBase { | |
| address adapter = getAndValidateAdapter(_integrationName); | ||
| address[] storage _rewardPoolClaimSettings = claimSettings[_setToken][_rewardPool]; | ||
|
|
||
| require(!_rewardPoolClaimSettings.contains(adapter), "Integration names must be unique"); | ||
| require(!claimSettingsStatus[_setToken][_rewardPool][adapter], "Integration names must be unique"); | ||
| _rewardPoolClaimSettings.push(adapter); | ||
| claimSettingsStatus[_setToken][_rewardPool][adapter] = true; | ||
|
|
||
| if (_rewardPoolClaimSettings.length == 1) { | ||
| if (!rewardPoolStatus[_setToken][_rewardPool]) { | ||
| rewardPoolList[_setToken].push(_rewardPool); | ||
| rewardPoolStatus[_setToken][_rewardPool] = true; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -428,7 +463,7 @@ contract ClaimModule is ModuleBase { | |
| } | ||
|
|
||
| /** | ||
| * Validates and store the adapter address used to claim rewards for the passed rewardPool. If no adapters | ||
| * Validates and stores the adapter address used to claim rewards for the passed rewardPool. If no adapters | ||
| * left after removal then remove rewardPool from rewardPoolList and delete entry in claimSettings. | ||
| * | ||
| * @param _setToken Address of SetToken | ||
|
|
@@ -437,14 +472,14 @@ contract ClaimModule is ModuleBase { | |
| */ | ||
| function _removeClaim(ISetToken _setToken, address _rewardPool, string calldata _integrationName) internal { | ||
| address adapter = getAndValidateAdapter(_integrationName); | ||
| address[] memory _rewardPoolClaimSettings = claimSettings[_setToken][_rewardPool]; | ||
|
|
||
| require(_rewardPoolClaimSettings.contains(adapter), "Integration must be added"); | ||
| claimSettings[_setToken][_rewardPool] = _rewardPoolClaimSettings.remove(adapter); | ||
| require(claimSettingsStatus[_setToken][_rewardPool][adapter], "Integration must be added"); | ||
| claimSettings[_setToken][_rewardPool].removeStorage(adapter); | ||
| claimSettingsStatus[_setToken][_rewardPool][adapter] = false; | ||
|
|
||
| if (claimSettings[_setToken][_rewardPool].length == 0) { | ||
| rewardPoolList[_setToken] = rewardPoolList[_setToken].remove(_rewardPool); | ||
| delete claimSettings[_setToken][_rewardPool]; | ||
| rewardPoolList[_setToken].removeStorage(_rewardPool); | ||
| rewardPoolStatus[_setToken][_rewardPool] = false; | ||
| } | ||
| } | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment for what this mapping does and why?