ModuleBase <> ModuleBaseV2

Created Diff never expires
7 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
237 lines
7 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
237 lines
/*
/*
Copyright 2020 Set Labs Inc.
Copyright 2022 Set Labs Inc.


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


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


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


SPDX-License-Identifier: Apache License, Version 2.0
SPDX-License-Identifier: Apache License, Version 2.0
*/
*/


pragma solidity 0.6.10;
pragma solidity 0.6.10;


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


import { AddressArrayUtils } from "../../lib/AddressArrayUtils.sol";
import { AddressArrayUtils } from "../../lib/AddressArrayUtils.sol";
import { ExplicitERC20 } from "../../lib/ExplicitERC20.sol";
import { ExplicitERC20 } from "../../lib/ExplicitERC20.sol";
import { IController } from "../../interfaces/IController.sol";
import { IController } from "../../interfaces/IController.sol";
import { IModule } from "../../interfaces/IModule.sol";
import { IModule } from "../../interfaces/IModule.sol";
import { ISetToken } from "../../interfaces/ISetToken.sol";
import { ISetToken } from "../../interfaces/ISetToken.sol";
import { Invoke } from "./Invoke.sol";
import { Invoke } from "./Invoke.sol";
import { Position } from "./Position.sol";
import { PositionV2 } from "./PositionV2.sol";
import { PreciseUnitMath } from "../../lib/PreciseUnitMath.sol";
import { PreciseUnitMath } from "../../lib/PreciseUnitMath.sol";
import { ResourceIdentifier } from "./ResourceIdentifier.sol";
import { ResourceIdentifier } from "./ResourceIdentifier.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol";
import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol";


/**
/**
* @title ModuleBase
* @title ModuleBaseV2
* @author Set Protocol
* @author Set Protocol
*
*
* Abstract class that houses common Module-related state and functions.
* Abstract class that houses common Module-related state and functions.
*
*
* CHANGELOG:
* CHANGELOG:
* - 4/21/21: Delegated modifier logic to internal helpers to reduce contract size
* - Uses PositionV2 linkable library.
*
*
*/
*/
abstract contract ModuleBase is IModule {
abstract contract ModuleBaseV2 is IModule {
using AddressArrayUtils for address[];
using AddressArrayUtils for address[];
using Invoke for ISetToken;
using Invoke for ISetToken;
using Position for ISetToken;
using PositionV2 for ISetToken;
using PreciseUnitMath for uint256;
using PreciseUnitMath for uint256;
using ResourceIdentifier for IController;
using ResourceIdentifier for IController;
using SafeCast for int256;
using SafeCast for int256;
using SafeCast for uint256;
using SafeCast for uint256;
using SafeMath for uint256;
using SafeMath for uint256;
using SignedSafeMath for int256;
using SignedSafeMath for int256;


/* ============ State Variables ============ */
/* ============ State Variables ============ */


// Address of the controller
// Address of the controller
IController public controller;
IController public controller;


/* ============ Modifiers ============ */
/* ============ Modifiers ============ */


modifier onlyManagerAndValidSet(ISetToken _setToken) {
modifier onlyManagerAndValidSet(ISetToken _setToken) {
_validateOnlyManagerAndValidSet(_setToken);
_validateOnlyManagerAndValidSet(_setToken);
_;
_;
}
}


modifier onlySetManager(ISetToken _setToken, address _caller) {
modifier onlySetManager(ISetToken _setToken, address _caller) {
_validateOnlySetManager(_setToken, _caller);
_validateOnlySetManager(_setToken, _caller);
_;
_;
}
}


modifier onlyValidAndInitializedSet(ISetToken _setToken) {
modifier onlyValidAndInitializedSet(ISetToken _setToken) {
_validateOnlyValidAndInitializedSet(_setToken);
_validateOnlyValidAndInitializedSet(_setToken);
_;
_;
}
}


/**
/**
* Throws if the sender is not a SetToken's module or module not enabled
* Throws if the sender is not a SetToken's module or module not enabled
*/
*/
modifier onlyModule(ISetToken _setToken) {
modifier onlyModule(ISetToken _setToken) {
_validateOnlyModule(_setToken);
_validateOnlyModule(_setToken);
_;
_;
}
}


/**
/**
* Utilized during module initializations to check that the module is in pending state
* Utilized during module initializations to check that the module is in pending state
* and that the SetToken is valid
* and that the SetToken is valid
*/
*/
modifier onlyValidAndPendingSet(ISetToken _setToken) {
modifier onlyValidAndPendingSet(ISetToken _setToken) {
_validateOnlyValidAndPendingSet(_setToken);
_validateOnlyValidAndPendingSet(_setToken);
_;
_;
}
}


/* ============ Constructor ============ */
/* ============ Constructor ============ */


/**
/**
* Set state variables and map asset pairs to their oracles
* Set state variables and map asset pairs to their oracles
*
*
* @param _controller Address of controller contract
* @param _controller Address of controller contract
*/
*/
constructor(IController _controller) public {
constructor(IController _controller) public {
controller = _controller;
controller = _controller;
}
}


/* ============ Internal Functions ============ */
/* ============ Internal Functions ============ */


/**
/**
* Transfers tokens from an address (that has set allowance on the module).
* Transfers tokens from an address (that has set allowance on the module).
*
*
* @param _token The address of the ERC20 token
* @param _token The address of the ERC20 token
* @param _from The address to transfer from
* @param _from The address to transfer from
* @param _to The address to transfer to
* @param _to The address to transfer to
* @param _quantity The number of tokens to transfer
* @param _quantity The number of tokens to transfer
*/
*/
function transferFrom(IERC20 _token, address _from, address _to, uint256 _quantity) internal {
function transferFrom(IERC20 _token, address _from, address _to, uint256 _quantity) internal {
ExplicitERC20.transferFrom(_token, _from, _to, _quantity);
ExplicitERC20.transferFrom(_token, _from, _to, _quantity);
}
}


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


/**
/**
* Gets the integration for the module with the passed in hash. Validates that the address is not empty
* Gets the integration for the module with the passed in hash. Validates that the address is not empty
*/
*/
function getAndValidateAdapterWithHash(bytes32 _integrationHash) internal view returns(address) {
function getAndValidateAdapterWithHash(bytes32 _integrationHash) internal view returns(address) {
address adapter = controller.getIntegrationRegistry().getIntegrationAdapterWithHash(
address adapter = controller.getIntegrationRegistry().getIntegrationAdapterWithHash(
address(this),
address(this),
_integrationHash
_integrationHash
);
);


require(adapter != address(0), "Must be valid adapter");
require(adapter != address(0), "Must be valid adapter");
return adapter;
return adapter;
}
}


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


/**
/**
* Pays the _feeQuantity from the _setToken denominated in _token to the protocol fee recipient
* Pays the _feeQuantity from the _setToken denominated in _token to the protocol fee recipient
*/
*/
function payProtocolFeeFromSetToken(ISetToken _setToken, address _token, uint256 _feeQuantity) internal {
function payProtocolFeeFromSetToken(ISetToken _setToken, address _token, uint256 _feeQuantity) internal {
if (_feeQuantity > 0) {
if (_feeQuantity > 0) {
_setToken.strictInvokeTransfer(_token, controller.feeRecipient(), _feeQuantity);
_setToken.strictInvokeTransfer(_token, controller.feeRecipient(), _feeQuantity);
}
}
}
}


/**
/**
* Returns true if the module is in process of initialization on the SetToken
* Returns true if the module is in process of initialization on the SetToken
*/
*/
function isSetPendingInitialization(ISetToken _setToken) internal view returns(bool) {
function isSetPendingInitialization(ISetToken _setToken) internal view returns(bool) {
return _setToken.isPendingModule(address(this));
return _setToken.isPendingModule(address(this));
}
}


/**
/**
* Returns true if the address is the SetToken's manager
* Returns true if the address is the SetToken's manager
*/
*/
function isSetManager(ISetToken _setToken, address _toCheck) internal view returns(bool) {
function isSetManager(ISetToken _setToken, address _toCheck) internal view returns(bool) {
return _setToken.manager() == _toCheck;
return _setToken.manager() == _toCheck;
}
}


/**
/**
* Returns true if SetToken must be enabled on the controller
* Returns true if SetToken must be enabled on the controller
* and module is registered on the SetToken
* and module is registered on the SetToken
*/
*/
function isSetValidAndInitialized(ISetToken _setToken) internal view returns(bool) {
function isSetValidAndInitialized(ISetToken _setToken) internal view returns(bool) {
return controller.isSet(address(_setToken)) &&
return controller.isSet(address(_setToken)) &&
_setToken.isInitializedModule(address(this));
_setToken.isInitializedModule(address(this));
}
}


/**
/**
* Hashes the string and returns a bytes32 value
* Hashes the string and returns a bytes32 value
*/
*/
function getNameHash(string memory _name) internal pure returns(bytes32) {
function getNameHash(string memory _name) internal pure returns(bytes32) {
return keccak256(bytes(_name));
return keccak256(bytes(_name));
}
}


/* ============== Modifier Helpers ===============
/* ============== Modifier Helpers ===============
* Internal functions used to reduce bytecode size
* Internal functions used to reduce bytecode size
*/
*/


/**
/**
* Caller must SetToken manager and SetToken must be valid and initialized
* Caller must SetToken manager and SetToken must be valid and initialized
*/
*/
function _validateOnlyManagerAndValidSet(ISetToken _setToken) internal view {
function _validateOnlyManagerAndValidSet(ISetToken _setToken) internal view {
require(isSetManager(_setToken, msg.sender), "Must be the SetToken manager");
require(isSetManager(_setToken, msg.sender), "Must be the SetToken manager");
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
}
}


/**
/**
* Caller must SetToken manager
* Caller must SetToken manager
*/
*/
function _validateOnlySetManager(ISetToken _setToken, address _caller) internal view {
function _validateOnlySetManager(ISetToken _setToken, address _caller) internal view {
require(isSetManager(_setToken, _caller), "Must be the SetToken manager");
require(isSetManager(_setToken, _caller), "Must be the SetToken manager");
}
}


/**
/**
* SetToken must be valid and initialized
* SetToken must be valid and initialized
*/
*/
function _validateOnlyValidAndInitializedSet(ISetToken _setToken) internal view {
function _validateOnlyValidAndInitializedSet(ISetToken _setToken) internal view {
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
require(isSetValidAndInitialized(_setToken), "Must be a valid and initialized SetToken");
}
}


/**
/**
* Caller must be initialized module and module must be enabled on the controller
* Caller must be initialized module and module must be enabled on the controller
*/
*/
function _validateOnlyModule(ISetToken _setToken) internal view {
function _validateOnlyModule(ISetToken _setToken) internal view {
require(
require(
_setToken.moduleStates(msg.sender) == ISetToken.ModuleState.INITIALIZED,
_setToken.moduleStates(msg.sender) == ISetToken.ModuleState.INITIALIZED,
"Only the module can call"
"Only the module can call"
);
);


require(
require(
controller.isModule(msg.sender),
controller.isModule(msg.sender),
"Module must be enabled on controller"
"Module must be enabled on controller"
);
);
}
}


/**
/**
* SetToken must be in a pending state and module must be in pending state
* SetToken must be in a pending state and module must be in pending state
*/
*/
function _validateOnlyValidAndPendingSet(ISetToken _setToken) internal view {
function _validateOnlyValidAndPendingSet(ISetToken _setToken) internal view {
require(controller.isSet(address(_setToken)), "Must be controller-enabled SetToken");
require(controller.isSet(address(_setToken)), "Must be controller-enabled SetToken");
require(isSetPendingInitialization(_setToken), "Must be pending initialization");
require(isSetPendingInitialization(_setToken), "Must be pending initialization");
}
}
}
}