• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IndexCoop / index-coop-smart-contracts / c35afff2-bbde-44b0-b239-74783fd1a2c8

08 Sep 2023 10:24PM UTC coverage: 77.128% (+0.7%) from 76.388%
c35afff2-bbde-44b0-b239-74783fd1a2c8

push

circleci

web-flow
feat(Manager): Add DelegatedManager System (#150)

958 of 1320 branches covered (0.0%)

Branch coverage included in aggregate %.

517 of 517 new or added lines in 16 files covered. (100.0%)

2721 of 3450 relevant lines covered (78.87%)

61.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

25.0
/contracts/lib/ModuleBase.sol
1
/*
2
    Copyright 2020 Set Labs Inc.
3

4
    Licensed under the Apache License, Version 2.0 (the "License");
5
    you may not use this file except in compliance with the License.
6
    You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
    Unless required by applicable law or agreed to in writing, software
11
    distributed under the License is distributed on an "AS IS" BASIS,
12
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
    See the License for the specific language governing permissions and
14
    limitations under the License.
15

16
    SPDX-License-Identifier: Apache License, Version 2.0
17
*/
18

19
pragma solidity 0.6.10;
20

21
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
22

23
import { AddressArrayUtils } from "./AddressArrayUtils.sol";
24
import { ExplicitERC20 } from "./ExplicitERC20.sol";
25
import { IController } from "../interfaces/IController.sol";
26
import { IModule } from "../interfaces/IModule.sol";
27
import { ISetToken } from "../interfaces/ISetToken.sol";
28
import { Invoke } from "./Invoke.sol";
29
import { Position } from "./Position.sol";
30
import { PreciseUnitMath } from "./PreciseUnitMath.sol";
31
import { ResourceIdentifier } from "./ResourceIdentifier.sol";
32
import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol";
33
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
34
import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol";
35

36
/**
37
 * @title ModuleBase
38
 * @author Set Protocol
39
 *
40
 * 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
 *
45
 */
46
abstract contract ModuleBase is IModule {
47
    using AddressArrayUtils for address[];
48
    using Invoke for ISetToken;
49
    using Position for ISetToken;
50
    using PreciseUnitMath for uint256;
51
    using ResourceIdentifier for IController;
52
    using SafeCast for int256;
53
    using SafeCast for uint256;
54
    using SafeMath for uint256;
55
    using SignedSafeMath for int256;
56

57
    /* ============ State Variables ============ */
58

59
    // Address of the controller
60
    IController public controller;
61

62
    /* ============ Modifiers ============ */
63

64
    modifier onlyManagerAndValidSet(ISetToken _setToken) {
65
        _validateOnlyManagerAndValidSet(_setToken);
×
66
        _;
67
    }
68

69
    modifier onlySetManager(ISetToken _setToken, address _caller) {
70
        _validateOnlySetManager(_setToken, _caller);
19✔
71
        _;
72
    }
73

74
    modifier onlyValidAndInitializedSet(ISetToken _setToken) {
75
        _validateOnlyValidAndInitializedSet(_setToken);
×
76
        _;
77
    }
78

79
    /**
80
     * Throws if the sender is not a SetToken's module or module not enabled
81
     */
82
    modifier onlyModule(ISetToken _setToken) {
83
        _validateOnlyModule(_setToken);
×
84
        _;
85
    }
86

87
    /**
88
     * Utilized during module initializations to check that the module is in pending state
89
     * and that the SetToken is valid
90
     */
91
    modifier onlyValidAndPendingSet(ISetToken _setToken) {
92
        _validateOnlyValidAndPendingSet(_setToken);
19✔
93
        _;
94
    }
95

96
    /* ============ Constructor ============ */
97

98
    /**
99
     * Set state variables and map asset pairs to their oracles
100
     *
101
     * @param _controller             Address of controller contract
102
     */
103
    constructor(IController _controller) public {
104
        controller = _controller;
6✔
105
    }
106

107
    /* ============ Internal Functions ============ */
108

109
    /**
110
     * Transfers tokens from an address (that has set allowance on the module).
111
     *
112
     * @param  _token          The address of the ERC20 token
113
     * @param  _from           The address to transfer from
114
     * @param  _to             The address to transfer to
115
     * @param  _quantity       The number of tokens to transfer
116
     */
117
    function transferFrom(IERC20 _token, address _from, address _to, uint256 _quantity) internal {
118
        ExplicitERC20.transferFrom(_token, _from, _to, _quantity);
×
119
    }
120

121
    /**
122
     * Gets the integration for the module with the passed in name. Validates that the address is not empty
123
     */
124
    function getAndValidateAdapter(string memory _integrationName) internal view returns(address) { 
125
        bytes32 integrationHash = getNameHash(_integrationName);
×
126
        return getAndValidateAdapterWithHash(integrationHash);
×
127
    }
128

129
    /**
130
     * Gets the integration for the module with the passed in hash. Validates that the address is not empty
131
     */
132
    function getAndValidateAdapterWithHash(bytes32 _integrationHash) internal view returns(address) { 
133
        address adapter = controller.getIntegrationRegistry().getIntegrationAdapterWithHash(
×
134
            address(this),
135
            _integrationHash
136
        );
137

138
        require(adapter != address(0), "Must be valid adapter"); 
×
139
        return adapter;
×
140
    }
141

142
    /**
143
     * Gets the total fee for this module of the passed in index (fee % * quantity)
144
     */
145
    function getModuleFee(uint256 _feeIndex, uint256 _quantity) internal view returns(uint256) {
146
        uint256 feePercentage = controller.getModuleFee(address(this), _feeIndex);
×
147
        return _quantity.preciseMul(feePercentage);
×
148
    }
149

150
    /**
151
     * Pays the _feeQuantity from the _setToken denominated in _token to the protocol fee recipient
152
     */
153
    function payProtocolFeeFromSetToken(ISetToken _setToken, address _token, uint256 _feeQuantity) internal {
154
        if (_feeQuantity > 0) {
×
155
            _setToken.strictInvokeTransfer(_token, controller.feeRecipient(), _feeQuantity); 
×
156
        }
157
    }
158

159
    /**
160
     * Returns true if the module is in process of initialization on the SetToken
161
     */
162
    function isSetPendingInitialization(ISetToken _setToken) internal view returns(bool) {
163
        return _setToken.isPendingModule(address(this));
19✔
164
    }
165

166
    /**
167
     * Returns true if the address is the SetToken's manager
168
     */
169
    function isSetManager(ISetToken _setToken, address _toCheck) internal view returns(bool) {
170
        return _setToken.manager() == _toCheck;
19✔
171
    }
172

173
    /**
174
     * Returns true if SetToken must be enabled on the controller 
175
     * and module is registered on the SetToken
176
     */
177
    function isSetValidAndInitialized(ISetToken _setToken) internal view returns(bool) {
178
        return controller.isSet(address(_setToken)) &&
×
179
            _setToken.isInitializedModule(address(this));
180
    }
181

182
    /**
183
     * Hashes the string and returns a bytes32 value
184
     */
185
    function getNameHash(string memory _name) internal pure returns(bytes32) {
186
        return keccak256(bytes(_name));
×
187
    }
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");
19✔
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");
19!
235
        require(isSetPendingInitialization(_setToken), "Must be pending initialization");
19!
236
    }
237
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc