Skip to content

Commit 944c015

Browse files
authored
GeneralIndexModule internal review and external audit revisions (#75)
* Make all revert reason strings < 32bytes * Remove _normalizedTargetMethod getter * Encapsulate _noTokensToSell#canSell logic as internal method * Encapsulate _allTargetsMet#targetUnmet logic in internal method * Validate exchange adapter when setting & store name as bytes32 hash * Consolidate position state and timestamp updates * Validate params for external view methods * Make all external setter method names use prefix `set` * Add RebalanceStarted event * Remove _caller param from onlyAllowedTrader modifier * Add getDefaultPositionRealUnit getter * Encapsulate data aggregation logic in #startRebalance in own method * Prohibit external positions for components in #initialize and #startRebalance * Refactor #createTradeInfo methods * Make weth state variable immutable * Delegate modifier logic to internal helpers in ModuleBase and GeneralIndexModule * Delete trader permissions on module removal / add removeModule tests * Add #validatePairsWithArray methods to AddressArrayUtils library and use in setter methods * Add approximatelyEquals helper in PreciseUnitMath and use in #_targetUnmet * Add AssetTargetsRaised event in RaiseAssetTargets with positionMultiplier arg * Remove trader from permissionInfo.tradersHistory when they are de-authorized * Add getAllowedTraders method and make tradersHistory contain unique elements
1 parent 0a86d87 commit 944c015

File tree

9 files changed

+1318
-293
lines changed

9 files changed

+1318
-293
lines changed

contracts/lib/AddressArrayUtils.sol

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ pragma solidity 0.6.10;
2323
* @author Set Protocol
2424
*
2525
* Utility functions to handle Address Arrays
26+
*
27+
* CHANGELOG:
28+
* - 4/21/21: Added validatePairsWithArray methods
2629
*/
2730
library AddressArrayUtils {
2831

@@ -74,7 +77,7 @@ library AddressArrayUtils {
7477

7578
/**
7679
* @param A The input array to search
77-
* @param a The address to remove
80+
* @param a The address to remove
7881
* @return Returns the array with the object removed.
7982
*/
8083
function remove(address[] memory A, address a)
@@ -149,4 +152,74 @@ library AddressArrayUtils {
149152
}
150153
return newAddresses;
151154
}
152-
}
155+
156+
/**
157+
* Validate that address and uint array lengths match. Validate address array is not empty
158+
* and contains no duplicate elements.
159+
*
160+
* @param A Array of addresses
161+
* @param B Array of uint
162+
*/
163+
function validatePairsWithArray(address[] memory A, uint[] memory B) internal pure {
164+
require(A.length == B.length, "Array length mismatch");
165+
_validateLengthAndUniqueness(A);
166+
}
167+
168+
/**
169+
* Validate that address and bool array lengths match. Validate address array is not empty
170+
* and contains no duplicate elements.
171+
*
172+
* @param A Array of addresses
173+
* @param B Array of bool
174+
*/
175+
function validatePairsWithArray(address[] memory A, bool[] memory B) internal pure {
176+
require(A.length == B.length, "Array length mismatch");
177+
_validateLengthAndUniqueness(A);
178+
}
179+
180+
/**
181+
* Validate that address and string array lengths match. Validate address array is not empty
182+
* and contains no duplicate elements.
183+
*
184+
* @param A Array of addresses
185+
* @param B Array of strings
186+
*/
187+
function validatePairsWithArray(address[] memory A, string[] memory B) internal pure {
188+
require(A.length == B.length, "Array length mismatch");
189+
_validateLengthAndUniqueness(A);
190+
}
191+
192+
/**
193+
* Validate that address array lengths match, and calling address array are not empty
194+
* and contain no duplicate elements.
195+
*
196+
* @param A Array of addresses
197+
* @param B Array of addresses
198+
*/
199+
function validatePairsWithArray(address[] memory A, address[] memory B) internal pure {
200+
require(A.length == B.length, "Array length mismatch");
201+
_validateLengthAndUniqueness(A);
202+
}
203+
204+
/**
205+
* Validate that address and bytes array lengths match. Validate address array is not empty
206+
* and contains no duplicate elements.
207+
*
208+
* @param A Array of addresses
209+
* @param B Array of bytes
210+
*/
211+
function validatePairsWithArray(address[] memory A, bytes[] memory B) internal pure {
212+
require(A.length == B.length, "Array length mismatch");
213+
_validateLengthAndUniqueness(A);
214+
}
215+
216+
/**
217+
* Validate address array is not empty and contains no duplicate elements.
218+
*
219+
* @param A Array of addresses
220+
*/
221+
function _validateLengthAndUniqueness(address[] memory A) internal pure {
222+
require(A.length > 0, "Array length must be > 0");
223+
require(!hasDuplicate(A), "Cannot duplicate addresses");
224+
}
225+
}

contracts/lib/PreciseUnitMath.sol

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol"
3232
*
3333
* CHANGELOG:
3434
* - 9/21/20: Added safePower function
35+
* - 4/21/21: Added approximatelyEquals function
3536
*/
3637
library PreciseUnitMath {
3738
using SafeMath for uint256;
@@ -149,16 +150,16 @@ library PreciseUnitMath {
149150
}
150151

151152
/**
152-
* @dev Multiplies value a by value b where rounding is towards the lesser number.
153-
* (positive values are rounded towards zero and negative values are rounded away from 0).
153+
* @dev Multiplies value a by value b where rounding is towards the lesser number.
154+
* (positive values are rounded towards zero and negative values are rounded away from 0).
154155
*/
155156
function conservativePreciseMul(int256 a, int256 b) internal pure returns (int256) {
156157
return divDown(a.mul(b), PRECISE_UNIT_INT);
157158
}
158159

159160
/**
160-
* @dev Divides value a by value b where rounding is towards the lesser number.
161-
* (positive values are rounded towards zero and negative values are rounded away from 0).
161+
* @dev Divides value a by value b where rounding is towards the lesser number.
162+
* (positive values are rounded towards zero and negative values are rounded away from 0).
162163
*/
163164
function conservativePreciseDiv(int256 a, int256 b) internal pure returns (int256) {
164165
return divDown(a.mul(PRECISE_UNIT_INT), b);
@@ -187,4 +188,11 @@ library PreciseUnitMath {
187188

188189
return result;
189190
}
190-
}
191+
192+
/**
193+
* @dev Returns true if a =~ b within range, false otherwise.
194+
*/
195+
function approximatelyEquals(uint256 a, uint256 b, uint256 range) internal pure returns (bool) {
196+
return a <= b.add(range) && a >= b.sub(range);
197+
}
198+
}

contracts/mocks/AddressArrayUtilsMock.sol

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,31 @@ contract AddressArrayUtilsMock {
5151
return A.pop(index);
5252
}
5353

54+
function testValidatePairsWithArrayUint(address[] memory A, uint[] memory a) external view {
55+
A.validatePairsWithArray(a);
56+
}
57+
58+
function testValidatePairsWithArrayBool(address[] memory A, bool[] memory a) external view {
59+
A.validatePairsWithArray(a);
60+
}
61+
62+
function testValidatePairsWithArrayString(address[] memory A, string[] memory a) external view {
63+
A.validatePairsWithArray(a);
64+
}
65+
66+
function testValidatePairsWithArrayAddress(address[] memory A, address[] memory a) external view {
67+
A.validatePairsWithArray(a);
68+
}
69+
70+
function testValidatePairsWithArrayBytes(address[] memory A, bytes[] memory a) external view {
71+
A.validatePairsWithArray(a);
72+
}
73+
5474
function setStorageArray(address[] memory A) external {
5575
storageArray = A;
5676
}
5777

5878
function getStorageArray() external view returns(address[] memory) {
5979
return storageArray;
6080
}
61-
}
81+
}

contracts/mocks/PreciseUnitMathMock.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,8 @@ contract PreciseUnitMathMock {
8181
function safePower(uint256 a, uint256 b) external pure returns(uint256) {
8282
return a.safePower(b);
8383
}
84-
}
84+
85+
function approximatelyEquals(uint256 a, uint256 b, uint256 range) external pure returns (bool) {
86+
return a.approximatelyEquals(b, range);
87+
}
88+
}

contracts/protocol/lib/ModuleBase.sol

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol"
3838
* @author Set Protocol
3939
*
4040
* Abstract class that houses common Module-related state and functions.
41+
*
42+
* CHANGELOG:
43+
* - 4/21/21: Delegated modifier logic to internal helpers to reduce contract size
44+
*
4145
*/
4246
abstract contract ModuleBase is IModule {
4347
using AddressArrayUtils for address[];
@@ -57,35 +61,26 @@ abstract contract ModuleBase is IModule {
5761

5862
/* ============ Modifiers ============ */
5963

60-
modifier onlyManagerAndValidSet(ISetToken _setToken) {
61-
require(isSetManager(_setToken, msg.sender), "Must be the SetToken manager");
62-
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
64+
modifier onlyManagerAndValidSet(ISetToken _setToken) {
65+
_validateOnlyManagerAndValidSet(_setToken);
6366
_;
6467
}
6568

6669
modifier onlySetManager(ISetToken _setToken, address _caller) {
67-
require(isSetManager(_setToken, _caller), "Must be the SetToken manager");
70+
_validateOnlySetManager(_setToken, _caller);
6871
_;
6972
}
7073

7174
modifier onlyValidAndInitializedSet(ISetToken _setToken) {
72-
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
75+
_validateOnlyValidAndInitializedSet(_setToken);
7376
_;
7477
}
7578

7679
/**
7780
* Throws if the sender is not a SetToken's module or module not enabled
7881
*/
7982
modifier onlyModule(ISetToken _setToken) {
80-
require(
81-
_setToken.moduleStates(msg.sender) == ISetToken.ModuleState.INITIALIZED,
82-
"Only the module can call"
83-
);
84-
85-
require(
86-
controller.isModule(msg.sender),
87-
"Module must be enabled on controller"
88-
);
83+
_validateOnlyModule(_setToken);
8984
_;
9085
}
9186

@@ -94,8 +89,7 @@ abstract contract ModuleBase is IModule {
9489
* and that the SetToken is valid
9590
*/
9691
modifier onlyValidAndPendingSet(ISetToken _setToken) {
97-
require(controller.isSet(address(_setToken)), "Must be controller-enabled SetToken");
98-
require(isSetPendingInitialization(_setToken), "Must be pending initialization");
92+
_validateOnlyValidAndPendingSet(_setToken);
9993
_;
10094
}
10195

@@ -191,4 +185,53 @@ abstract contract ModuleBase is IModule {
191185
function getNameHash(string memory _name) internal pure returns(bytes32) {
192186
return keccak256(bytes(_name));
193187
}
188+
189+
/* ============== Modifier Helpers ===============
190+
* Internal functions used to reduce bytecode size
191+
*/
192+
193+
/**
194+
* Caller must SetToken manager and SetToken must be valid and initialized
195+
*/
196+
function _validateOnlyManagerAndValidSet(ISetToken _setToken) internal view {
197+
require(isSetManager(_setToken, msg.sender), "Must be the SetToken manager");
198+
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
199+
}
200+
201+
/**
202+
* Caller must SetToken manager
203+
*/
204+
function _validateOnlySetManager(ISetToken _setToken, address _caller) internal view {
205+
require(isSetManager(_setToken, _caller), "Must be the SetToken manager");
206+
}
207+
208+
/**
209+
* SetToken must be valid and initialized
210+
*/
211+
function _validateOnlyValidAndInitializedSet(ISetToken _setToken) internal view {
212+
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
213+
}
214+
215+
/**
216+
* Caller must be initialized module and module must be enabled on the controller
217+
*/
218+
function _validateOnlyModule(ISetToken _setToken) internal view {
219+
require(
220+
_setToken.moduleStates(msg.sender) == ISetToken.ModuleState.INITIALIZED,
221+
"Only the module can call"
222+
);
223+
224+
require(
225+
controller.isModule(msg.sender),
226+
"Module must be enabled on controller"
227+
);
228+
}
229+
230+
/**
231+
* SetToken must be in a pending state and module must be in pending state
232+
*/
233+
function _validateOnlyValidAndPendingSet(ISetToken _setToken) internal view {
234+
require(controller.isSet(address(_setToken)), "Must be controller-enabled SetToken");
235+
require(isSetPendingInitialization(_setToken), "Must be pending initialization");
236+
}
194237
}

0 commit comments

Comments
 (0)